55 IUFillText(&InfoT[INFO_NAME],
"INFO_NAME",
"Name",
"NA");
56 IUFillText(&InfoT[INFO_VERSION],
"INFO_VERSION",
"Version",
"NA");
68 IUFillSwitch(&TemperatureCompensationS[TC_DISABLED],
"TC_DISABLED",
"Disabled",
ISS_ON);
79 IUFillNumber(&TemperatureSettingsN[TC_FACTOR],
"TC_FACTOR",
"Factor",
"%.2f", 0, 1, 0.1, 0);
80 IUFillNumber(&TemperatureSettingsN[TC_PERIOD],
"TC_PERIOD",
"Period (ms)",
"%.f", 10, 600000, 1000, 0);
81 IUFillNumber(&TemperatureSettingsN[TC_DELTA],
"TC_DELTA",
"Delta (C)",
"%.2f", 0, 10, 0.1, 0);
86 IUFillNumber(&TemperatureSensorN[TEMP_0],
"TEMP_0",
"Motor (C)",
"%.2f", -60, 60, 0, 0);
87 IUFillNumber(&TemperatureSensorN[TEMP_1],
"TEMP_1",
"Controller (C)",
"%.f", -60, 60, 0, 0);
88 IUFillNumber(&TemperatureSensorN[TEMP_AVG],
"TEMP_AVG",
"Average (C)",
"%.2f", -60, 60, 0, 0);
93 IUFillNumber(&StepperDriveN[CURRENT_MOVE],
"STEPPER_DRIVE_CURRENT_MOVE",
"Inverse Current Move",
"%.f", 0, 127, 1, 25);
94 IUFillNumber(&StepperDriveN[CURRENT_HOLD],
"STEPPER_DRIVE_CURRENT_HOLD",
"Inverse Current Hold",
"%.f", 0, 127, 1, 100);
96 &StepperDriveNP, StepperDriveN,
NARRAY(StepperDriveN),
149 if (!getParameter(
"VERSION", version))
152 LOGF_INFO(
"Detected version %s", version.c_str());
162 return "Baader SteelDriveII";
173 if (!strcmp(TemperatureCompensationSP.
name, name))
175 bool enabled = !strcmp(
IUFindOnSwitchName(states, names, n), TemperatureCompensationS[TC_ENABLED].name);
176 bool rc = setParameter(
"TCOMP", enabled ?
"1" :
"0");
181 TemperatureCompensationSP.
s =
IPS_OK;
182 LOGF_INFO(
"Temperature compensation is %s.", enabled ?
"enabled" :
"disabled");
194 if (!strcmp(TemperatureStateSP.
name, name))
196 bool active = !strcmp(
IUFindOnSwitchName(states, names, n), TemperatureStateS[TC_ACTIVE].name);
197 bool rc = setParameter(
"TCOMP_PAUSE", active ?
"0" :
"1");
203 LOGF_INFO(
"Temperature compensation is %s.", active ?
"active" :
"paused");
215 if (!strcmp(OperationSP.
name, name))
218 if (OperationS[OPERATION_RESET].s ==
ISS_ON)
221 if (m_ConfirmFactoryReset ==
false)
223 LOG_WARN(
"Click button again to confirm factory reset.");
230 m_ConfirmFactoryReset =
false;
231 if (!sendCommandOK(
"RESET"))
234 LOG_ERROR(
"Failed to reset to factory settings.");
241 if (OperationS[OPERATION_REBOOT].s ==
ISS_ON)
244 if (!sendCommand(
"REBOOT"))
258 if (OperationS[OPERATION_ZEROING].s ==
ISS_ON)
260 if (!sendCommandOK(
"SET USE_ENDSTOP:1"))
262 LOG_WARN(
"Failed to enable homing sensor magnet!");
265 if (!sendCommandOK(
"ZEROING"))
268 LOG_ERROR(
"Failed to zero to home position.");
274 LOG_INFO(
"Zeroing to home position in progress...");
294 if (!strcmp(TemperatureSettingsNP.
name, name))
296 double factor = TemperatureSettingsN[TC_FACTOR].value;
297 double period = TemperatureSettingsN[TC_PERIOD].value;
298 double delta = TemperatureSettingsN[TC_DELTA].value;
299 bool rc1 =
true, rc2 =
true, rc3 =
true;
302 if (factor != TemperatureSettingsN[TC_FACTOR].value)
303 rc1 = setParameter(
"TCOMP_FACTOR", to_string(factor));
304 if (period != TemperatureSettingsN[TC_PERIOD].value)
305 rc2 = setParameter(
"TCOMP_PERIOD", to_string(period));
306 if (delta != TemperatureSettingsN[TC_DELTA].value)
307 rc3 = setParameter(
"TCOMP_DELTA", to_string(delta));
314 if (!strcmp(StepperDriveNP.
name, name))
318 if (StepperDriveN[CURRENT_MOVE].value != values[CURRENT_MOVE])
320 if (setParameter(
"CURRENT_MOVE", to_string(values[CURRENT_MOVE], 0)))
321 StepperDriveN[CURRENT_MOVE].value = values[CURRENT_MOVE];
326 if (StepperDriveN[CURRENT_HOLD].value != values[CURRENT_HOLD])
328 if (setParameter(
"CURRENT_HOLD", to_string(values[CURRENT_HOLD], 0)))
329 StepperDriveN[CURRENT_HOLD].value = values[CURRENT_HOLD];
348 char cmd[DRIVER_LEN] = {0};
349 snprintf(
cmd, DRIVER_LEN,
"SET POS:%u", ticks);
350 return sendCommandOK(
cmd);
358 if (targetTicks < std::stoul(m_Summary[
LIMIT]))
360 char cmd[DRIVER_LEN] = {0};
361 snprintf(
cmd, DRIVER_LEN,
"GO %u", targetTicks);
362 if (!sendCommandOK(
cmd))
376 uint32_t limit = std::stoul(m_Summary[
LIMIT]);
380 int relative =
static_cast<int>(ticks);
381 int targetAbsPosition =
FocusAbsPosN[0].value + (relative * direction * reversed);
384 targetAbsPosition)));
441 else if (std::fabs(
FocusAbsPosN[0].value - summaryPosition) > 0)
453 double temp0 = std::stod(m_Summary[
TEMP0]);
454 double temp1 = std::stod(m_Summary[
TEMP1]);
455 double tempa = std::stod(m_Summary[
TEMPAVG]);
457 if (temp0 != TemperatureSensorN[TEMP_0].value ||
458 temp1 != TemperatureSensorN[TEMP_1].value ||
459 tempa != TemperatureSensorN[TEMP_AVG].value)
461 TemperatureSensorN[TEMP_0].value = temp0;
462 TemperatureSensorN[TEMP_1].value = temp1;
463 TemperatureSensorN[TEMP_AVG].value = tempa;
464 TemperatureSensorNP.
s =
IPS_OK;
476 return sendCommandOK(
"STOP");
484 char cmd[DRIVER_LEN] = {0};
485 snprintf(
cmd, DRIVER_LEN,
"SET LIMIT:%u", ticks);
486 return sendCommandOK(
cmd);
510 void SteelDriveII::getStartupValues()
514 if (getParameter(
"NAME", value))
517 if (getParameter(
"VERSION", value))
518 IUSaveText(&InfoT[INFO_VERSION], value.c_str());
520 if (getParameter(
"TCOMP", value))
522 TemperatureCompensationS[TC_ENABLED].s = (value ==
"1") ?
ISS_ON :
ISS_OFF;
523 TemperatureCompensationS[TC_DISABLED].s = (value ==
"1") ?
ISS_OFF :
ISS_ON;
526 if (getParameter(
"TCOMP_FACTOR", value))
528 TemperatureSettingsN[TC_FACTOR].value = std::stod(value);
531 if (getParameter(
"TCOMP_PERIOD", value))
533 TemperatureSettingsN[TC_PERIOD].value = std::stod(value);
536 if (getParameter(
"TCOMP_DELTA", value))
538 TemperatureSettingsN[TC_DELTA].value = std::stod(value);
541 if (getParameter(
"TCOMP_PAUSE", value))
548 if (getParameter(
"CURRENT_MOVE", value))
549 StepperDriveN[CURRENT_MOVE].value = std::stod(value);
553 if (getParameter(
"CURRENT_HOLD", value))
554 StepperDriveN[CURRENT_HOLD].value = std::stod(value);
563 TemperatureSensorN[TEMP_0].value = std::stod(m_Summary[
TEMP0]);
564 TemperatureSensorN[TEMP_1].value = std::stod(m_Summary[
TEMP1]);
565 TemperatureSensorN[TEMP_AVG].value = std::stod(m_Summary[
TEMPAVG]);
572 bool SteelDriveII::getSummary()
574 char res[DRIVER_LEN] = {0};
576 if (!sendCommand(
"SUMMARY", res))
579 std::vector<std::string> params = split(res,
";");
580 if (params.size() < 10)
583 for (
int i = 0; i < 10; i++)
585 std::vector<std::string>
value = split(params[i],
":");
586 m_Summary[
static_cast<Summary>(i)] = value[1];
589 if (m_Summary[
STATE] ==
"GOING_UP")
591 else if (m_Summary[
STATE] ==
"GOING_DOWN")
593 else if (m_Summary[
STATE] ==
"STOPPED")
595 else if (m_Summary[
STATE] ==
"ZEROED")
604 bool SteelDriveII::getParameter(
const std::string ¶meter, std::string &value)
606 char res[DRIVER_LEN] = {0};
608 std::string
cmd =
"GET " + parameter;
609 if (sendCommand(
cmd.c_str(), res) ==
false)
612 std::vector<std::string> values = split(res,
":");
613 if (values.size() != 2)
624 bool SteelDriveII::setParameter(
const std::string ¶meter,
const std::string &value)
626 std::string
cmd =
"SET " + parameter +
":" +
value;
627 return sendCommandOK(
cmd.c_str());
633 bool SteelDriveII::sendCommandOK(
const char *
cmd)
635 char res[DRIVER_LEN] = {0};
637 if (!sendCommand(
cmd, res))
640 return strstr(res,
"OK");
646 bool SteelDriveII::sendCommand(
const char *
cmd,
char * res,
int cmd_len,
int res_len)
648 int nbytes_written = 0, nbytes_read = 0, rc = -1;
650 tcflush(
PortFD, TCIOFLUSH);
654 char hex_cmd[DRIVER_LEN * 3] = {0};
655 hexDump(hex_cmd,
cmd, cmd_len);
663 char formatted_command[DRIVER_LEN] = {0};
664 snprintf(formatted_command, DRIVER_LEN,
"$BS %s\r\n",
cmd);
672 LOGF_ERROR(
"Serial write error: %s.", errstr);
679 char rawResponse[DRIVER_LEN * 2] = {0};
682 rc =
tty_read(
PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
701 char hex_res[DRIVER_LEN * 3] = {0};
702 hexDump(hex_res, res, res_len);
708 rawResponse[nbytes_read - 2] = 0;
710 strncpy(res, rawResponse + 4, DRIVER_LEN);
714 tcflush(
PortFD, TCIOFLUSH);
722 void SteelDriveII::hexDump(
char * buf,
const char * data,
int size)
724 for (
int i = 0; i < size; i++)
725 sprintf(buf + 3 * i,
"%02X ",
static_cast<uint8_t
>(data[i]));
728 buf[3 * size - 1] =
'\0';
734 std::vector<std::string> SteelDriveII::split(
const std::string &input,
const std::string ®ex)
737 std::regex re(regex);
738 std::sregex_token_iterator
739 first{input.begin(), input.end(), re, -1},
741 return {first, last};
747 template <
typename T>
748 std::string SteelDriveII::to_string(
const T a_value,
const int n)
750 std::ostringstream out;
752 out << std::fixed << a_value;
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.
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.
ISwitchVectorProperty FocusMotionSP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
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 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.
Connection::Serial * serialConnection
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
Reverse Focuser Motion.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual IPState MoveRelFocuser(FocusDirection dir, unsigned int ticks) override
virtual bool ReverseFocuser(bool enabled) override
Reverse Focuser Motion.
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
const char * getDefaultName() override
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
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 Handshake() override
perform handshake with device to check communication
virtual bool SyncFocuser(uint32_t ticks) override
Sync focuser.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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,...
#define NARRAY(a)
Handy macro to find the number of elements in array a[]. Must be used with actual array,...
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 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.
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
const char * IUFindOnSwitchName(ISState *states, char *names[], int n)
Returns the name of the first ON switch it finds in the supplied arguments.
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
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 IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text'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 LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
#define LOGF_ERROR(fmt,...)
@ value
the parser finished reading a JSON value
std::unique_ptr< SteelDrive > steelDrive(new SteelDrive())