32static std::unique_ptr<IKunFocuser> ikunFocuser(
new IKunFocuser());
44 return "IKun Focuser";
58 applyMaximumPosition(816000);
60 AccelerationNP[0].
fill(
"ACCELERATION_VALUE",
"Steps/s²",
"%.f", 1, 10000, 10, 1000);
63 HoldSP[HOLD_ON].
fill(
"HOLD_ON",
"Enabled",
ISS_OFF);
64 HoldSP[HOLD_OFF].
fill(
"HOLD_OFF",
"Disabled",
ISS_ON);
67 TemperatureNP[0].
fill(
"TEMPERATURE",
"Celsius",
"%6.2f", -55, 125, 0, 20);
70 FirmwareTP[FIRMWARE_VERSION].
fill(
"VERSION",
"Firmware",
"Unknown");
71 FirmwareTP[CONTROLLER_MODEL].
fill(
"MODEL",
"Controller",
"Unknown");
100 AccelerationNP.
apply();
102 TemperatureNP.
apply();
104 LOG_INFO(
"IKunFocuser parameters updated; focuser is ready.");
108 LOG_WARN(
"Connected to IKunFocuser, but one or more startup values could not be read.");
128 tcflush(
PortFD, TCIOFLUSH);
131 char response[RESPONSE_SIZE] = { 0 };
132 if (!sendCommand(
"#", response,
sizeof(response),
true) ||
135 LOG_ERROR(
"IKunFocuser identification failed. Check the selected port, power, and firmware.");
139 char identity[128] = { 0 };
140 std::snprintf(identity,
sizeof(identity),
"%s", response);
142 if (!sendCommand(
"V#", response,
sizeof(response),
true) ||
145 LOG_ERROR(
"IKunFocuser firmware version query failed.");
149 char versionText[16] = { 0 };
150 std::snprintf(versionText,
sizeof(versionText),
"%d", m_FirmwareVersion);
151 FirmwareTP[FIRMWARE_VERSION].setText(versionText);
156 LOGF_ERROR(
"Firmware %d is outside the supported release range. Upgrade the IKunFocuser firmware.",
161 LOGF_INFO(
"Connected to %s, firmware %d.", identity, m_FirmwareVersion);
165bool IKunFocuser::sendCommand(
const char *command,
char *response, std::size_t responseSize,
bool silent)
167 if (response ==
nullptr || responseSize < 2)
171 tcflush(
PortFD, TCIFLUSH);
175 int bytesWritten = 0;
181 char errorMessage[
MAXRBUF] = { 0 };
183 LOGF_ERROR(
"IKunFocuser write failed: %s.", errorMessage);
190 IO_TIMEOUT_SECONDS, &bytesRead);
195 char errorMessage[
MAXRBUF] = { 0 };
197 LOGF_ERROR(
"IKunFocuser read failed: %s.", errorMessage);
202 response[bytesRead] =
'\0';
208 LOGF_ERROR(
"IKunFocuser rejected command <%s> with response <%s>.", command, response);
217 char response[RESPONSE_SIZE] = { 0 };
218 if (!sendCommand(
"G#", response,
sizeof(response), silent))
224 LOGF_ERROR(
"Invalid IKunFocuser status response <%s>.", response);
231void IKunFocuser::applyMaximumPosition(uint32_t maximum)
241 FocusSyncNP[0].setStep(std::max(1.0, maximum / 50.0));
253bool IKunFocuser::readFullState()
255 char response[RESPONSE_SIZE] = { 0 };
256 if (!sendCommand(
"I#", response,
sizeof(response)))
259 const std::string
json(response);
260 bool foundAny =
false;
261 int64_t integerValue = 0;
262 double numberValue = 0;
263 bool booleanValue =
false;
266 integerValue >= 100 && integerValue <= 9999999)
268 applyMaximumPosition(
static_cast<uint32_t
>(integerValue));
275 m_LastPosition =
static_cast<uint32_t
>(integerValue);
280 integerValue >= 1 && integerValue <= 10000)
282 AccelerationNP[0].setValue(integerValue);
303 numberValue >= -55 && numberValue <= 125)
305 TemperatureNP[0].setValue(numberValue);
320 const auto position =
static_cast<uint32_t
>(status.
position);
321 if (position != m_LastPosition)
325 m_LastPosition = position;
344 LOG_INFO(
"IKunFocuser reached the requested position.");
351 char command[64] = { 0 };
352 char response[RESPONSE_SIZE] = { 0 };
353 std::snprintf(command,
sizeof(command),
"M %u#", targetTicks);
355 if (!sendCommand(command, response,
sizeof(response)))
362 m_CommunicationFailures = 0;
368 const uint32_t current =
static_cast<uint32_t
>(
FocusAbsPosNP[0].getValue());
369 const uint32_t maximum =
static_cast<uint32_t
>(
FocusMaxPosNP[0].getValue());
370 uint32_t target = current;
373 target = ticks > current ? 0 : current - ticks;
375 target = ticks > maximum - current ? maximum : current + ticks;
382 char response[RESPONSE_SIZE] = { 0 };
383 return sendCommand(
"S#", response,
sizeof(response));
388 char command[64] = { 0 };
389 char response[RESPONSE_SIZE] = { 0 };
390 std::snprintf(command,
sizeof(command),
"P %u#", ticks);
391 return sendCommand(command, response,
sizeof(response));
396 char response[RESPONSE_SIZE] = { 0 };
397 return sendCommand(enabled ?
"R 1#" :
"R 0#", response,
sizeof(response));
402 char command[64] = { 0 };
403 char response[RESPONSE_SIZE] = { 0 };
404 std::snprintf(command,
sizeof(command),
"D %u#", ticks);
405 if (!sendCommand(command, response,
sizeof(response)))
408 applyMaximumPosition(ticks);
414 char command[64] = { 0 };
415 char response[RESPONSE_SIZE] = { 0 };
416 std::snprintf(command,
sizeof(command),
"X %d#", speed);
417 return sendCommand(command, response,
sizeof(response));
420bool IKunFocuser::setAcceleration(uint32_t acceleration)
422 char command[64] = { 0 };
423 char response[RESPONSE_SIZE] = { 0 };
424 std::snprintf(command,
sizeof(command),
"A %u#", acceleration);
425 return sendCommand(command, response,
sizeof(response));
428bool IKunFocuser::setHold(
bool enabled)
430 char response[RESPONSE_SIZE] = { 0 };
431 return sendCommand(enabled ?
"C 1#" :
"C 0#", response, sizeof(response));
438 const double previous = AccelerationNP[0].getValue();
439 AccelerationNP.
update(values, names, n);
440 const auto requested =
static_cast<uint32_t
>(AccelerationNP[0].getValue());
446 AccelerationNP[0].setValue(previous);
450 AccelerationNP.
apply();
462 HoldSP.
update(states, names, n);
481void IKunFocuser::markMotionAlert()
498 if (readMotionStatus(status,
true))
500 m_CommunicationFailures = 0;
501 applyMotionStatus(status);
503 else if (++m_CommunicationFailures >= MAX_COMMUNICATION_FAILURES)
506 m_CommunicationFailures = 0;
507 LOG_ERROR(
"Lost communication with IKunFocuser while polling status.");
510 if (++m_TemperaturePollCounter >= 10)
512 m_TemperaturePollCounter = 0;
514 const double previousAcceleration = AccelerationNP[0].getValue();
515 const double previousTemperature = TemperatureNP[0].getValue();
524 if (AccelerationNP[0].getValue() != previousAcceleration)
525 AccelerationNP.
apply();
526 if (TemperatureNP[0].getValue() != previousTemperature ||
527 TemperatureNP.
getState() != previousTemperatureState)
528 TemperatureNP.
apply();
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
void setDefaultHost(const char *addressHost)
void setDefaultPort(uint32_t addressPort)
const char * getDefaultName() override
IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
bool AbortFocuser() override
AbortFocuser all focus motion.
IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
bool SetFocuserSpeed(int speed) override
SetFocuserSpeed Set Focuser speed.
bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
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.
Connection::Interface * getActiveConnection()
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
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::PropertyNumber FocusAbsPosNP
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
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,...
Connection::TCP * tcpConnection
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
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 setSupportedConnections(const uint8_t &value)
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
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 fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
a class to store JSON values
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,...)
bool parseJsonBoolean(const std::string &json, const std::string &key, bool &value)
const char * modelForVersion(int version)
bool isSupportedIdentity(const std::string &response)
bool isErrorResponse(const std::string &response)
bool isSupportedVersion(int version)
bool parseJsonNumber(const std::string &json, const std::string &key, double &value)
bool parseMotionStatus(const std::string &response, MotionStatus &status)
bool parseVersion(const std::string &response, int &version)
bool parseJsonInteger(const std::string &json, const std::string &key, int64_t &value)