35static std::unique_ptr<AvalonUPAS> upas(
new AvalonUPAS());
64 GearRatioNP[GEAR_AZ].
fill(
"GEAR_AZ",
"Azimuth (mm/arcmin)",
"%.4f", 0.001, 1000, 0.1, 1.0);
65 GearRatioNP[GEAR_ALT].
fill(
"GEAR_ALT",
"Altitude (mm/arcmin)",
"%.4f", 0.001, 1000, 0.1, 1.0);
69 FirmwareTP[0].
fill(
"VERSION",
"Version",
"Unknown");
109 GearRatioNP.
save(fp);
119 tcflush(PortFD, TCIOFLUSH);
122 const char softReset[2] = {
'\x18',
'\n'};
124 tty_write(PortFD, softReset, 1, &nbytes);
126 tcflush(PortFD, TCIOFLUSH);
129 char res[DRIVER_LEN] = {0};
130 if (!sendCommand(
"?", res))
133 if (strstr(res,
"MPos") ==
nullptr && strstr(res,
"WPos") ==
nullptr)
135 LOGF_ERROR(
"Unexpected handshake response: %s", res);
143 char ver[DRIVER_LEN] = {0};
144 if (sendCommand(
"$I", ver))
147 const char *tag = strstr(ver,
"[VER:");
151 char version[64] = {0};
152 sscanf(tag,
"[VER:%63[^]]]", version);
153 FirmwareTP[0].setText(version);
157 FirmwareTP[0].setText(ver);
161 LOG_INFO(
"UPAS connected and ready.");
170 char res[DRIVER_LEN] = {0};
171 if (sendCommand(
"?", res))
177bool AvalonUPAS::parseStatus(
const char *response)
181 const char *mposTag = strstr(response,
"MPos:");
182 if (mposTag ==
nullptr)
185 double azMM = 0.0, altMM = 0.0;
186 if (sscanf(mposTag + 5,
"%lf,%lf", &azMM, &altMM) < 2)
189 const double gearAZ = GearRatioNP[GEAR_AZ].getValue();
190 const double gearALT = GearRatioNP[GEAR_ALT].getValue();
196 bool wasMoving = m_IsMoving;
197 m_IsMoving = (strstr(response,
"Jog") !=
nullptr || strstr(response,
"Run") !=
nullptr);
216 const double mm = degrees * 60 * GearRatioNP[GEAR_AZ].getValue();
217 const double feedRate =
SpeedNP[0].getValue();
219 char cmd[DRIVER_LEN] = {0};
220 snprintf(
cmd, DRIVER_LEN,
"$J=G91G21X%.4f F%.0f", mm, feedRate);
222 char res[DRIVER_LEN] = {0};
223 if (!sendCommand(
cmd, res))
227 if (strncmp(res,
"ok", 2) != 0)
229 LOGF_ERROR(
"Unexpected AZ jog response: %s", res);
234 LOGF_INFO(
"AZ jog: %.4f deg → %.4f mm @ %.0f mm/min.", degrees, mm, feedRate);
241 const double mm = degrees * 60 *GearRatioNP[GEAR_ALT].getValue();
242 const double feedRate =
SpeedNP[0].getValue();
244 char cmd[DRIVER_LEN] = {0};
245 snprintf(
cmd, DRIVER_LEN,
"$J=G91G21Y%.4f F%.0f", mm, feedRate);
247 char res[DRIVER_LEN] = {0};
248 if (!sendCommand(
cmd, res))
251 if (strncmp(res,
"ok", 2) != 0)
253 LOGF_ERROR(
"Unexpected ALT jog response: %s", res);
258 LOGF_INFO(
"ALT jog: %.4f deg → %.4f mm @ %.0f mm/min.", degrees, mm, feedRate);
267 const double mmAZ = azDegrees * 60 * GearRatioNP[GEAR_AZ].getValue();
268 const double mmALT = altDegrees * 60 * GearRatioNP[GEAR_ALT].getValue();
269 const double feedRate =
SpeedNP[0].getValue();
271 char cmd[DRIVER_LEN] = {0};
272 snprintf(
cmd, DRIVER_LEN,
"$J=G91G21X%.4fY%.4f F%.0f", mmAZ, mmALT, feedRate);
274 char res[DRIVER_LEN] = {0};
275 if (!sendCommand(
cmd, res))
278 if (strncmp(res,
"ok", 2) != 0)
280 LOGF_ERROR(
"MoveBoth GRBL response: %s", res);
285 LOGF_INFO(
"MoveBoth: AZ %.4f° (%.4f mm), ALT %.4f° (%.4f mm) @ %.0f mm/min.",
286 azDegrees, mmAZ, altDegrees, mmALT, feedRate);
293 const char cancel =
'\x85';
295 int rc =
tty_write(PortFD, &cancel, 1, &nbytes);
300 LOGF_ERROR(
"AbortMotion serial write error: %s.", errstr);
313 LOGF_INFO(
"UPAS speed set to %u mm/min.", speed);
320 m_ReverseFlags |= 0x01;
322 m_ReverseFlags &= ~0x01;
324 char cmd[DRIVER_LEN] = {0};
325 snprintf(
cmd, DRIVER_LEN,
"$3=%d", m_ReverseFlags);
327 char res[DRIVER_LEN] = {0};
328 if (!sendCommand(
cmd, res))
331 LOGF_INFO(
"AZ reverse %s (flags=0x%02X).", enabled ?
"enabled" :
"disabled", m_ReverseFlags);
332 return (strncmp(res,
"ok", 2) == 0);
338 m_ReverseFlags |= 0x02;
340 m_ReverseFlags &= ~0x02;
342 char cmd[DRIVER_LEN] = {0};
343 snprintf(
cmd, DRIVER_LEN,
"$3=%d", m_ReverseFlags);
345 char res[DRIVER_LEN] = {0};
346 if (!sendCommand(
cmd, res))
349 LOGF_INFO(
"ALT reverse %s (flags=0x%02X).", enabled ?
"enabled" :
"disabled", m_ReverseFlags);
350 return (strncmp(res,
"ok", 2) == 0);
359 GearRatioNP.
update(values, names, n);
386bool AvalonUPAS::sendCommand(
const char *
cmd,
char *res,
int cmd_len,
int res_len)
388 int nbytes_written = 0, nbytes_read = 0, rc = -1;
390 tcflush(PortFD, TCIOFLUSH);
395 char hex_cmd[DRIVER_LEN * 3] = {0};
396 hexDump(hex_cmd,
cmd, cmd_len);
404 char formatted[DRIVER_LEN] = {0};
405 snprintf(formatted, DRIVER_LEN,
"%s\n",
cmd);
413 LOGF_ERROR(
"Serial write error: %s.", errstr);
421 rc =
tty_read(PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
423 rc =
tty_nread_section(PortFD, res, DRIVER_LEN, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read);
434 if (nbytes_read > 0 && (res[nbytes_read - 1] ==
'\n' || res[nbytes_read - 1] ==
'\r'))
435 res[nbytes_read - 1] =
'\0';
436 if (nbytes_read > 1 && (res[nbytes_read - 2] ==
'\r'))
437 res[nbytes_read - 2] =
'\0';
441 tcflush(PortFD, TCIOFLUSH);
445void AvalonUPAS::hexDump(
char *buf,
const char *data,
int size)
447 for (
int i = 0; i < size; i++)
448 sprintf(buf + 3 * i,
"%02X ",
static_cast<uint8_t
>(data[i]));
450 buf[3 * size - 1] =
'\0';
The AvalonUPAS class drives the Avalon Instruments Universal Polar Alignment System (UPAS) via its GR...
bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
bool AbortMotion() override
AbortMotion Abort all axis motion immediately.
IPState MoveAZ(double degrees) override
Move the azimuth axis by the given number of degrees.
IPState MoveBoth(double azDegrees, double altDegrees) override
MoveBoth Move both axes in a single coordinated operation.
bool ReverseAZ(bool enabled) override
ReverseAZ Reverse the direction of azimuth axis movement.
bool ReverseALT(bool enabled) override
ReverseALT Reverse the direction of altitude axis movement.
const char * getDefaultName() override
bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
IPState MoveALT(double degrees) override
MoveALT Move the altitude axis by the given number of degrees.
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
bool SetPACSpeed(uint16_t speed) override
SetPACSpeed Set the motor speed used for axis movements.
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the initial connection to the devic...
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
const char * getDeviceName() const
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
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)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
virtual bool initProperties()
Initialize properties initial state and value. The child class must implement this function.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
bool saveConfigItems(FILE *fp)
saveConfigItems Save PAC interface properties to config file. Call this from your driver's saveConfig...
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process PAC number properties.
INDI::PropertyNumber SpeedNP
void initProperties(const char *group)
initProperties Initialize PAC properties. Call this from your driver's initProperties().
void SetCapability(uint32_t cap)
SetCapability sets the PAC device capabilities. Call this in the driver constructor.
INDI::PropertyNumber PositionNP
INDI::PropertyNumber ManualAdjustmentNP
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process PAC switch properties.
bool updateProperties()
updateProperties Define or delete properties based on connection state. Call this from your driver's ...
@ POSITION_ALT
Current altitude position in degrees.
@ POSITION_AZ
Current azimuth position in degrees.
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
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)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
Provides interface to implement automated polar alignment correction (PAC).
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * INFO_TAB
INFO_TAB Where all the properties for general information are located.
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.
#define LOGF_INFO(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOGF_ERROR(fmt,...)