33static std::unique_ptr<AskarWAF> askarWAF(
new AskarWAF());
48 FirmwareVersionTP[VERSION].
fill(
"VERSION",
"Firmware",
"Unknown");
49 FirmwareVersionTP[MODEL].
fill(
"MODEL",
"Model",
"Unknown");
97 if (!readMaxPosition()) {
102 if (!readPosition()) {
107 if (!readBacklash()) {
113 if (!readReverse()) {
118 lastPosition =
static_cast<uint32_t
>(
FocusAbsPosNP[0].getValue());
127 LOG_INFO(
"Askar-WAF parameters updated, focuser ready for use.");
129 LOG_ERROR(
"Failed to read one or more Askar-WAF parameters after "
139 char res[WAF_RES] = {0};
141 for (
int i = 0; i < 3; i++) {
142 if (sendCommand(
"FV#", res,
true)) {
143 char version[16] = {0};
144 if (sscanf(res,
"FV%15[^#]#", version) == 1) {
145 FirmwareVersionTP[VERSION].setText(version);
146 LOGF_INFO(
"Askar-WAF is online. Firmware version %s.", version);
148 char model[32] = {0};
149 if (sendCommand(
"FI#", res,
true) &&
150 sscanf(res,
"FI%31[^#]#", model) == 1)
151 FirmwareVersionTP[MODEL].setText(model);
160 LOG_ERROR(
"Error retrieving data from Askar-WAF, please ensure the focuser "
161 "is powered and the port is correct.");
167bool AskarWAF::sendCommand(
const char *
cmd,
char *res,
bool silent) {
168 int nbytes_written = 0, nbytes_read = 0, rc =
TTY_OK;
170 tcflush(
PortFD, TCIOFLUSH);
178 LOGF_ERROR(
"Serial write error: %s.", errstr);
182 if (res ==
nullptr) {
190 &nbytes_read)) !=
TTY_OK) {
199 res[nbytes_read] =
'\0';
203 if (strcmp(res,
"FE#") == 0) {
212bool AskarWAF::readPosition() {
213 char res[WAF_RES] = {0};
215 if (!sendCommand(
"Fp#", res))
219 if (sscanf(res,
"Fp%d#", &pos) != 1) {
220 LOGF_ERROR(
"Invalid position response <%s>.", res);
228bool AskarWAF::readMaxPosition() {
229 char res[WAF_RES] = {0};
231 if (!sendCommand(
"Fm#", res))
235 if (sscanf(res,
"Fm%d#", &maxStep) != 1) {
236 LOGF_ERROR(
"Invalid max travel response <%s>.", res);
262bool AskarWAF::readBacklash() {
263 char res[WAF_RES] = {0};
265 if (!sendCommand(
"Fb#", res))
268 int32_t backlash = 0;
269 if (sscanf(res,
"Fb%d#", &backlash) != 1) {
270 LOGF_ERROR(
"Invalid backlash response <%s>.", res);
283bool AskarWAF::readReverse() {
284 char res[WAF_RES] = {0};
286 if (!sendCommand(
"Fr#", res))
289 bool reversed = (strcmp(res,
"Fr1#") == 0);
298bool AskarWAF::isMoving(
bool *ok) {
299 char res[WAF_RES] = {0};
301 if (!sendCommand(
"FQ#", res)) {
307 if (strcmp(res,
"FQ1#") == 0) {
313 if (strcmp(res,
"FQ0#") == 0) {
319 LOGF_ERROR(
"Unknown isMoving response <%s>.", res);
326 char cmd[WAF_RES] = {0};
327 char res[WAF_RES] = {0};
328 snprintf(
cmd,
sizeof(
cmd),
"FP%u#", targetTicks);
330 if (!sendCommand(
cmd, res))
333 m_MotionQueryFailures = 0;
338 char cmd[WAF_RES] = {0};
339 char res[WAF_RES] = {0};
343 if (!sendCommand(
cmd, res))
346 m_MotionQueryFailures = 0;
351 char res[WAF_RES] = {0};
353 if (!sendCommand(
"FS#", res))
356 m_MotionQueryFailures = 0;
361 char cmd[WAF_RES] = {0};
362 char res[WAF_RES] = {0};
363 snprintf(
cmd,
sizeof(
cmd),
"FY%u#", ticks);
365 return sendCommand(
cmd, res);
369 char res[WAF_RES] = {0};
371 return sendCommand(enabled ?
"FR1#" :
"FR0#", res);
375 char cmd[WAF_RES] = {0};
376 char res[WAF_RES] = {0};
377 snprintf(
cmd,
sizeof(
cmd),
"FB%d#", steps);
379 return sendCommand(
cmd, res);
391 char cmd[WAF_RES] = {0};
392 char res[WAF_RES] = {0};
393 snprintf(
cmd,
sizeof(
cmd),
"FM%u#", ticks);
397 if (!sendCommand(
cmd, res))
408 const bool positionOk = readPosition();
410 if (
static_cast<uint32_t
>(
FocusAbsPosNP[0].getValue()) != lastPosition) {
412 lastPosition =
static_cast<uint32_t
>(
FocusAbsPosNP[0].getValue());
418 bool queryOk =
false;
419 const bool moving = isMoving(&queryOk);
422 if (++m_MotionQueryFailures >= WAF_MOTION_QUERY_MAX_FAILURES) {
427 m_MotionQueryFailures = 0;
428 LOG_ERROR(
"Lost contact with Askar-WAF while waiting for motion to "
432 m_MotionQueryFailures = 0;
435 if (!moving && positionOk) {
440 LOG_INFO(
"Focuser reached requested position.");
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
virtual bool Handshake() override
Handshake Try to communicate with the focuser and read its firmware version.
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
virtual bool SetFocuserBacklashEnabled(bool enabled) override
SetFocuserBacklashEnabled Enables or disables the focuser backlash compensation.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
const char * getDefaultName() override
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
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.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
INDI::PropertyNumber FocusRelPosNP
INDI::PropertySwitch FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusSyncNP
INDI::PropertyNumber FocusMaxPosNP
INDI::PropertySwitch FocusBacklashSP
INDI::PropertyNumber FocusBacklashNP
INDI::PropertyNumber FocusAbsPosNP
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,...
virtual void SyncPresets(uint32_t ticks)
Synchronizes the range (min, max, step) of the preset number properties (PresetNP) based on the focus...
Connection::Serial * serialConnection
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
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_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,...)