34static std::unique_ptr<nFrameRotator> rotator(
new nFrameRotator());
52 SteppingModeSP[STEPPING_WAVE].
fill(
"STEPPING_WAVE",
"Wave",
ISS_OFF);
53 SteppingModeSP[STEPPING_HALF].
fill(
"STEPPING_HALF",
"Half",
ISS_OFF);
54 SteppingModeSP[STEPPING_FULL].
fill(
"STEPPING_FULL",
"Full",
ISS_ON);
59 SteppingPhaseNP[0].
fill(
"PHASES",
"Wiring",
"%.f", 0, 2, 1, 0);
64 RotatorSpeedNP[0].
fill(
"ROTATE_SPEED_VALUE",
"Step Rate",
"%3.0f", 0.0, 255.0, 1.0, 255.0);
69 MaxSpeedNP[0].
fill(
"RATE",
"Rate",
"%.f", 1, 254, 10, 0);
74 CoilStatusSP[COIL_ENERGIZED_OFF].
fill(
"COIL_ENERGIZED_OFF",
"De-energized",
ISS_OFF);
75 CoilStatusSP[COIL_ENERGIZED_ON].
fill(
"COIL_ENERGIZED_ON",
"Energized",
ISS_OFF);
79 SettingNP[PARAM_STEPS_DEGREE].
fill(
"PARAM_STEPS_DEGREE",
"Steps/Degree",
"%.2f", 1., 10000., 500., 1000.);
83 RotatorAbsPosNP[0].
fill(
"ROTATOR_ABSOLUTE_POSITION",
"Value",
"%.f", 0., 1000000., 0., 0.);
104 return "nFrameRotator";
121 RotatorAbsPosNP.
apply();
126 bool rc = getStartupValues();
135 LOG_INFO(
"nFrameRotator is ready.");
137 LOG_WARN(
"Failed to query startup values.");
155 char cmd[NFRAME_LEN] = {0}, res[NFRAME_LEN] = {0};
160 bool rc = sendCommand(
cmd, res, 1, 1);
164 return res[0] ==
'S';
167bool nFrameRotator::sendCommand(
const char *
cmd,
char * res,
int cmd_len,
int res_len)
169 int nbytes_written = 0, nbytes_read = 0, rc = -1;
171 tcflush(
PortFD, TCIOFLUSH);
175 char hex_cmd[NFRAME_LEN * 3] = {0};
176 hexDump(hex_cmd,
cmd, cmd_len);
190 LOGF_ERROR(
"Serial write error: %s.", errstr);
198 rc =
tty_read(
PortFD, res, res_len, NFRAME_TIMEOUT, &nbytes_read);
212 char hex_res[NFRAME_LEN * 3] = {0};
213 hexDump(hex_res, res, res_len);
221 tcflush(
PortFD, TCIOFLUSH);
226void nFrameRotator::hexDump(
char * buf,
const char * data,
int size)
228 for (
int i = 0; i < size; i++)
229 sprintf(buf + 3 * i,
"%02X ",
static_cast<uint8_t
>(data[i]));
232 buf[3 * size - 1] =
'\0';
243 if (setSteppingPhase(
static_cast<uint8_t
>(values[0])))
245 SteppingPhaseNP.
update(values, names, n);
251 SteppingPhaseNP.
apply();
276 if (setMaxSpeed(
static_cast<uint8_t
>(values[0])))
278 MaxSpeedNP.
update(values, names, n);
296 std::vector<double> prevValue(SettingNP.
count());
297 for (uint8_t i = 0; i < SettingNP.
count(); i++)
298 prevValue[i] = SettingNP[i].getValue();
299 SettingNP.
update(values, names, n);
302 if (SettingNP[PARAM_STEPS_DEGREE].value != prevValue[PARAM_STEPS_DEGREE])
304 GotoRotatorNP[0].setValue(calculateAngle(RotatorAbsPosNP[0].getValue()));
310 for (uint8_t i = 0; i < SettingNP.
count(); i++)
311 SettingNP[i].
setValue(prevValue[i]);
332 SteppingModeSP.
update(states, names, n);
334 SteppingModeSP.
apply();
343 CoilStatusSP.
update(states, names, n);
345 if (setCoilStatus(state))
348 if (state == COIL_ENERGIZED_ON)
349 LOG_WARN(
"Coil shall be kept energized after motion is complete. Watch for motor heating!");
351 LOG_INFO(
"Coil shall be de-energized after motion is complete.");
355 CoilStatusSP.
reset();
358 LOG_ERROR(
"Failed to update coil energization status.");
361 CoilStatusSP.
apply();
369bool nFrameRotator::getStartupValues()
371 bool rc1 = readCoilStatus();
372 bool rc2 = readSteppingInfo();
374 return (rc1 && rc2 );
379 requestedAngle = angle ;
381 LOGF_DEBUG(
"Angle = <%f> Step/Deg=<%d>", angle, (
int)SettingNP[PARAM_STEPS_DEGREE].getValue());
383 double r = (angle > 180) ? 360 - angle : angle;
384 int sign = (angle >= 0 && angle <= 180) ? 1 : -1;
391 double newTarget = r * SettingNP[PARAM_STEPS_DEGREE].getValue() + m_ZeroPosition;
392 m_TargetDiff = (int)newTarget - (
int)RotatorAbsPosNP[0].getValue();
419 LOGF_DEBUG(
"wantAbort = %d, diff = %d", wantAbort, m_TargetDiff);
421 if (m_TargetDiff == 0)
425 LOGF_DEBUG(
"HIT reqAngle=%f diff=%d", requestedAngle, m_TargetDiff);
426 RotatorAbsPosNP.
apply();
434 int nextMotion = (std::abs(m_TargetDiff) > 999) ? 999 : std::abs(m_TargetDiff);
437 char cmd[NFRAME_LEN] = {0};
438 snprintf(
cmd, NFRAME_LEN,
":F%d%d%03d#", direction, mode, nextMotion);
439 if (sendCommand(
cmd) ==
false)
441 LOG_ERROR(
"Failed to issue motion command.");
450 RotatorAbsPosNP.
apply();
458 m_TargetDiff = m_TargetDiff + (nextMotion * ((direction ==
ROTATE_INWARD) ? 1 : -1));
463 if (m_TargetDiff == 0)
465 RotatorAbsPosNP.
apply();
467 RotatorAbsPosNP.
apply();
473bool nFrameRotator::isMoving()
475 char res[NFRAME_LEN] = {0};
477 bool rc = sendCommand(
"S", res, 1, 1);
479 if (rc && res[0] ==
'1')
486bool nFrameRotator::readPosition()
488 char res[NFRAME_LEN] = {0};
490 if (sendCommand(
":RP", res, 3, 7) ==
false)
494 sscanf(res,
"%d", &pos);
500 RotatorAbsPosNP[0].setValue(pos);
502 GotoRotatorNP[0].setValue(calculateAngle(RotatorAbsPosNP[0].getValue() ));
503 RotatorAbsPosNP.
apply();
510bool nFrameRotator::readSpeedInfo()
512 char res[NFRAME_LEN] = {0};
513 int32_t max_step = 1e6, current_step = 1e6;
516 if (sendCommand(
":RS", res, 3, 3) ==
false)
518 sscanf(res,
"%d", &max_step);
523 if (sendCommand(
":RO", res, 3, 3) ==
false)
525 sscanf(res,
"%d", ¤t_step);
526 if (current_step == 1e6)
529 MaxSpeedNP[0].setValue(254 - max_step + 1);
543bool nFrameRotator::readSteppingInfo()
545 char res[NFRAME_LEN] = {0};
547 if (sendCommand(
":RW", res, 3, 1) ==
false)
551 sscanf(res,
"%d", &phase);
556 SteppingPhaseNP[0].setValue(phase);
562bool nFrameRotator::readCoilStatus()
564 char res[NFRAME_LEN] = {0};
566 if (sendCommand(
":RC", res, 3, 1) ==
false)
569 CoilStatusSP.
reset();
587 double r = (angle > 180) ? 360 - angle : angle;
588 int sign = (angle >= 0 && angle <= 180) ? 1 : -1;
592 double newTarget = r * SettingNP[PARAM_STEPS_DEGREE].getValue() + m_ZeroPosition;
594 char cmd[NFRAME_LEN] = {0};
595 snprintf(
cmd, NFRAME_LEN,
"#:CP+%06d#", (
int)newTarget);
596 return sendCommand(
cmd);
603 char cmd[NFRAME_LEN] = {0};
604 snprintf(
cmd, NFRAME_LEN,
"#:CO%03d#", 254 - speed + 1);
605 return sendCommand(
cmd);
608bool nFrameRotator::setMaxSpeed(uint8_t maxSpeed)
613 char cmd[NFRAME_LEN] = {0};
614 snprintf(
cmd, NFRAME_LEN,
":CS%03d#", 254 - maxSpeed + 1);
615 return sendCommand(
cmd);
620bool nFrameRotator::setSteppingPhase(uint8_t phase)
622 char cmd[NFRAME_LEN] = {0};
623 snprintf(
cmd, NFRAME_LEN,
"#:CW%01d#", phase);
624 return sendCommand(
cmd);
627bool nFrameRotator::setCoilStatus(uint8_t status)
629 char cmd[NFRAME_LEN] = {0};
630 snprintf(
cmd, NFRAME_LEN,
"#:CC%01d#", status == COIL_ENERGIZED_OFF ? 1 : 0);
631 LOGF_DEBUG(
"setCoil = %d hex=%x", status, status);
632 LOGF_DEBUG(
"setCoilS = %s CEOFF=%d CEON = %d",
cmd, COIL_ENERGIZED_OFF, COIL_ENERGIZED_ON);
633 return sendCommand(
cmd);
640 SteppingModeSP.
save(fp);
646double nFrameRotator::calculateAngle(uint32_t steps)
648 int diff = (
static_cast<int32_t
>(steps) - m_ZeroPosition) *
651 return range360((
float(diff) + 0.5) / SettingNP[PARAM_STEPS_DEGREE].getValue());
int setValue(const INDI::LilXmlElement &root, char *errmsg)
handle SetXXX commands from client
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.
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool load()
load Attempt to load property values from configuration file.
void save(FILE *f) const
save Save property to configuration file.
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)
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 SetCapability(uint32_t cap)
SetRotatorCapability sets the Rotator capabilities. All capabilities must be initialized.
INDI::PropertySwitch ReverseRotatorSP
INDI::PropertyNumber GotoRotatorNP
virtual bool initProperties() override
Initialize 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.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
INDI::PropertyNumber PresetNP
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the reverse direction property in the configuration file
virtual bool SyncRotator(double angle) override
SyncRotator Set current angle as the supplied angle without moving the rotator.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual IPState MoveRotator(double angle) override
MoveRotator Go to specific angle.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the reverse direction property in the configuration file
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool Handshake() override
perform handshake with device to check communication
INDI::PropertyNumber RotatorSpeedNP
bool SetRotatorSpeed(uint8_t speed)
const char * getDefaultName() override
virtual bool AbortRotator() override
AbortRotator Abort all motion.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
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
Initialize properties initial state and value. The child class must implement this function.
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
double range360(double r)
range360 Limits an angle to be between 0-360 degrees.
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.
#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,...)