31 static std::unique_ptr<NStep> nstep(
new NStep());
48 IUFillNumber(&TemperatureN[0],
"TEMPERATURE",
"Celsius",
"%6.2f", -100, 100, 0, 0);
53 IUFillSwitch(&CompensationModeS[COMPENSATION_MODE_OFF],
"COMPENSATION_MODE_OFF",
"Off",
ISS_ON);
54 IUFillSwitch(&CompensationModeS[COMPENSATION_MODE_ONE_SHOT],
"COMPENSATION_MODE_ONE_SHOT",
"One shot",
ISS_OFF);
55 IUFillSwitch(&CompensationModeS[COMPENSATION_MODE_AUTO],
"COMPENSATION_MODE_AUTO",
"Auto",
ISS_OFF);
65 IUFillNumber(&CompensationSettingsN[COMPENSATION_SETTING_CHANGE],
"COMPENSATION_SETTING_CHANGE",
"Delta T. (C)",
"%.1f",
67 IUFillNumber(&CompensationSettingsN[COMPENSATION_SETTING_STEP],
"COMPENSATION_SETTING_STEP",
"Steps per Delta",
"%.0f", 0,
69 IUFillNumber(&CompensationSettingsN[COMPENSATION_SETTING_BACKLASH],
"COMPENSATION_SETTING_BACKLASH",
"Backlash steps",
70 "%.0f", 0, 999, 1, 0);
71 IUFillNumber(&CompensationSettingsN[COMPENSATION_SETTING_TIMER],
"COMPENSATION_SETTING_TIMER",
"Averaged Time (s)",
"%.0f",
84 IUFillNumber(&SteppingPhaseN[0],
"PHASES",
"Wiring",
"%.f", 0, 2, 1, 0);
89 IUFillNumber(&MaxSpeedN[0],
"RATE",
"Rate",
"%.f", 1, 254, 10, 0);
94 IUFillSwitch(&CoilStatusS[COIL_ENERGIZED_OFF],
"COIL_ENERGIZED_OFF",
"De-energized",
ISS_OFF);
119 return "Rigel NStep";
135 if (readTemperature())
138 bool rc = getStartupValues();
152 LOG_WARN(
"Failed to query startup values.");
173 char cmd[NSTEP_LEN] = {0}, res[NSTEP_LEN] = {0};
178 bool rc = sendCommand(
cmd, res, 1, 1);
182 return res[0] ==
'S';
185 bool NStep::sendCommand(
const char *
cmd,
char * res,
int cmd_len,
int res_len)
187 int nbytes_written = 0, nbytes_read = 0, rc = -1;
189 tcflush(
PortFD, TCIOFLUSH);
193 char hex_cmd[NSTEP_LEN * 3] = {0};
194 hexDump(hex_cmd,
cmd, cmd_len);
208 LOGF_ERROR(
"Serial write error: %s.", errstr);
230 char hex_res[NSTEP_LEN * 3] = {0};
231 hexDump(hex_res, res, res_len);
239 tcflush(
PortFD, TCIOFLUSH);
244 void NStep::hexDump(
char * buf,
const char * data,
int size)
246 for (
int i = 0; i < size; i++)
247 sprintf(buf + 3 * i,
"%02X ",
static_cast<uint8_t
>(data[i]));
250 buf[3 * size - 1] =
'\0';
258 if (!strcmp(name, CompensationSettingsNP.
name))
261 int change = 0, step = 0, backlash = 0, timer = 0;
262 for (
int i = 0; i < n; i++)
264 if (!strcmp(names[i], CompensationSettingsN[COMPENSATION_SETTING_CHANGE].name))
268 else if (!strcmp(names[i], CompensationSettingsN[COMPENSATION_SETTING_STEP].name))
272 else if (!strcmp(names[i], CompensationSettingsN[COMPENSATION_SETTING_BACKLASH].name))
274 backlash = values[i];
276 else if (!strcmp(names[i], CompensationSettingsN[COMPENSATION_SETTING_TIMER].name))
283 if (setCompensationSettings(change, step, backlash, timer))
286 CompensationSettingsNP.
s =
IPS_OK;
299 if (!strcmp(name, SteppingPhaseNP.
name))
301 if (setSteppingPhase(
static_cast<uint8_t
>(values[0])))
314 if (!strcmp(name, MaxSpeedNP.
name))
316 if (setMaxSpeed(
static_cast<uint8_t
>(values[0])))
343 if (!strcmp(name, CompensationModeSP.
name))
348 if (setCompensationMode(mode))
354 case COMPENSATION_MODE_OFF:
355 LOG_INFO(
"Temperature compensation is disabled.");
358 case COMPENSATION_MODE_ONE_SHOT:
360 CompensationModeS[COMPENSATION_MODE_OFF].s =
ISS_ON;
361 LOG_INFO(
"One shot compensation applied.");
364 case COMPENSATION_MODE_AUTO:
365 LOG_INFO(
"Automatic temperature compensation is enabled.");
372 CompensationModeS[prevIndex].s =
ISS_ON;
374 LOG_ERROR(
"Failed to change temperature compensation mode.");
382 if (!strcmp(name, PrimeManualSP.
name))
387 LOG_INFO(
"Prime for manual complete. Click One Shot to apply manual compensation once.");
392 if (!strcmp(name, SteppingModeSP.
name))
401 if (!strcmp(name, CoilStatusSP.
name))
406 if (setCoilStatus(state))
409 if (state == COIL_ENERGIZED_ON)
410 LOG_WARN(
"Coil shall be kept energized after motion is complete. Watch for motor heating!");
412 LOG_INFO(
"Coil shall be de-energized after motion is complete.");
417 CoilStatusS[prevIndex].s =
ISS_ON;
419 LOG_ERROR(
"Failed to update coil energization status.");
430 bool NStep::getStartupValues()
432 bool rc1 = readCoilStatus();
433 bool rc2 = readSteppingInfo();
434 bool rc3 = readCompensationInfo();
436 return (rc1 && rc2 && rc3);
447 m_TargetDiff = ticks * ((dir ==
FOCUS_INWARD) ? -1 : 1);
453 return sendCommand(
"F00000#");
470 if (m_TargetDiff == 0)
482 int nextMotion = (std::abs(m_TargetDiff) > 999) ? 999 : std::abs(m_TargetDiff);
485 char cmd[NSTEP_LEN] = {0};
486 snprintf(
cmd, NSTEP_LEN,
":F%d%d%03d#", direction, mode, nextMotion);
487 if (sendCommand(
cmd) ==
false)
489 LOG_ERROR(
"Failed to issue motion command.");
505 m_TargetDiff = m_TargetDiff + (nextMotion * ((direction ==
FOCUS_INWARD) ? 1 : -1));
515 if (TemperatureNP.
s ==
IPS_OK && m_TemperatureCounter++ == NSTEP_TEMPERATURE_FREQ)
517 m_TemperatureCounter = 0;
518 if (readTemperature())
525 bool NStep::isMoving()
527 char res[NSTEP_LEN] = {0};
529 bool rc = sendCommand(
"S", res, 1, 1);
531 if (rc && res[0] ==
'1')
537 bool NStep::readTemperature()
539 char res[NSTEP_LEN] = {0};
541 if (sendCommand(
":RT", res, 3, 4) ==
false)
544 float temperature = -1000;
545 sscanf(res,
"%f", &temperature);
550 if (temperature < -80)
553 TemperatureN[0].value = temperature;
559 bool NStep::readPosition()
561 char res[NSTEP_LEN] = {0};
563 if (sendCommand(
":RP", res, 3, 7) ==
false)
567 sscanf(res,
"%d", &pos);
577 bool NStep::readCompensationInfo()
579 char res[NSTEP_LEN] = {0};
580 int32_t change = 1e6, step = 1e6, state = 1e6, backlash = 1e6, timer = 1e6;
583 if (sendCommand(
":RG", res, 3, 1) ==
false)
585 std::this_thread::sleep_for(std::chrono::milliseconds(250));
586 if (sendCommand(
":RG", res, 3, 1) ==
false)
589 sscanf(res,
"%d", &state);
593 CompensationModeS[state].s =
ISS_ON;
597 memset(res, 0, NSTEP_LEN);
598 if (sendCommand(
":RA", res, 3, 4) ==
false)
600 std::this_thread::sleep_for(std::chrono::milliseconds(250));
601 if (sendCommand(
":RA", res, 3, 4) ==
false)
604 sscanf(res,
"%d", &change);
607 CompensationSettingsN[COMPENSATION_SETTING_CHANGE].value = change;
610 memset(res, 0, NSTEP_LEN);
611 if (sendCommand(
":RB", res, 3, 3) ==
false)
613 std::this_thread::sleep_for(std::chrono::milliseconds(250));
614 if (sendCommand(
":RB", res, 3, 3) ==
false)
617 sscanf(res,
"%d", &step);
620 CompensationSettingsN[COMPENSATION_SETTING_STEP].value = step;
623 memset(res, 0, NSTEP_LEN);
624 if (sendCommand(
":RE", res, 3, 3) ==
false)
626 std::this_thread::sleep_for(std::chrono::milliseconds(250));
627 if (sendCommand(
":RE", res, 3, 3) ==
false)
630 sscanf(res,
"%d", &backlash);
633 CompensationSettingsN[COMPENSATION_SETTING_BACKLASH].value = backlash;
636 memset(res, 0, NSTEP_LEN);
637 if (sendCommand(
":RH", res, 3, 2) ==
false)
639 std::this_thread::sleep_for(std::chrono::milliseconds(250));
640 if (sendCommand(
":RH", res, 3, 2) ==
false)
643 sscanf(res,
"%d", &timer);
646 CompensationSettingsN[COMPENSATION_SETTING_TIMER].value = timer;
647 CompensationSettingsNP.
s =
IPS_OK;
653 bool NStep::readSpeedInfo()
655 char res[NSTEP_LEN] = {0};
656 int32_t max_step = 1e6, current_step = 1e6;
659 if (sendCommand(
":RS", res, 3, 3) ==
false)
661 sscanf(res,
"%d", &max_step);
666 if (sendCommand(
":RO", res, 3, 3) ==
false)
668 sscanf(res,
"%d", ¤t_step);
669 if (current_step == 1e6)
672 MaxSpeedN[0].value = 254 - max_step + 1;
684 bool NStep::readSteppingInfo()
686 char res[NSTEP_LEN] = {0};
688 if (sendCommand(
":RW", res, 3, 1) ==
false)
692 sscanf(res,
"%d", &phase);
697 SteppingPhaseN[0].value = phase;
703 bool NStep::readCoilStatus()
705 char res[NSTEP_LEN] = {0};
707 if (sendCommand(
":RC", res, 3, 1) ==
false)
712 CoilStatusS[COIL_ENERGIZED_OFF].s = (res[0] ==
'0') ?
ISS_ON :
ISS_OFF;
713 CoilStatusS[COIL_ENERGIZED_ON].s = (res[0] ==
'0') ?
ISS_OFF :
ISS_ON;
721 char cmd[NSTEP_LEN] = {0};
722 snprintf(
cmd, NSTEP_LEN,
"#:CP+%06d#", ticks);
723 return sendCommand(
cmd);
730 char cmd[NSTEP_LEN] = {0};
731 snprintf(
cmd, NSTEP_LEN,
"#:CO%03d#", 254 - speed + 1);
732 return sendCommand(
cmd);
735 bool NStep::setMaxSpeed(uint8_t maxSpeed)
740 char cmd[NSTEP_LEN] = {0};
741 snprintf(
cmd, NSTEP_LEN,
":CS%03d#", 254 - maxSpeed + 1);
742 return sendCommand(
cmd);
745 bool NStep::setCompensationMode(uint8_t mode)
747 char cmd[NSTEP_LEN] = {0};
748 snprintf(
cmd, NSTEP_LEN,
"#:TA%01d#", mode);
749 return sendCommand(
cmd);
752 bool NStep::setCompensationSettings(
double change,
double move,
double backlash,
double timer)
754 int temperature_change = change * 10;
755 char cmd[NSTEP_LEN] = {0};
756 snprintf(
cmd, NSTEP_LEN,
":TT%+03d#", temperature_change);
757 bool rc1 = sendCommand(
cmd);
759 int temperature_steps =
static_cast<int>(move);
760 snprintf(
cmd, NSTEP_LEN,
":TS%03d#", temperature_steps);
761 bool rc2 = sendCommand(
cmd);
763 int temperature_backlash =
static_cast<int>(backlash);
764 snprintf(
cmd, NSTEP_LEN,
":TB%03d#", temperature_backlash);
765 bool rc3 = sendCommand(
cmd);
768 int temperature_timer =
static_cast<int>(timer);
772 snprintf(
cmd, NSTEP_LEN,
":TC%02d#", temperature_timer);
773 rc4 = sendCommand(
cmd);
776 return (rc1 && rc2 && rc3 && rc4);
779 bool NStep::setSteppingPhase(uint8_t phase)
781 char cmd[NSTEP_LEN] = {0};
782 snprintf(
cmd, NSTEP_LEN,
"#:CW%01d#", phase);
783 return sendCommand(
cmd);
786 bool NStep::setCoilStatus(uint8_t status)
788 char cmd[NSTEP_LEN] = {0};
789 snprintf(
cmd, NSTEP_LEN,
"#:CC%01d#", status == COIL_ENERGIZED_OFF ? 1 : 0);
790 return sendCommand(
cmd);
const char * getDeviceName() const
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.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
INumberVectorProperty FocusSpeedNP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
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 saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
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.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
bool SetFocuserSpeed(int speed) override
SetFocuserSpeed Set Focuser speed.
IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
const char * getDefaultName() override
virtual bool Handshake() override
perform handshake with device to check communication
bool AbortFocuser() override
AbortFocuser all focus motion.
bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
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.
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
#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,...)