35 #include <sys/ioctl.h>
37 static std::unique_ptr<SestoSenso2> sesto(
new SestoSenso2());
39 static const char *MOTOR_TAB =
"Motor";
51 m_MotionProgressTimer.
callOnTimeout(std::bind(&SestoSenso2::checkMotionProgressCallback,
this));
72 setConnectionParams();
75 FirmwareTP[FIRMWARE_SN].
fill(
"SERIALNUMBER",
"Serial Number",
"");
76 FirmwareTP[FIRMWARE_VERSION].
fill(
"VERSION",
"Version",
"");
80 VoltageInNP[0].
fill(
"VOLTAGEIN",
"Volts",
"%.2f", 0, 100, 0., 0.);
84 TemperatureNP[TEMPERATURE_MOTOR].
fill(
"TEMPERATURE",
"Motor (c)",
"%.2f", -50, 70., 0., 0.);
85 TemperatureNP[TEMPERATURE_EXTERNAL].
fill(
"TEMPERATURE_ETX",
"External (c)",
"%.2f", -50, 70., 0., 0.);
89 CalibrationMessageTP[0].
fill(
"CALIBRATION",
"Calibration stage",
"Press START to begin the Calibration.");
93 CalibrationSP[CALIBRATION_START].
fill(
"CALIBRATION_START",
"Start",
ISS_OFF);
94 CalibrationSP[CALIBRATION_NEXT].
fill(
"CALIBRATION_NEXT",
"Next",
ISS_OFF);
98 FastMoveSP[FASTMOVE_IN].
fill(
"FASTMOVE_IN",
"Move In",
ISS_OFF);
99 FastMoveSP[FASTMOVE_OUT].
fill(
"FASTMOVE_OUT",
"Move out",
ISS_OFF);
100 FastMoveSP[FASTMOVE_STOP].
fill(
"FASTMOVE_STOP",
"Stop",
ISS_OFF);
104 MotorHoldSP[MOTOR_HOLD_ON].
fill(
"HOLD_ON",
"Hold On",
ISS_OFF);
105 MotorHoldSP[MOTOR_HOLD_OFF].
fill(
"HOLD_OFF",
"Hold Off",
ISS_OFF);
114 MotorRateNP[MOTOR_RATE_ACC].
fill(
"ACC",
"Acceleration",
"%.f", 1, 10, 1, 1);
115 MotorRateNP[MOTOR_RATE_RUN].
fill(
"RUN",
"Run Speed",
"%.f", 1, 10, 1, 2);
116 MotorRateNP[MOTOR_RATE_DEC].
fill(
"DEC",
"Deceleration",
"%.f", 1, 10, 1, 1);
120 MotorCurrentNP[MOTOR_CURR_ACC].
fill(
"CURR_ACC",
"Acceleration",
"%.f", 1, 10, 1, 7);
121 MotorCurrentNP[MOTOR_CURR_RUN].
fill(
"CURR_RUN",
"Run",
"%.f", 1, 10, 1, 7);
122 MotorCurrentNP[MOTOR_CURR_DEC].
fill(
"CURR_DEC",
"Deceleration",
"%.f", 1, 10, 1, 7);
123 MotorCurrentNP[MOTOR_CURR_HOLD].
fill(
"CURR_HOLD",
"Hold",
"%.f", 0, 5, 1, 3);
127 MotorApplyPresetSP[MOTOR_APPLY_LIGHT].
fill(
"MOTOR_APPLY_LIGHT",
"Light",
ISS_OFF);
128 MotorApplyPresetSP[MOTOR_APPLY_MEDIUM].
fill(
"MOTOR_APPLY_MEDIUM",
"Medium",
ISS_OFF);
129 MotorApplyPresetSP[MOTOR_APPLY_HEAVY].
fill(
"MOTOR_APPLY_HEAVY",
"Heavy",
ISS_OFF);
133 MotorApplyUserPresetSP[MOTOR_APPLY_USER1].
fill(
"MOTOR_APPLY_USER1",
"User 1",
ISS_OFF);
134 MotorApplyUserPresetSP[MOTOR_APPLY_USER2].
fill(
"MOTOR_APPLY_USER2",
"User 2",
ISS_OFF);
135 MotorApplyUserPresetSP[MOTOR_APPLY_USER3].
fill(
"MOTOR_APPLY_USER3",
"User 3",
ISS_OFF);
140 MotorSaveUserPresetSP[MOTOR_SAVE_USER1].
fill(
"MOTOR_SAVE_USER1",
"User 1",
ISS_OFF);
141 MotorSaveUserPresetSP[MOTOR_SAVE_USER2].
fill(
"MOTOR_SAVE_USER2",
"User 2",
ISS_OFF);
142 MotorSaveUserPresetSP[MOTOR_SAVE_USER3].
fill(
"MOTOR_SAVE_USER3",
"User 3",
ISS_OFF);
192 if (updateTemperature())
195 if (updateVoltageIn())
198 if (getStartupValues())
199 LOG_INFO(
"Parameters updated, focuser ready for use.");
201 LOG_WARN(
"Failed to inquire parameters. Check logs.");
233 LOG_INFO(
"Error retrieving data from device, please ensure focuser is powered and the port is correct.");
242 return m_SestoSenso2->setBacklash(steps);
250 return "Sesto Senso 2";
256 bool SestoSenso2::updateTemperature()
258 double temperature = 0;
262 else if ( m_SestoSenso2->getMotorTemp(temperature) ==
false)
265 if (temperature > 90)
268 TemperatureNP[TEMPERATURE_MOTOR].setValue(temperature);
272 if (m_SestoSenso2->getExternalTemp(temperature))
274 if (temperature < 90)
275 TemperatureNP[TEMPERATURE_EXTERNAL].setValue(temperature);
277 TemperatureNP[TEMPERATURE_EXTERNAL].setValue(-273.15);
286 bool SestoSenso2::updateMaxLimit()
288 uint32_t maxLimit = 0;
293 if (m_SestoSenso2->getMaxPosition(maxLimit) ==
false)
325 bool SestoSenso2::updatePosition()
330 else if (m_SestoSenso2->getAbsolutePosition(steps) ==
false)
341 bool SestoSenso2::updateVoltageIn()
343 double voltageIn = 0;
347 else if (m_SestoSenso2->getVoltage12v(voltageIn) ==
false)
353 VoltageInNP[0].setValue(voltageIn);
362 bool SestoSenso2::fetchMotorSettings()
367 bool motorHoldActive =
false;
381 if (!m_SestoSenso2->getMotorSettings(ms, mc, motorHoldActive))
390 MotorRateNP[MOTOR_RATE_ACC].setValue(ms.
accRate);
391 MotorRateNP[MOTOR_RATE_RUN].setValue(ms.
runSpeed);
392 MotorRateNP[MOTOR_RATE_DEC].setValue(ms.
decRate);
396 MotorCurrentNP[MOTOR_CURR_ACC].setValue(mc.
accCurrent);
397 MotorCurrentNP[MOTOR_CURR_RUN].setValue(mc.
runCurrent);
398 MotorCurrentNP[MOTOR_CURR_DEC].setValue(mc.
decCurrent);
399 MotorCurrentNP[MOTOR_CURR_HOLD].setValue(mc.
holdCurrent);
401 MotorCurrentNP.
apply();
404 auto activeSwitchID = motorHoldActive ?
"HOLD_ON" :
"HOLD_OFF";
406 assert(sp !=
nullptr &&
"Motor hold switch not found");
417 LOG_WARN(
"Motor hold current set to 0, motor hold setting will have no effect");
426 bool SestoSenso2::applyMotorRates()
433 mr.
accRate =
static_cast<uint32_t
>(MotorRateNP[MOTOR_RATE_ACC].getValue());
434 mr.
runSpeed =
static_cast<uint32_t
>(MotorRateNP[MOTOR_RATE_RUN].getValue());
435 mr.
decRate =
static_cast<uint32_t
>(MotorRateNP[MOTOR_RATE_DEC].getValue());
437 if (!m_SestoSenso2->setMotorRates(mr))
439 LOG_ERROR(
"Failed to apply motor rates");
451 bool SestoSenso2::applyMotorCurrents()
458 mc.
accCurrent =
static_cast<uint32_t
>(MotorCurrentNP[MOTOR_CURR_ACC].getValue());
459 mc.
runCurrent =
static_cast<uint32_t
>(MotorCurrentNP[MOTOR_CURR_RUN].getValue());
460 mc.
decCurrent =
static_cast<uint32_t
>(MotorCurrentNP[MOTOR_CURR_DEC].getValue());
461 mc.
holdCurrent =
static_cast<uint32_t
>(MotorCurrentNP[MOTOR_CURR_HOLD].getValue());
463 if (!m_SestoSenso2->setMotorCurrents(mc))
465 LOG_ERROR(
"Failed to apply motor currents");
477 bool SestoSenso2::isMotionComplete()
482 int32_t targPos =
static_cast<int32_t
>(targetPos);
484 if (targPos > nextPos)
486 else if (targPos < nextPos)
489 if (abs(nextPos - targPos) < 250)
491 else if (nextPos < 0)
497 return (std::abs(nextPos -
static_cast<int32_t
>(targetPos)) == 0);
500 return !m_SestoSenso2->isBusy();
513 CalibrationSP.
update(states, names, n);
516 CalibrationSP.
apply();
518 if (current_switch == CALIBRATION_START)
520 if (cStage == Idle || cStage == Complete )
525 CalibrationSP.
apply();
530 if (m_IsSestoSenso2 && m_SestoSenso2->initCalibration() ==
false)
533 CalibrationMessageTP[0].setText(
"Set focus in MIN position and then press NEXT.");
534 CalibrationMessageTP.
apply();
537 fetchMotorSettings();
544 LOG_INFO(
"Already started calibration. Proceed to next step.");
545 CalibrationMessageTP[0].setText(
"Already started. Proceed to NEXT.");
546 CalibrationMessageTP.
apply();
549 else if (current_switch == CALIBRATION_NEXT)
551 if (cStage == GoToMiddle)
556 if (m_SestoSenso2->storeAsMinPosition() ==
false)
559 CalibrationMessageTP[0].setText(
"Press MOVE OUT to move focuser out (CAUTION!)");
560 CalibrationMessageTP.
apply();
569 const char *fn[1] = { FastMoveSP[FASTMOVE_OUT].
getName() };
573 else if (cStage == GoMinimum)
575 if (m_SestoSenso2->storeAsMaxPosition() ==
false)
578 CalibrationMessageTP[0].setText(
"Press NEXT to finish.");
579 CalibrationMessageTP.
apply();
582 else if (cStage == GoMaximum)
584 uint32_t maxLimit = 0;
586 if (m_SestoSenso2->getMaxPosition(maxLimit) ==
false)
589 LOGF_INFO(
"MAX setting is %d", maxLimit);
617 CalibrationMessageTP[0].setText(
"Calibration Completed.");
618 CalibrationMessageTP.
apply();
625 CalibrationSP.
apply();
627 CalibrationSP.
apply();
630 fetchMotorSettings();
634 CalibrationMessageTP[0].setText(
"Calibration not in progress.");
635 CalibrationMessageTP.
apply();
644 FastMoveSP.
update(states, names, n);
647 switch (current_switch)
650 if (m_SestoSenso2->fastMoveIn() ==
false)
658 if (m_SestoSenso2->goOutToFindMaxPos() ==
false)
662 CalibrationMessageTP[0].setText(
"Press STOP focuser almost at MAX position.");
663 fetchMotorSettings();
667 if (m_SestoSenso2->fastMoveOut())
669 CalibrationMessageTP[0].setText(
"Focusing out to detect hall sensor.");
670 m_MotionProgressTimer.
start(500);
673 CalibrationMessageTP.
apply();
676 if (m_SestoSenso2->stop() ==
false)
680 CalibrationMessageTP[0].setText(
"Press NEXT to store max limit.");
681 CalibrationMessageTP.
apply();
694 MotorHoldSP.
update(states, names, n);
696 assert(sp !=
nullptr);
699 if (!strcmp(sp->name,
"HOLD_OFF"))
701 m_SestoSenso2->setMotorHold(
false);
703 LOG_INFO(
"Motor hold OFF. You may now manually adjust the focuser. Remember to enable motor hold once done.");
707 m_SestoSenso2->setMotorHold(
true);
709 LOG_INFO(
"Motor hold ON. Do NOT attempt to manually adjust the focuser!");
710 if (MotorCurrentNP[MOTOR_CURR_HOLD].getValue() < 2.0)
712 LOGF_WARN(
"Motor hold current set to %.1f: This may be insufficent to hold focus",
713 MotorCurrentNP[MOTOR_CURR_HOLD].getValue());
722 MotorApplyPresetSP.
update(states, names, n);
724 assert(index >= 0 && index < 3);
728 if (m_SestoSenso2->applyMotorPreset(presetName))
730 LOGF_INFO(
"Loaded motor preset: %s", presetName);
735 LOGF_ERROR(
"Failed to load motor preset: %s", presetName);
740 MotorApplyPresetSP.
apply();
742 fetchMotorSettings();
816 MotorRateNP.
update(values, names, n);
824 MotorCurrentNP.
update(values, names, n);
826 applyMotorCurrents();
827 MotorCurrentNP.
apply();
839 targetPos = targetTicks;
846 targetPos -= backlashTicks;
850 targetPos += backlashTicks;
852 if (m_SestoSenso2->goAbsolutePosition(targetPos) ==
false)
856 m_MotionProgressTimer.
start(10);
866 int relativeTicks = ((dir ==
FOCUS_INWARD) ? -ticks : ticks) * reversed;
867 double newPosition =
FocusAbsPosN[0].value + relativeTicks;
885 m_MotionProgressTimer.
stop();
890 return m_SestoSenso2->stop();
896 void SestoSenso2::checkMotionProgressCallback()
898 if (isMotionComplete())
909 const char * names[2] = { CalibrationSP[CALIBRATION_START].
getName(), CalibrationSP[CALIBRATION_NEXT].
getName() };
913 LOG_INFO(
"Focuser reached requested position.");
922 m_MotionProgressTimer.
start(500);
966 bool rc = updatePosition();
976 if (m_TemperatureCounter++ == SESTO_TEMPERATURE_FREQ)
978 rc = updateTemperature();
981 if (fabs(lastTemperature - TemperatureNP[0].getValue()) >= 0.1)
983 TemperatureNP.
apply();
984 lastTemperature = TemperatureNP[0].getValue();
989 rc = updateVoltageIn();
992 if (fabs(lastVoltageIn - VoltageInNP[0].getValue()) >= 0.1)
995 lastVoltageIn = VoltageInNP[0].getValue();
997 if (VoltageInNP[0].getValue() < 11.0)
999 LOG_WARN(
"Please check 12v DC power supply is connected.");
1004 m_TemperatureCounter = 0;
1013 bool SestoSenso2::getStartupValues()
1015 bool rc = updatePosition();
1021 rc &= fetchMotorSettings();
1038 bool SestoSenso2::Ack()
1040 std::string response;
1043 response =
"1.0 Simulation";
1046 if(initCommandSet() ==
false)
1048 LOG_ERROR(
"Failed setting attributes on serial port and init command sets");
1051 if(m_SestoSenso2->getSerialNumber(response))
1053 LOGF_INFO(
"Serial number: %s", response.c_str());
1061 m_IsSestoSenso2 = !strstr(response.c_str(),
"ESATTO");
1062 FirmwareTP[FIRMWARE_SN].setText(response.c_str());
1064 if (m_SestoSenso2->getFirmwareVersion(response))
1066 LOGF_INFO(
"Firmware version: %s", response.c_str());
1067 IUSaveText(&FirmwareTP[FIRMWARE_VERSION], response.c_str());
1080 void SestoSenso2::setConnectionParams()
1089 bool SestoSenso2::initCommandSet()
1096 LOG_ERROR(
"setTTYFlags: failed getting tty attributes.");
1102 LOG_ERROR(
"setTTYFlags: failed setting attributes on serial port.");
1113 Focuser::saveConfigItems(fp);
1114 MotorRateNP.
save(fp);
1115 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...
const char * getDeviceName() const
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.
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
ISwitchVectorProperty FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INumber FocusBacklashN[1]
INumberVectorProperty FocusMaxPosNP
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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.
INumberVectorProperty PresetNP
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Connection::Serial * serialConnection
void setState(IPState state)
WidgetView< T > * findWidgetByName(const char *name) const
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
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 updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
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 initProperties() override
Initilize properties initial state and value. The child class must implement this function.
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
const char * getDefaultName() override
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool Handshake() override
perform handshake with device to check communication
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
Implementations for common driver routines.
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 IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
#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 * CONNECTION_TAB
const char * MOTOR_PRESET_NAMES[]
struct termios tty_setting