35static std::unique_ptr<MyFocuserPro2> myFocuserPro2(
new MyFocuserPro2());
74 BacklashInStepsN[0].min = 0;
75 BacklashInStepsN[0].max = 512;
76 BacklashInStepsN[0].value = 0;
77 BacklashInStepsN[0].step = 2;
79 BacklashOutStepsN[0].min = 0;
80 BacklashOutStepsN[0].max = 512;
81 BacklashOutStepsN[0].value = 0;
82 BacklashOutStepsN[0].step = 2;
91 IUFillNumber(&BacklashInStepsN[0],
"Steps",
"",
"%3.0f", 0, 512, 2, 0);
101 IUFillNumber(&BacklashOutStepsN[0],
"Steps",
"",
"%3.0f", 0, 512, 2, 0);
106 IUFillNumber(&TemperatureN[0],
"TEMPERATURE",
"Celsius",
"%6.2f", -40, 80., 0., 0.);
111 IUFillNumber(&TemperatureSettingN[0],
"Coefficient",
"",
"%6.2f", 0, 50, 1, 0);
177 setTemperatureCelsius();
179 LOG_INFO(
"MyFocuserPro2 parameters updated, focuser ready for use.");
203 LOG_INFO(
"MyFocuserPro2 is online. Getting focus parameters...");
211 "Error retrieving data from MyFocuserPro2, please ensure MyFocuserPro2 controller is powered and the port is correct.");
217 return "MyFocuserPro2";
220bool MyFocuserPro2::Ack()
222 int nbytes_written = 0, nbytes_read = 0, rc = -1;
225 int firmWareVersion = 0;
227 tcflush(
PortFD, TCIOFLUSH);
236 bool success =
false;
237 while(numChecks < 3 && !success)
243 if(!transmissionSuccess)
246 LOGF_ERROR(
"Handshake Attempt %i, Connection transmission error: %s.", numChecks, errstr);
249 bool responseSuccess;
252 responseSuccess = (rc =
tty_read(
PortFD, resp, 5, MYFOCUSERPRO2_SERIAL_TIMEOUT, &nbytes_read)) ==
TTY_OK;
257 responseSuccess = (rc =
tty_read(
PortFD, resp, 5, MYFOCUSERPRO2_TCPIP_TIMEOUT, &nbytes_read)) ==
TTY_OK;
263 LOGF_ERROR(
"Handshake Attempt %i, updatePosition response error: %s.", numChecks, errstr);
265 success = transmissionSuccess && responseSuccess;
270 LOG_INFO(
"Handshake failed after 3 attempts");
274 tcflush(
PortFD, TCIOFLUSH);
276 rc = sscanf(resp,
"F%d#", &firmWareVersion);
281 LOGF_INFO(
"MyFP2 reported firmware %d", firmWareVersion);
282 LOG_INFO(
"Connection to focuser is successful.");
287 LOGF_ERROR(
"Invalid Response: focuser firmware version value (%s)", resp);
292bool MyFocuserPro2::readCoilPowerState()
294 char res[ML_RES] = {0};
296 if (sendCommand(
":11#", res) ==
false)
303 int rc = sscanf(res,
"O%u#", &temp);
317 LOGF_ERROR(
"Invalid Response: focuser Coil Power value (%s)", res);
323 LOGF_ERROR(
"Unknown error: focuser Coil Power value (%s)", res);
329bool MyFocuserPro2::readReverseDirection()
331 char res[ML_RES] = {0};
333 if (sendCommand(
":13#", res) ==
false)
338 int rc = sscanf(res,
"R%u#", &temp);
352 LOGF_ERROR(
"Invalid Response: focuser Reverse direction value (%s)", res);
358 LOGF_ERROR(
"Unknown error: focuser Reverse direction value (%s)", res);
364bool MyFocuserPro2::readStepMode()
366 char res[ML_RES] = {0};
368 if (sendCommand(
":29#", res) ==
false)
373 uint32_t stepmode = 0;
375 int rc = sscanf(res,
"S%u#", &stepmode);
409 LOGF_ERROR(
"Unknown error: Step mode value (%d)", stepmode);
416 LOGF_ERROR(
"Unknown error: Step mode value (%s)", res);
422bool MyFocuserPro2::readTemperature()
424 char res[ML_RES] = {0};
426 if(!readTempProbeAvailability())
429 if (sendCommand(
":06#", res) ==
false)
433 int rc = sscanf(res,
"Z%lf#", &temp);
436 TemperatureN[0].value = temp;
440 LOGF_ERROR(
"Unknown error: focuser temperature value (%s)", res);
446bool MyFocuserPro2::readTempCompensateEnable()
448 char res[ML_RES] = {0};
450 if (sendCommand(
":24#", res) ==
false)
457 int rc = sscanf(res,
"1%u#", &temp);
471 LOGF_ERROR(
"Invalid Response: focuser T.Compensate value (%s)", res);
477 LOGF_ERROR(
"Unknown error: focuser T.Compensate value (%s)", res);
484bool MyFocuserPro2::readPosition()
486 char res[ML_RES] = {0};
488 if (sendCommand(
":00#", res) ==
false)
494 int rc = sscanf(res,
"%*c%d#", &pos);
502 LOGF_ERROR(
"Unknown error: focuser position value (%s)", res);
508bool MyFocuserPro2::readTempProbeAvailability()
510 char res[ML_RES] = {0};
512 if (sendCommand(
":83#", res) ==
false)
518 int rc = sscanf(res,
"c%d#", &val);
522 return val==0 ? false :
true;
526 LOGF_ERROR(
"Unknown error: Temp Probe Availability value (%s). We assume available.", res);
532bool MyFocuserPro2::readTemperatureCoefficient()
534 char res[ML_RES] = {0};
536 if (sendCommand(
":26#", res) ==
false)
542 int rc = sscanf(res,
"B%d#", &val);
546 TemperatureSettingN[0].value = val;
550 LOGF_ERROR(
"Unknown error: Temperature Coefficient value (%s)", res);
556bool MyFocuserPro2::readSpeed()
558 char res[ML_RES] = {0};
560 if (sendCommand(
":43#", res) ==
false)
566 int rc = sscanf(res,
"C%d#", &speed);
574 LOGF_ERROR(
"Unknown error: focuser speed value (%s)", res);
580bool MyFocuserPro2::readMaxPos()
582 char res[ML_RES] = {0};
584 if (sendCommand(
":08#", res) ==
false)
590 int rc = sscanf(res,
"M%u#", &maxPos);
595 Focuser::SyncPresets(maxPos);
599 LOGF_ERROR(
"Unknown error: focuser max position value (%s)", res);
605bool MyFocuserPro2::readBacklashInSteps()
607 char res[ML_RES] = {0};
609 if (sendCommand(
":78#", res) ==
false)
614 uint32_t backlash = 0;
615 int rc = sscanf(res,
"6%u#", &backlash);
619 BacklashInStepsN[0].value = backlash;
623 BacklashInStepsN[0].value = 0;
624 LOGF_ERROR(
"Unknown error: focuser Backlash IN value (%s)", res);
630bool MyFocuserPro2::readBacklashInEnabled()
632 char res[ML_RES] = {0};
634 if (sendCommand(
":74#", res) ==
false)
640 int rc = sscanf(res,
"4%u#", &temp);
654 LOGF_ERROR(
"Unknown Response: focuser Backlash IN enabled (%s)", res);
660 LOGF_ERROR(
"Unknown error: focuser Backlash IN enabled (%s)", res);
666bool MyFocuserPro2::readBacklashOutSteps()
668 char res[ML_RES] = {0};
670 if (sendCommand(
":80#", res) ==
false)
675 uint32_t backlash = 0;
676 int rc = sscanf(res,
"7%u#", &backlash);
680 BacklashOutStepsN[0].value = backlash;
684 LOGF_ERROR(
"Unknown error: focuser Backlash OUT value (%s)", res);
690bool MyFocuserPro2::readBacklashOutEnabled()
692 char res[ML_RES] = {0};
694 if (sendCommand(
":76#", res) ==
false)
700 int rc = sscanf(res,
"5%u#", &temp);
714 LOGF_ERROR(
"Unknown response: focuser Backlash OUT enabled (%s)", res);
720 LOGF_ERROR(
"Unknown error: focuser Backlash OUT enabled (%s)", res);
726bool MyFocuserPro2::readDisplayVisible()
728 char res[ML_RES] = {0};
730 if (sendCommand(
":37#", res) ==
false)
737 int rc = sscanf(res,
"D%u#", &temp);
751 LOGF_ERROR(
"Invalid Response: focuser Display value (%s)", res);
757 LOGF_ERROR(
"Unknown error: focuser Display value (%s)", res);
763bool MyFocuserPro2::isMoving()
765 char res[ML_RES] = {0};
769 if (sendCommand(
":01#", res) ==
false)
776 int rc = sscanf(res,
"I%u#", &temp);
790 LOGF_ERROR(
"Invalid Response: focuser isMoving value (%s)", res);
796 LOGF_ERROR(
"Unknown error: focuser isMoving value (%s)", res);
801bool MyFocuserPro2::setTemperatureCelsius()
803 char cmd[ML_RES] = {0};
804 snprintf(
cmd, ML_RES,
":16#");
805 return sendCommand(
cmd);
808bool MyFocuserPro2::setTemperatureCoefficient(
double coefficient)
810 char cmd[ML_RES] = {0};
811 int coeff = coefficient;
812 snprintf(
cmd, ML_RES,
":22%d#", coeff);
813 return sendCommand(
cmd);
818 char cmd[ML_RES] = {0};
819 snprintf(
cmd, ML_RES,
":31%u#", ticks);
820 return sendCommand(
cmd);
825 char cmd[ML_RES] = {0};
830 snprintf(
cmd, ML_RES,
":05%u#", position);
831 return sendCommand(
cmd);
834bool MyFocuserPro2::setBacklashInSteps(int16_t steps)
836 char cmd[ML_RES] = {0};
837 snprintf(
cmd, ML_RES,
":77%d#", steps);
838 return sendCommand(
cmd);
841bool MyFocuserPro2::setBacklashInEnabled(
bool enabled)
843 char cmd[ML_RES] = {0};
844 snprintf(
cmd, ML_RES,
":73%c#", enabled ?
'1' :
'0');
845 return sendCommand(
cmd);
848bool MyFocuserPro2::setBacklashOutSteps(int16_t steps)
850 char cmd[ML_RES] = {0};
851 snprintf(
cmd, ML_RES,
":79%d#", steps);
852 return sendCommand(
cmd);
855bool MyFocuserPro2::setBacklashOutEnabled(
bool enabled)
857 char cmd[ML_RES] = {0};
858 snprintf(
cmd, ML_RES,
":75%c#", enabled ?
'1' :
'0');
859 return sendCommand(
cmd);
862bool MyFocuserPro2::setCoilPowerState(CoilPower enable)
864 char cmd[ML_RES] = {0};
866 snprintf(
cmd, ML_RES,
":12%d#", enable);
867 return sendCommand(
cmd);
872 char cmd[ML_RES] = {0};
873 snprintf(
cmd, ML_RES,
":14%d#",
static_cast<int>(enable));
874 return sendCommand(
cmd);
877bool MyFocuserPro2::setDisplayVisible(DisplayMode enable)
879 char cmd[ML_RES] = {0};
880 snprintf(
cmd, ML_RES,
":36%d#", enable);
881 return sendCommand(
cmd);
884bool MyFocuserPro2::setGotoHome()
886 char cmd[ML_RES] = {0};
891 snprintf(
cmd, ML_RES,
":28#");
892 return sendCommand(
cmd);
895bool MyFocuserPro2::setStepMode(FocusStepMode smode)
897 char cmd[ML_RES] = {0};
935 snprintf(
cmd, ML_RES,
":30%d#", stepmode);
936 return sendCommand(
cmd);
939bool MyFocuserPro2::setSpeed(uint16_t speed)
941 char cmd[ML_RES] = {0};
942 snprintf(
cmd, ML_RES,
":150%d#", speed);
943 return sendCommand(
cmd);
946bool MyFocuserPro2::setTemperatureCompensation(
bool enable)
948 char cmd[ML_RES] = {0};
949 snprintf(
cmd, ML_RES,
":23%c#", enable ?
'1' :
'0');
950 return sendCommand(
cmd);
958 if (strcmp(StepModeSP.
name, name) == 0)
966 if (current_mode == target_mode)
972 bool rc = setStepMode(
static_cast<FocusStepMode>(target_mode));
976 StepModeS[current_mode].s =
ISS_ON;
988 if (strcmp(GotoHomeSP.
name, name) == 0)
990 bool rc = setGotoHome();
1005 if (strcmp(CoilPowerSP.
name, name) == 0)
1013 if (current_mode == target_mode)
1019 bool rc = setCoilPowerState(
static_cast<CoilPower>(target_mode));
1023 CoilPowerS[current_mode].s =
ISS_ON;
1035 if (strcmp(DisplaySP.
name, name) == 0)
1043 if (current_mode == target_mode)
1049 bool rc = setDisplayVisible(
static_cast<DisplayMode>(target_mode));
1053 DisplayS[current_mode].s =
ISS_ON;
1065 if (strcmp(BacklashInSP.
name, name) == 0)
1073 if (current_mode == target_mode)
1079 bool rc = setBacklashInEnabled(target_mode ==
INDI_ENABLED);
1083 BacklashInS[current_mode].s =
ISS_ON;
1095 if (strcmp(BacklashOutSP.
name, name) == 0)
1103 if (current_mode == target_mode)
1109 bool rc = setBacklashOutEnabled(target_mode ==
INDI_ENABLED);
1113 BacklashOutS[current_mode].s =
ISS_ON;
1125 if (strcmp(TemperatureCompensateSP.
name, name) == 0)
1130 bool rc = setTemperatureCompensation((TemperatureCompensateS[0].s ==
ISS_ON));
1136 TemperatureCompensateS[last_index].s =
ISS_ON;
1141 TemperatureCompensateSP.
s =
IPS_OK;
1155 if (strcmp(name, TemperatureSettingNP.
name) == 0)
1158 if (!setTemperatureCoefficient(TemperatureSettingN[0].value))
1165 TemperatureSettingNP.
s =
IPS_OK;
1171 if (strcmp(name, BacklashInStepsNP.
name) == 0)
1174 if (!setBacklashInSteps(BacklashInStepsN[0].value))
1187 if (strcmp(name, BacklashOutStepsNP.
name) == 0)
1190 if (!setBacklashOutSteps(BacklashOutStepsN[0].value))
1197 BacklashOutStepsNP.
s =
IPS_OK;
1207void MyFocuserPro2::getStartupValues()
1212 readTemperatureCoefficient();
1214 readTempCompensateEnable();
1216 readCoilPowerState();
1217 readDisplayVisible();
1218 readReverseDirection();
1219 readBacklashInEnabled();
1220 readBacklashOutEnabled();
1221 readBacklashInSteps();
1222 readBacklashOutSteps();
1227 return setSpeed(speed);
1233 char cmd[ML_RES] = {0};
1235 snprintf(
cmd, ML_RES,
":07%06d#", maxPos);
1237 if(sendCommand(
cmd))
1239 Focuser::SyncPresets(maxPos);
1247 if (speed !=
static_cast<int>(
FocusSpeedNP[0].getValue()))
1249 if (!setSpeed(speed))
1275void MyFocuserPro2::timedMoveCallback()
1289 targetPos = targetTicks;
1300 int32_t newPosition = 0;
1312 newPosition = std::max(0, std::min(
static_cast<int32_t
>(
FocusAbsPosNP[0].getMax()), newPosition));
1334 if (Position_Counter++ == GET_POSITION_FREQ)
1337 Position_Counter = 0;
1338 bool rc = readPosition();
1356 LOG_INFO(
"Focuser reached requested position.");
1370 LOG_INFO(
"Focuser reached requested position.");
1375 if (Temperature_Counter++ == GET_TEMPERATURE_FREQ)
1378 Temperature_Counter = 0;
1379 bool rc = readTemperature();
1382 if (fabs(lastTemperature - TemperatureN[0].value) >= 0.5)
1385 lastTemperature = TemperatureN[0].value;
1394 return sendCommand(
":27#");
1399 Focuser::saveConfigItems(fp);
1414int MyFocuserPro2::msleep(
long duration)
1425 ts.tv_sec = duration / 1000;
1426 ts.tv_nsec = (duration % 1000) * 1000000;
1430 res = nanosleep(&ts, &ts);
1432 while (res &&
errno == EINTR);
1437void MyFocuserPro2::clearbufferonerror()
1440 char res[ML_RES] = {0};
1441 int nbytes_read = 0;
1445 pthread_mutex_lock(&cmdlock);
1446 msleep(MYFOCUSERPRO2_RECOVER_DELAY);
1456 pthread_mutex_unlock(&cmdlock);
1463 LOGF_ERROR(
"Data read from controller: %s.", res);
1467bool MyFocuserPro2::sendCommand(
const char *
cmd,
char * res)
1469 int nbytes_written = 0, nbytes_read = 0, rc = -1;
1471 tcflush(
PortFD, TCIOFLUSH);
1475 pthread_mutex_lock(&cmdlock);
1480 LOGF_ERROR(
"Connection write error: %s.", errstr);
1481 pthread_mutex_unlock(&cmdlock);
1488 pthread_mutex_unlock(&cmdlock);
1494 msleep(MYFOCUSERPRO2_SMALL_DELAY);
1512 LOGF_ERROR(
"Connection read error: %s.", errstr);
1513 pthread_mutex_unlock(&cmdlock);
1519 tcflush(
PortFD, TCIOFLUSH);
1520 pthread_mutex_unlock(&cmdlock);
void setDefaultHost(const char *addressHost)
void setDefaultPort(uint32_t addressPort)
void setPollingPeriodRange(uint32_t minimum, uint32_t maximum)
setPollingPeriodRange Set the range permitted by the polling range in milliseconds
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.
Connection::Interface * getActiveConnection()
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.
@ FOCUSER_HAS_VARIABLE_SPEED
INDI::PropertyNumber FocusSpeedNP
INDI::PropertyNumber FocusTimerNP
INDI::PropertyNumber FocusMaxPosNP
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,...
Connection::TCP * tcpConnection
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 setSupportedConnections(const uint8_t &value)
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
virtual bool saveConfigItems(FILE *fp) override
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration) override
MoveFocuser Move focuser in a specific direction and speed for period of time.
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
@ TEMP_COMPENSATE_DISABLE
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 SyncFocuser(uint32_t ticks) override
SyncFocuser Set the supplied position as the current focuser position.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool SetFocuserSpeed(int speed) override
SetFocuserSpeed Set Focuser speed.
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveRelFocuser Move focuser for a relative amount of ticks in a specific direction.
virtual bool Handshake() override
Handshake Try to communicate with Focuser and see if there is a valid response.
static void timedMoveHelper(void *context)
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
@ ONEHUNDREDTWENTYEIGHT_STEP
@ TWOHUNDREDFIFTYSIX_STEP
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveAbsFocuser Move to an absolute target position.
const char * getDefaultName() override
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
int IEAddTimer(int millisecs, IE_TCF *fp, void *p)
Register a new single-shot timer function, fp, to be called with ud as argument after ms.
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
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
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.
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 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 LOGF_ERROR(fmt,...)
#define STEPMODE_THIRTYSECOND
#define STEPMODE_ONEHUNDREDTWENTYEIGHT
#define CDRIVER_VERSION_MAJOR
#define STEPMODE_SIXTEENTH
#define CDRIVER_VERSION_MINOR
#define STEPMODE_SIXTYFOUR
#define STEPMODE_TWOHUNDREDFIFTYSIX