35 static 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";
220 bool 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);
292 bool 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);
329 bool 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);
364 bool 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);
422 bool MyFocuserPro2::readTemperature()
424 char res[ML_RES] = {0};
426 if (sendCommand(
":06#", res) ==
false)
430 int rc = sscanf(res,
"Z%lf#", &temp);
433 TemperatureN[0].value = temp;
437 LOGF_ERROR(
"Unknown error: focuser temperature value (%s)", res);
443 bool MyFocuserPro2::readTempCompensateEnable()
445 char res[ML_RES] = {0};
447 if (sendCommand(
":24#", res) ==
false)
454 int rc = sscanf(res,
"1%u#", &temp);
468 LOGF_ERROR(
"Invalid Response: focuser T.Compensate value (%s)", res);
474 LOGF_ERROR(
"Unknown error: focuser T.Compensate value (%s)", res);
481 bool MyFocuserPro2::readPosition()
483 char res[ML_RES] = {0};
485 if (sendCommand(
":00#", res) ==
false)
491 int rc = sscanf(res,
"%*c%d#", &pos);
499 LOGF_ERROR(
"Unknown error: focuser position value (%s)", res);
505 bool MyFocuserPro2::readTemperatureCoefficient()
507 char res[ML_RES] = {0};
509 if (sendCommand(
":26#", res) ==
false)
515 int rc = sscanf(res,
"B%d#", &val);
519 TemperatureSettingN[0].value = val;
523 LOGF_ERROR(
"Unknown error: Temperature Coefficient value (%s)", res);
529 bool MyFocuserPro2::readSpeed()
531 char res[ML_RES] = {0};
533 if (sendCommand(
":43#", res) ==
false)
539 int rc = sscanf(res,
"C%d#", &speed);
547 LOGF_ERROR(
"Unknown error: focuser speed value (%s)", res);
553 bool MyFocuserPro2::readMaxPos()
555 char res[ML_RES] = {0};
557 if (sendCommand(
":08#", res) ==
false)
563 int rc = sscanf(res,
"M%u#", &maxPos);
568 Focuser::SyncPresets(maxPos);
572 LOGF_ERROR(
"Unknown error: focuser max position value (%s)", res);
578 bool MyFocuserPro2::readBacklashInSteps()
580 char res[ML_RES] = {0};
582 if (sendCommand(
":78#", res) ==
false)
587 uint32_t backlash = 0;
588 int rc = sscanf(res,
"6%u#", &backlash);
592 BacklashInStepsN[0].value = backlash;
596 BacklashInStepsN[0].value = 0;
597 LOGF_ERROR(
"Unknown error: focuser Backlash IN value (%s)", res);
603 bool MyFocuserPro2::readBacklashInEnabled()
605 char res[ML_RES] = {0};
607 if (sendCommand(
":74#", res) ==
false)
613 int rc = sscanf(res,
"4%u#", &temp);
627 LOGF_ERROR(
"Unknown Response: focuser Backlash IN enabled (%s)", res);
633 LOGF_ERROR(
"Unknown error: focuser Backlash IN enabled (%s)", res);
639 bool MyFocuserPro2::readBacklashOutSteps()
641 char res[ML_RES] = {0};
643 if (sendCommand(
":80#", res) ==
false)
648 uint32_t backlash = 0;
649 int rc = sscanf(res,
"7%u#", &backlash);
653 BacklashOutStepsN[0].value = backlash;
657 LOGF_ERROR(
"Unknown error: focuser Backlash OUT value (%s)", res);
663 bool MyFocuserPro2::readBacklashOutEnabled()
665 char res[ML_RES] = {0};
667 if (sendCommand(
":76#", res) ==
false)
673 int rc = sscanf(res,
"5%u#", &temp);
687 LOGF_ERROR(
"Unknown response: focuser Backlash OUT enabled (%s)", res);
693 LOGF_ERROR(
"Unknown error: focuser Backlash OUT enabled (%s)", res);
699 bool MyFocuserPro2::readDisplayVisible()
701 char res[ML_RES] = {0};
703 if (sendCommand(
":37#", res) ==
false)
710 int rc = sscanf(res,
"D%u#", &temp);
724 LOGF_ERROR(
"Invalid Response: focuser Display value (%s)", res);
730 LOGF_ERROR(
"Unknown error: focuser Display value (%s)", res);
736 bool MyFocuserPro2::isMoving()
738 char res[ML_RES] = {0};
740 if (sendCommand(
":01#", res) ==
false)
747 int rc = sscanf(res,
"I%u#", &temp);
761 LOGF_ERROR(
"Invalid Response: focuser isMoving value (%s)", res);
767 LOGF_ERROR(
"Unknown error: focuser isMoving value (%s)", res);
772 bool MyFocuserPro2::setTemperatureCelsius()
774 char cmd[ML_RES] = {0};
775 snprintf(
cmd, ML_RES,
":16#");
776 return sendCommand(
cmd);
779 bool MyFocuserPro2::setTemperatureCoefficient(
double coefficient)
781 char cmd[ML_RES] = {0};
782 int coeff = coefficient;
783 snprintf(
cmd, ML_RES,
":22%d#", coeff);
784 return sendCommand(
cmd);
789 char cmd[ML_RES] = {0};
790 snprintf(
cmd, ML_RES,
":31%u#", ticks);
791 return sendCommand(
cmd);
796 char cmd[ML_RES] = {0};
801 snprintf(
cmd, ML_RES,
":05%u#", position);
802 return sendCommand(
cmd);
805 bool MyFocuserPro2::setBacklashInSteps(int16_t steps)
807 char cmd[ML_RES] = {0};
808 snprintf(
cmd, ML_RES,
":77%d#", steps);
809 return sendCommand(
cmd);
812 bool MyFocuserPro2::setBacklashInEnabled(
bool enabled)
814 char cmd[ML_RES] = {0};
815 snprintf(
cmd, ML_RES,
":73%c#", enabled ?
'1' :
'0');
816 return sendCommand(
cmd);
819 bool MyFocuserPro2::setBacklashOutSteps(int16_t steps)
821 char cmd[ML_RES] = {0};
822 snprintf(
cmd, ML_RES,
":79%d#", steps);
823 return sendCommand(
cmd);
826 bool MyFocuserPro2::setBacklashOutEnabled(
bool enabled)
828 char cmd[ML_RES] = {0};
829 snprintf(
cmd, ML_RES,
":75%c#", enabled ?
'1' :
'0');
830 return sendCommand(
cmd);
833 bool MyFocuserPro2::setCoilPowerState(CoilPower enable)
835 char cmd[ML_RES] = {0};
837 snprintf(
cmd, ML_RES,
":12%d#", enable);
838 return sendCommand(
cmd);
843 char cmd[ML_RES] = {0};
844 snprintf(
cmd, ML_RES,
":14%d#",
static_cast<int>(enable));
845 return sendCommand(
cmd);
848 bool MyFocuserPro2::setDisplayVisible(DisplayMode enable)
850 char cmd[ML_RES] = {0};
851 snprintf(
cmd, ML_RES,
":36%d#", enable);
852 return sendCommand(
cmd);
855 bool MyFocuserPro2::setGotoHome()
857 char cmd[ML_RES] = {0};
862 snprintf(
cmd, ML_RES,
":28#");
863 return sendCommand(
cmd);
866 bool MyFocuserPro2::setStepMode(FocusStepMode smode)
868 char cmd[ML_RES] = {0};
906 snprintf(
cmd, ML_RES,
":30%d#", stepmode);
907 return sendCommand(
cmd);
910 bool MyFocuserPro2::setSpeed(uint16_t speed)
912 char cmd[ML_RES] = {0};
913 snprintf(
cmd, ML_RES,
":150%d#", speed);
914 return sendCommand(
cmd);
917 bool MyFocuserPro2::setTemperatureCompensation(
bool enable)
919 char cmd[ML_RES] = {0};
920 snprintf(
cmd, ML_RES,
":23%c#", enable ?
'1' :
'0');
921 return sendCommand(
cmd);
929 if (strcmp(StepModeSP.
name, name) == 0)
937 if (current_mode == target_mode)
943 bool rc = setStepMode(
static_cast<FocusStepMode>(target_mode));
947 StepModeS[current_mode].s =
ISS_ON;
959 if (strcmp(GotoHomeSP.
name, name) == 0)
961 bool rc = setGotoHome();
976 if (strcmp(CoilPowerSP.
name, name) == 0)
984 if (current_mode == target_mode)
990 bool rc = setCoilPowerState(
static_cast<CoilPower>(target_mode));
994 CoilPowerS[current_mode].s =
ISS_ON;
1006 if (strcmp(DisplaySP.
name, name) == 0)
1014 if (current_mode == target_mode)
1020 bool rc = setDisplayVisible(
static_cast<DisplayMode>(target_mode));
1024 DisplayS[current_mode].s =
ISS_ON;
1036 if (strcmp(BacklashInSP.
name, name) == 0)
1044 if (current_mode == target_mode)
1050 bool rc = setBacklashInEnabled(target_mode ==
INDI_ENABLED);
1054 BacklashInS[current_mode].s =
ISS_ON;
1066 if (strcmp(BacklashOutSP.
name, name) == 0)
1074 if (current_mode == target_mode)
1080 bool rc = setBacklashOutEnabled(target_mode ==
INDI_ENABLED);
1084 BacklashOutS[current_mode].s =
ISS_ON;
1096 if (strcmp(TemperatureCompensateSP.
name, name) == 0)
1101 bool rc = setTemperatureCompensation((TemperatureCompensateS[0].s ==
ISS_ON));
1107 TemperatureCompensateS[last_index].s =
ISS_ON;
1112 TemperatureCompensateSP.
s =
IPS_OK;
1126 if (strcmp(name, TemperatureSettingNP.
name) == 0)
1129 if (!setTemperatureCoefficient(TemperatureSettingN[0].value))
1136 TemperatureSettingNP.
s =
IPS_OK;
1142 if (strcmp(name, BacklashInStepsNP.
name) == 0)
1145 if (!setBacklashInSteps(BacklashInStepsN[0].value))
1158 if (strcmp(name, BacklashOutStepsNP.
name) == 0)
1161 if (!setBacklashOutSteps(BacklashOutStepsN[0].value))
1168 BacklashOutStepsNP.
s =
IPS_OK;
1178 void MyFocuserPro2::getStartupValues()
1183 readTemperatureCoefficient();
1185 readTempCompensateEnable();
1187 readCoilPowerState();
1188 readDisplayVisible();
1189 readReverseDirection();
1190 readBacklashInEnabled();
1191 readBacklashOutEnabled();
1192 readBacklashInSteps();
1193 readBacklashOutSteps();
1198 return setSpeed(speed);
1204 char cmd[ML_RES] = {0};
1206 snprintf(
cmd, ML_RES,
":07%06d#", maxPos);
1208 if(sendCommand(
cmd))
1210 Focuser::SyncPresets(maxPos);
1218 if (speed !=
static_cast<int>(
FocusSpeedN[0].value))
1220 if (!setSpeed(speed))
1246 void MyFocuserPro2::timedMoveCallback()
1260 targetPos = targetTicks;
1271 int32_t newPosition = 0;
1305 if (Position_Counter++ == GET_POSITION_FREQ)
1308 Position_Counter = 0;
1309 bool rc = readPosition();
1327 LOG_INFO(
"Focuser reached requested position.");
1341 LOG_INFO(
"Focuser reached requested position.");
1346 if (Temperature_Counter++ == GET_TEMPERATURE_FREQ)
1349 Temperature_Counter = 0;
1350 bool rc = readTemperature();
1353 if (fabs(lastTemperature - TemperatureN[0].value) >= 0.5)
1356 lastTemperature = TemperatureN[0].value;
1365 return sendCommand(
":27#");
1370 Focuser::saveConfigItems(fp);
1385 int MyFocuserPro2::msleep(
long duration)
1396 ts.tv_sec = duration / 1000;
1397 ts.tv_nsec = (duration % 1000) * 1000000;
1401 res = nanosleep(&ts, &ts);
1403 while (res &&
errno == EINTR);
1408 void MyFocuserPro2::clearbufferonerror()
1411 char res[ML_RES] = {0};
1412 int nbytes_read = 0;
1416 pthread_mutex_lock(&cmdlock);
1417 msleep(MYFOCUSERPRO2_RECOVER_DELAY);
1427 pthread_mutex_unlock(&cmdlock);
1434 LOGF_ERROR(
"Data read from controller: %s.", res);
1438 bool MyFocuserPro2::sendCommand(
const char *
cmd,
char * res)
1440 int nbytes_written = 0, nbytes_read = 0, rc = -1;
1442 tcflush(
PortFD, TCIOFLUSH);
1446 pthread_mutex_lock(&cmdlock);
1451 LOGF_ERROR(
"Connection write error: %s.", errstr);
1452 pthread_mutex_unlock(&cmdlock);
1459 pthread_mutex_unlock(&cmdlock);
1465 msleep(MYFOCUSERPRO2_SMALL_DELAY);
1483 LOGF_ERROR(
"Connection read error: %s.", errstr);
1484 pthread_mutex_unlock(&cmdlock);
1490 tcflush(
PortFD, TCIOFLUSH);
1491 pthread_mutex_unlock(&cmdlock);
void setDefaultHost(const char *addressHost)
void setDefaultPort(uint32_t addressPort)
const char * getDeviceName() const
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.
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
INumberVectorProperty FocusTimerNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
@ FOCUSER_HAS_VARIABLE_SPEED
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.
Connection::TCP * tcpConnection
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
void setSupportedConnections(const uint8_t &value)
setConnection Set Focuser connection mode. Child class should call this in the constructor before Foc...
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
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
Process the client newNumber command.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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
Initilize properties initial state and value. The child class must implement this function.
@ 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 CDRIVER_VERSION_MAJOR
#define CDRIVER_VERSION_MINOR
#define STEPMODE_THIRTYSECOND
#define STEPMODE_ONEHUNDREDTWENTYEIGHT
#define STEPMODE_SIXTEENTH
#define STEPMODE_SIXTYFOUR
#define STEPMODE_TWOHUNDREDFIFTYSIX