36static std::unique_ptr<SestoSenso3> sesto3(
new SestoSenso3());
38static const char *MOTOR_TAB =
"Motor";
48 m_MotionProgressTimer.
callOnTimeout(std::bind(&SestoSenso3::checkMotionProgressCallback,
this));
64 setConnectionParams();
67 FirmwareTP[FIRMWARE_SN].
fill(
"SERIALNUMBER",
"Serial Number",
"");
68 FirmwareTP[FIRMWARE_VERSION].
fill(
"VERSION",
"Version",
"");
72 VoltageInNP[0].
fill(
"VOLTAGEIN",
"Volts",
"%.2f", 0, 100, 0., 0.);
76 TemperatureNP[TEMPERATURE_MOTOR].
fill(
"TEMPERATURE",
"Motor (c)",
"%.2f", -50, 70., 0., 0.);
77 TemperatureNP[TEMPERATURE_EXTERNAL].
fill(
"TEMPERATURE_ETX",
"External (c)",
"%.2f", -50, 70., 0., 0.);
81 CalibrationMessageTP[0].
fill(
"CALIBRATION",
"Calibration stage",
"Press START to begin the Calibration.");
85 CalibrationSP[CALIBRATION_START].
fill(
"CALIBRATION_START",
"Start",
ISS_OFF);
86 CalibrationSP[CALIBRATION_NEXT].
fill(
"CALIBRATION_NEXT",
"Next",
ISS_OFF);
90 RecoveryDelayNP[RECOVERY_DELAY_VALUE].
fill(
"RECOVERY_DELAY",
"Recovery Delay (s)",
"%.0f", -1, 120, 1, 0);
94 FastMoveSP[FASTMOVE_IN].
fill(
"FASTMOVE_IN",
"Move In",
ISS_OFF);
95 FastMoveSP[FASTMOVE_OUT].
fill(
"FASTMOVE_OUT",
"Move out",
ISS_OFF);
96 FastMoveSP[FASTMOVE_STOP].
fill(
"FASTMOVE_STOP",
"Stop",
ISS_OFF);
100 MoveInOut100SP[MOVE_IN_100].
fill(
"MOVE_IN_100",
"Move In 100",
ISS_OFF);
101 MoveInOut100SP[MOVE_OUT_100].
fill(
"MOVE_OUT_100",
"Move Out 100",
ISS_OFF);
105 MoveInOut500SP[MOVE_IN_500].
fill(
"MOVE_IN_500",
"Move In 500",
ISS_OFF);
106 MoveInOut500SP[MOVE_OUT_500].
fill(
"MOVE_OUT_500",
"Move Out 500",
ISS_OFF);
110 MoveInOut1000SP[MOVE_IN_1000].
fill(
"MOVE_IN_1000",
"Move In 1000",
ISS_OFF);
111 MoveInOut1000SP[MOVE_OUT_1000].
fill(
"MOVE_OUT_1000",
"Move Out 1000",
ISS_OFF);
116 MotorHoldSP[MOTOR_HOLD_ON].
fill(
"HOLD_ON",
"Hold On",
ISS_OFF);
117 MotorHoldSP[MOTOR_HOLD_OFF].
fill(
"HOLD_OFF",
"Hold Off",
ISS_OFF);
124 MotorRateNP[MOTOR_RATE_ACC].
fill(
"ACC",
"Acceleration",
"%.f", 1, 10, 1, 1);
125 MotorRateNP[MOTOR_RATE_RUN].
fill(
"RUN",
"Run Speed",
"%.f", 1, 10, 1, 2);
126 MotorRateNP[MOTOR_RATE_DEC].
fill(
"DEC",
"Deceleration",
"%.f", 1, 10, 1, 1);
130 MotorCurrentNP[MOTOR_CURR_ACC].
fill(
"CURR_ACC",
"Acceleration",
"%.f", 1, 10, 1, 7);
131 MotorCurrentNP[MOTOR_CURR_RUN].
fill(
"CURR_RUN",
"Run",
"%.f", 1, 10, 1, 7);
132 MotorCurrentNP[MOTOR_CURR_DEC].
fill(
"CURR_DEC",
"Deceleration",
"%.f", 1, 10, 1, 7);
133 MotorCurrentNP[MOTOR_CURR_HOLD].
fill(
"CURR_HOLD",
"Hold",
"%.f", 0, 5, 1, 3);
137 MotorApplyPresetSP[MOTOR_APPLY_LIGHT].
fill(
"MOTOR_APPLY_LIGHT",
"Light",
ISS_OFF);
138 MotorApplyPresetSP[MOTOR_APPLY_MEDIUM].
fill(
"MOTOR_APPLY_MEDIUM",
"Medium",
ISS_OFF);
139 MotorApplyPresetSP[MOTOR_APPLY_HEAVY].
fill(
"MOTOR_APPLY_HEAVY",
"Heavy",
ISS_OFF);
179 if (m_SubModel == SESTOSENSO3_SC)
187 if (m_SestoSenso3->getRecoveryDelay(delay))
189 RecoveryDelayNP[RECOVERY_DELAY_VALUE].setValue(delay);
196 RecoveryDelayNP.
apply();
204 if (updateTemperature())
207 if (updateVoltageIn())
210 if (getStartupValues())
211 LOG_INFO(
"Parameters updated, focuser ready for use.");
213 LOG_WARN(
"Failed to inquire parameters. Check logs.");
244 LOG_INFO(
"Error retrieving data from device, please ensure focuser is powered and the port is correct.");
253 return m_SestoSenso3->setBacklash(steps);
261 return "Sesto Senso 3";
267bool SestoSenso3::updateTemperature()
273 else if (m_SestoSenso3->getMotorTemp(
temperature) ==
false)
279 TemperatureNP[TEMPERATURE_MOTOR].setValue(
temperature);
285 TemperatureNP[TEMPERATURE_EXTERNAL].setValue(
temperature);
287 TemperatureNP[TEMPERATURE_EXTERNAL].setValue(-273.15);
296bool SestoSenso3::updateMaxLimit()
298 uint32_t maxLimit = 0;
303 if (m_SestoSenso3->getMaxPosition(maxLimit) ==
false)
334bool SestoSenso3::updatePosition()
339 else if (m_SestoSenso3->getAbsolutePosition(steps) ==
false)
349bool SestoSenso3::updateVoltageIn()
351 double voltageIn = 0;
355 else if (m_SestoSenso3->getVoltage12v(voltageIn) ==
false)
361 VoltageInNP[0].setValue(voltageIn);
370bool SestoSenso3::fetchMotorSettings()
374 bool motorHoldActive =
false;
388 if (!m_SestoSenso3->getMotorSettings(ms, mc, motorHoldActive))
397 MotorRateNP[MOTOR_RATE_ACC].setValue(ms.
accRate);
398 MotorRateNP[MOTOR_RATE_RUN].setValue(ms.
runSpeed);
399 MotorRateNP[MOTOR_RATE_DEC].setValue(ms.
decRate);
403 MotorCurrentNP[MOTOR_CURR_ACC].setValue(mc.
accCurrent);
404 MotorCurrentNP[MOTOR_CURR_RUN].setValue(mc.
runCurrent);
405 MotorCurrentNP[MOTOR_CURR_DEC].setValue(mc.
decCurrent);
406 MotorCurrentNP[MOTOR_CURR_HOLD].setValue(mc.
holdCurrent);
408 MotorCurrentNP.
apply();
410 auto activeSwitchID = motorHoldActive ?
"HOLD_ON" :
"HOLD_OFF";
412 assert(sp !=
nullptr &&
"Motor hold switch not found");
422 LOG_WARN(
"Motor hold current set to 0, motor hold setting will have no effect");
430bool SestoSenso3::applyMotorRates()
436 mr.
accRate =
static_cast<uint32_t
>(MotorRateNP[MOTOR_RATE_ACC].getValue());
437 mr.
runSpeed =
static_cast<uint32_t
>(MotorRateNP[MOTOR_RATE_RUN].getValue());
438 mr.
decRate =
static_cast<uint32_t
>(MotorRateNP[MOTOR_RATE_DEC].getValue());
440 if (!m_SestoSenso3->setMotorRates(mr))
442 LOG_ERROR(
"Failed to apply motor rates");
453bool SestoSenso3::applyMotorCurrents()
459 mc.
accCurrent =
static_cast<uint32_t
>(MotorCurrentNP[MOTOR_CURR_ACC].getValue());
460 mc.
runCurrent =
static_cast<uint32_t
>(MotorCurrentNP[MOTOR_CURR_RUN].getValue());
461 mc.
decCurrent =
static_cast<uint32_t
>(MotorCurrentNP[MOTOR_CURR_DEC].getValue());
462 mc.
holdCurrent =
static_cast<uint32_t
>(MotorCurrentNP[MOTOR_CURR_HOLD].getValue());
464 if (!m_SestoSenso3->setMotorCurrents(mc))
466 LOG_ERROR(
"Failed to apply motor currents");
478bool SestoSenso3::isMotionComplete()
483 int32_t targPos =
static_cast<int32_t
>(targetPos);
485 if (targPos > nextPos)
487 else if (targPos < nextPos)
490 if (abs(nextPos - targPos) < 250)
492 else if (nextPos < 0)
498 return (std::abs(nextPos -
static_cast<int32_t
>(targetPos)) == 0);
501 return !m_SestoSenso3->isBusy();
514 CalibrationSP.
update(states, names, n);
517 CalibrationSP.
apply();
519 if (current_switch == CALIBRATION_START)
521 if (cStage == Idle || cStage == Complete)
525 CalibrationSP.
apply();
527 if (m_SubModel == SESTOSENSO3_SC)
529 if (m_SestoSenso3->startAutoCalibration() ==
false)
531 CalibrationMessageTP[0].setText(
"Automatic Calibration Started. Please wait...");
532 CalibrationMessageTP.
apply();
538 if (m_SestoSenso3->initCalibrationSemiAuto() ==
false)
540 CalibrationMessageTP[0].setText(
"Semi-Automatic Calibration: Move focuser to MIN position and then press NEXT.");
541 CalibrationMessageTP.
apply();
542 fetchMotorSettings();
552 LOG_INFO(
"Already started calibration. Proceed to next step.");
553 CalibrationMessageTP[0].setText(
"Already started. Proceed to NEXT.");
554 CalibrationMessageTP.
apply();
557 else if (current_switch == CALIBRATION_NEXT)
559 if (m_SubModel == SESTOSENSO3_SC)
561 LOG_ERROR(
"CALIBRATION_NEXT not applicable for SestoSenso3 SC Automatic Calibration.");
562 CalibrationMessageTP[0].setText(
"Error: NEXT not applicable for Automatic Calibration.");
563 CalibrationMessageTP.
apply();
565 CalibrationSP.
apply();
569 if (cStage == GoToMiddle)
572 if (m_SestoSenso3->storeAsMinPosition() ==
false)
574 CalibrationMessageTP[0].setText(
"Semi-Automatic Calibration: Use Fast Move OUT to find MAX position, then press STOP, then NEXT.");
575 CalibrationMessageTP.
apply();
578 else if (cStage == GoMinimum)
580 if (m_SestoSenso3->storeAsMaxPosition() ==
false)
582 CalibrationMessageTP[0].setText(
"Calibration: Press NEXT to finish.");
583 CalibrationMessageTP.
apply();
586 else if (cStage == GoMaximum)
588 uint32_t maxLimit = 0;
589 if (m_SestoSenso3->getMaxPosition(maxLimit) ==
false)
592 LOGF_INFO(
"MAX setting is %d", maxLimit);
620 CalibrationMessageTP[0].setText(
"Calibration Completed.");
621 CalibrationMessageTP.
apply();
632 CalibrationSP.
apply();
634 CalibrationSP.
apply();
636 fetchMotorSettings();
640 CalibrationMessageTP[0].setText(
"Calibration not in progress.");
641 CalibrationMessageTP.
apply();
649 FastMoveSP.
update(states, names, n);
652 switch (current_switch)
655 if (m_SestoSenso3->fastMoveIn() ==
false)
659 if (m_SestoSenso3->goOutToFindMaxPos() ==
false)
661 CalibrationMessageTP[0].setText(
"Semi-Automatic Calibration: Press STOP when focuser is almost at MAX position.");
662 CalibrationMessageTP.
apply();
663 fetchMotorSettings();
666 if (m_SestoSenso3->stopMotor() ==
false)
668 CalibrationMessageTP[0].setText(
"Press NEXT to store max limit.");
669 CalibrationMessageTP.
apply();
682 MoveInOut100SP.
update(states, names, n);
684 if (current_move_switch == MOVE_IN_100)
686 if (m_SestoSenso3->moveIn(100) ==
false)
return false;
688 else if (current_move_switch == MOVE_OUT_100)
690 if (m_SestoSenso3->moveOut(100) ==
false)
return false;
693 MoveInOut100SP.
apply();
698 MoveInOut500SP.
update(states, names, n);
700 if (current_move_switch == MOVE_IN_500)
702 if (m_SestoSenso3->moveIn(500) ==
false)
return false;
704 else if (current_move_switch == MOVE_OUT_500)
706 if (m_SestoSenso3->moveOut(500) ==
false)
return false;
709 MoveInOut500SP.
apply();
714 MoveInOut1000SP.
update(states, names, n);
716 if (current_move_switch == MOVE_IN_1000)
718 if (m_SestoSenso3->moveIn(1000) ==
false)
return false;
720 else if (current_move_switch == MOVE_OUT_1000)
722 if (m_SestoSenso3->moveOut(1000) ==
false)
return false;
725 MoveInOut1000SP.
apply();
731 MotorHoldSP.
update(states, names, n);
733 assert(sp !=
nullptr);
735 if (!strcmp(sp->name,
"HOLD_OFF"))
737 m_SestoSenso3->setMotorHold(
false);
739 LOG_INFO(
"Motor hold OFF. You may now manually adjust the focuser. Remember to enable motor hold once done.");
743 m_SestoSenso3->setMotorHold(
true);
745 LOG_INFO(
"Motor hold ON. Do NOT attempt to manually adjust the focuser!");
746 if (MotorCurrentNP[MOTOR_CURR_HOLD].getValue() < 2.0)
748 LOGF_WARN(
"Motor hold current set to %.1f: This may be insufficient to hold focus",
749 MotorCurrentNP[MOTOR_CURR_HOLD].getValue());
758 MotorApplyPresetSP.
update(states, names, n);
760 assert(index >= 0 && index < 3);
764 if (m_SestoSenso3->applyMotorPreset(presetName))
766 LOGF_INFO(
"Loaded motor preset: %s", presetName);
771 LOGF_ERROR(
"Failed to load motor preset: %s", presetName);
776 MotorApplyPresetSP.
apply();
778 fetchMotorSettings();
795 MotorRateNP.
update(values, names, n);
803 MotorCurrentNP.
update(values, names, n);
805 applyMotorCurrents();
806 MotorCurrentNP.
apply();
811 RecoveryDelayNP.
update(values, names, n);
812 int32_t delay =
static_cast<int32_t
>(RecoveryDelayNP[RECOVERY_DELAY_VALUE].getValue());
813 if (m_SestoSenso3->setRecoveryDelay(delay))
816 LOGF_INFO(
"Recovery Delay set to %d seconds.", delay);
821 LOG_ERROR(
"Failed to set Recovery Delay.");
824 RecoveryDelayNP.
apply();
836 targetPos = targetTicks;
842 targetPos -= backlashTicks;
844 targetPos += backlashTicks;
846 if (m_SestoSenso3->goAbsolutePosition(targetPos) ==
false)
850 m_MotionProgressTimer.
start(10);
860 int relativeTicks = ((dir ==
FOCUS_INWARD) ? -ticks : ticks) * reversed;
861 double newPosition =
FocusAbsPosNP[0].getValue() + relativeTicks;
873 m_MotionProgressTimer.
stop();
878 return m_SestoSenso3->stop();
884void SestoSenso3::checkMotionProgressCallback()
888 if (isMotionComplete())
895 const char *names[2] = { CalibrationSP[CALIBRATION_START].
getName(), CalibrationSP[CALIBRATION_NEXT].
getName() };
899 LOG_INFO(
"Focuser reached requested position.");
905 m_MotionProgressTimer.
start(500);
922 bool rc = updatePosition();
932 if (m_TemperatureCounter++ == SESTO_TEMPERATURE_FREQ)
934 rc = updateTemperature();
937 if (fabs(lastTemperature - TemperatureNP[0].getValue()) >= 0.1)
939 TemperatureNP.
apply();
940 lastTemperature = TemperatureNP[0].getValue();
944 rc = updateVoltageIn();
947 if (fabs(lastVoltageIn - VoltageInNP[0].getValue()) >= 0.1)
950 lastVoltageIn = VoltageInNP[0].getValue();
952 if (VoltageInNP[0].getValue() < 11.0)
953 LOG_WARN(
"Please check 12v DC power supply is connected.");
957 m_TemperatureCounter = 0;
966bool SestoSenso3::getStartupValues()
968 bool rc = updatePosition();
972 rc &= fetchMotorSettings();
989bool SestoSenso3::Ack()
991 std::string response;
994 response =
"1.0 Simulation";
997 if (initCommandSet() ==
false)
999 LOG_ERROR(
"Failed setting attributes on serial port and init command sets");
1002 if (m_SestoSenso3->getSerialNumber(response))
1004 LOGF_INFO(
"Serial number: %s", response.c_str());
1011 std::string modelName;
1012 if (m_SestoSenso3->getModel(modelName))
1014 LOGF_INFO(
"Model name: %s", modelName.c_str());
1016 std::string subModel;
1017 if (m_SestoSenso3->getSubModel(subModel))
1019 LOGF_INFO(
"SubModel: %s", subModel.c_str());
1021 if (subModel.find(
"SESTOSENSO3SC") != std::string::npos)
1023 m_SubModel = SESTOSENSO3_SC;
1024 LOG_INFO(
"Detected: SestoSenso3 SC (Automatic Calibration)");
1026 else if (subModel.find(
"SESTOSENSO3LS") != std::string::npos)
1028 m_SubModel = SESTOSENSO3_LS;
1029 LOG_INFO(
"Detected: SestoSenso3 LS (Semi-Automatic Calibration)");
1033 m_SubModel = SESTOSENSO3_STANDARD;
1034 LOG_INFO(
"Detected: SestoSenso3 Standard (Semi-Automatic Calibration)");
1039 m_SubModel = SESTOSENSO3_STANDARD;
1040 LOG_WARN(
"Failed to query submodel, defaulting to SestoSenso3 Standard");
1045 FirmwareTP[FIRMWARE_SN].setText(response.c_str());
1047 if (m_SestoSenso3->getFirmwareVersion(response))
1049 LOGF_INFO(
"Firmware version: %s", response.c_str());
1050 IUSaveText(&FirmwareTP[FIRMWARE_VERSION], response.c_str());
1063void SestoSenso3::setConnectionParams()
1072bool SestoSenso3::initCommandSet()
1079 LOG_ERROR(
"setTTYFlags: failed getting tty attributes.");
1085 LOG_ERROR(
"setTTYFlags: failed setting attributes on serial port.");
1096 Focuser::saveConfigItems(fp);
1097 MotorRateNP.
save(fp);
1098 MotorCurrentNP.
save(fp);
void setWordSize(const uint8_t &value)
setWordSize Set word size to be used in the serial connection. Default 8
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
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
INDI::PropertySwitch FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusMaxPosNP
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...
Connection::Serial * serialConnection
INDI::PropertyNumber PresetNP
void setState(IPState state)
WidgetView< T > * findWidgetByName(const char *name) const
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
const char * getName() const
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)
INDI::WidgetViewSwitch * findOnSwitch() const
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)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
void setSingleShot(bool singleShot)
Set whether the timer is a single-shot timer.
void callOnTimeout(const std::function< void()> &callback)
void start()
Starts or restarts the timer with the timeout specified in interval.
void stop()
Stops the timer.
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
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 IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
const char * getDefaultName() override
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative 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 void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual bool saveConfigItems(FILE *fp) override
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
const char * CONNECTION_TAB
CONNECTION_TAB Where all device connection settings (serial, usb, ethernet) are defined and controlle...
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
Implementations for common driver routines.
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
#define LOGF_INFO(fmt,...)
#define LOGF_WARN(fmt,...)
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
#define LOGF_ERROR(fmt,...)
const char * MOTOR_PRESET_NAMES[]
const char * MOTOR_PRESET_NAMES[]
struct termios tty_setting