33static std::unique_ptr<AllunaTCS2> allunaTCS2(
new AllunaTCS2 ());
60 TemperatureNP[0].
fill(
"TEMPERATURE",
"Focuser Temp [C]",
"%6.2f", -100, 100, 0, 0);
61 TemperatureNP[1].
fill(
"TEMPERATURE_PRIMARY",
"Primary Temp [C]",
"%6.2f", -100, 100, 0, 0);
62 TemperatureNP[2].
fill(
"TEMPERATURE_SECONDARY",
"Secondary Temp [C]",
"%6.2f", -100, 100, 0, 0);
63 TemperatureNP[3].
fill(
"HUMIDITY",
"Humidity [%]",
"%6.2f", 0, 100, 0, 0);
67 ClimateControlSP[AUTO].
fill(
"CLIMATE_AUTO",
"On",
ISS_OFF);
68 ClimateControlSP[MANUAL].
fill(
"CLIMATE_MANUAL",
"Off",
ISS_ON);
71 PrimaryDewHeaterSP[ON].
fill(
"PRIMARY_HEATER_ON",
"On",
ISS_OFF);
72 PrimaryDewHeaterSP[OFF].
fill(
"PRIMARY_HEATER_OFF",
"Off",
ISS_ON);
75 SecondaryDewHeaterSP[ON].
fill(
"SECONDARY_HEATER_ON",
"On",
ISS_OFF);
76 SecondaryDewHeaterSP[OFF].
fill(
"SECONDARY_HEATER_OFF",
"Off",
ISS_ON);
80 FanPowerNP[0].
fill(
"FANPOWER",
"Fan power [130..255]",
"%3.0f", 130, 255, 1, 255);
84 SteppingModeSP[SPEED].
fill(
"STEPPING_SPEED",
"SpeedStep",
ISS_ON);
85 SteppingModeSP[MICRO].
fill(
"STEPPING_MICRO",
"MicroStep",
ISS_OFF);
91 FocusAbsPosNP[0].setMax((steppingMode == MICRO) ? 22400 : 1400);
114 return "Alluna TCS2";
124 if (sendCommand(
"Connect 1\n"))
130 LOG_ERROR(
"Cannot turn on Connected-LED");
179 char cmd[DRIVER_LEN] =
"HandShake\n", res[DRIVER_LEN] = {0};
182 bool rc = sendCommand(
cmd, res, 0, 2);
187 return res[0] ==
'\r' && res[1] ==
'\n';
190bool AllunaTCS2::sendCommand(
const char *
cmd,
char * res,
int cmd_len,
int res_len)
196 result = sendCommandNoLock(
cmd, res, cmd_len, res_len);
202 LOG_INFO(
"sendCommand: lock failed, abort");
208bool AllunaTCS2::sendCommandNoLock(
const char *
cmd,
char * res,
int cmd_len,
int res_len)
210 int nbytes_written = 0, nbytes_read = 0, rc = -1;
213 tcflush(
PortFD, TCIOFLUSH);
217 char hex_cmd[DRIVER_LEN * 3] = {0};
218 hexDump(hex_cmd,
cmd, cmd_len);
232 LOGF_ERROR(
"Serial write error: %s.", errstr);
241 LOG_DEBUG(
"sendCommand: Read Answer Bytes");
242 rc =
tty_read(
PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
246 LOG_DEBUG(
"sendCommand: Read Answer String");
254 LOGF_ERROR(
"203 Serial read error: %s.", errstr);
260 char hex_res[DRIVER_LEN * 3] = {0};
261 hexDump(hex_res, res, res_len);
269 tcflush(
PortFD, TCIOFLUSH);
274bool AllunaTCS2::sendCommandOnly(
const char *
cmd,
int cmd_len)
276 int nbytes_written = 0, rc = -1;
278 if (! tcs.try_lock() )
280 LOGF_INFO(
"sendCommandOnly: %s: lock failed, abort",
cmd);
284 tcflush(
PortFD, TCIOFLUSH);
288 char hex_cmd[DRIVER_LEN * 3] = {0};
289 hexDump(hex_cmd,
cmd, cmd_len);
303 LOGF_ERROR(
"Serial write error: %s.", errstr);
312bool AllunaTCS2::receiveNext(
char * res,
int res_len)
314 int nbytes_read = 0, rc = -1;
318 rc =
tty_read(
PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
326 LOGF_ERROR(
"285 Serial read error: %s.", errstr);
333 char hex_res[DRIVER_LEN * 3] = {0};
334 hexDump(hex_res, res, res_len);
346void AllunaTCS2::receiveDone()
349 tcflush(
PortFD, TCIOFLUSH);
353void AllunaTCS2::hexDump(
char * buf,
const char * data,
int size)
355 for (
int i = 0; i < size; i++)
356 sprintf(buf + 3 * i,
"%02X ",
static_cast<uint8_t
>(data[i]));
359 buf[3 * size - 1] =
'\0';
370 if (!strcmp(name,
"CONNECTION") && !strcmp(names[0],
"DISCONNECT") && states[0] ==
ISS_ON)
373 if (sendCommand(
"Connect 0\n"))
376 LOG_ERROR(
"Cannot turn off Connected-LED");
381 SteppingModeSP.
update(states, names, n);
383 SteppingModeSP.
apply();
386 setStepping((SteppingModeSP[SPEED].s ==
ISS_ON) ? SPEED : MICRO);
388 FocusAbsPosNP[0].setMax((steppingMode == MICRO) ? 22400 : 1400);
396 LOGF_INFO(
"Setting new max position to %d", (steppingMode == MICRO) ? 22400 : 1400 );
413 if (ClimateControlSP[currentClimateControlIndex].isNameMatch(actionName))
417 ClimateControlSP.
apply();
422 ClimateControlSP.
update(states, names, n);
424 if ( setClimateControl((currentClimateControlIndex == AUTO) ? MANUAL : AUTO) )
428 ClimateControlSP.
apply();
435 ClimateControlSP.
apply();
446 if (PrimaryDewHeaterSP[currentPrimaryDewHeaterIndex].isNameMatch(actionName))
450 PrimaryDewHeaterSP.
apply();
455 PrimaryDewHeaterSP.
update(states, names, n);
457 if ( setPrimaryDewHeater((currentPrimaryDewHeaterIndex == OFF) ? ON : OFF) )
461 PrimaryDewHeaterSP.
apply();
468 PrimaryDewHeaterSP.
apply();
479 if (SecondaryDewHeaterSP[currentSecondaryDewHeaterIndex].isNameMatch(actionName))
482 SecondaryDewHeaterSP[currentSecondaryDewHeaterIndex].label);
484 SecondaryDewHeaterSP.
apply();
489 SecondaryDewHeaterSP.
update(states, names, n);
491 if ( setSecondaryDewHeater((currentSecondaryDewHeaterIndex == OFF) ? ON : OFF) )
494 SecondaryDewHeaterSP[currentSecondaryDewHeaterIndex].label);
496 SecondaryDewHeaterSP.
apply();
503 SecondaryDewHeaterSP.
apply();
522 int power = values[0];
523 if (power > 255) power = 255;
524 if (power < 0) power = 0;
525 if (setFanPower(power))
527 FanPowerNP.
update(values, names, n);
545 char cmd[DRIVER_LEN];
546 snprintf(
cmd, DRIVER_LEN,
"FocuserGoTo %d\r\n", targetTicks);
547 bool rc = sendCommandOnly(
cmd);
550 LOGF_ERROR(
"MoveAbsFocuser %d failed", targetTicks);
553 isFocuserMoving =
true;
560 m_TargetDiff = ticks * ((dir ==
FOCUS_INWARD) ? -1 : 1);
566 return sendCommand(
"FocuserStop\n");
575 if (getTemperature() && getFanPower())
582 bool actionInProgress = isFocuserMoving || isCoverMoving;
584 char res[DRIVER_LEN] = {0};
587 while (actionInProgress && receiveNext(res))
596 LOG_INFO(
"Primary heater switched ON");
599 LOG_INFO(
"Primary heater switched OFF");
602 LOG_INFO(
"Secondary heater switched ON");
605 LOG_INFO(
"Secondary heater switched OFF");
608 LOG_INFO(
"Climate Control switched ON");
611 LOG_INFO(
"Climate Control switched OFF");
637 sscanf(res,
"K#%d", &pos);
648 LOG_DEBUG(
"TimerHit: starting to focus");
652 isFocuserMoving =
false;
662 isCoverMoving =
false;
669 LOGF_DEBUG(
"TimerHit: unexpected response (%s)", res);
674 LOGF_DEBUG(
"TimerHit: unexpected response (%s)", res);
676 actionInProgress = isFocuserMoving || isCoverMoving;
701bool AllunaTCS2::isMoving()
703 return isFocuserMoving;
706bool AllunaTCS2::getTemperature()
709 static std::chrono::system_clock::time_point last_temp_update = std::chrono::system_clock::now();
710 static bool first_run =
true;
718 std::chrono::duration<double> seconds = std::chrono::system_clock::now() - last_temp_update;
719 if ( !first_run && seconds.count() < 10 )
731 else if ( sendCommandOnly(
"GetTemperatures\n") )
734 isGetTemperature =
true;
737 char res[DRIVER_LEN] = {0};
741 while (isGetTemperature && receiveNext(res))
746 sscanf(res,
"R#%f", &value);
747 TemperatureNP[0].value = value;
750 sscanf(res,
"S#%f", &value);
751 TemperatureNP[1].value = value;
754 sscanf(res,
"T#%f", &value);
755 TemperatureNP[2].value = value;
758 sscanf(res,
"d#%f", &value);
759 TemperatureNP[3].value = value;
761 isGetTemperature =
false;
763 TemperatureNP.
apply();
766 LOGF_ERROR(
"GetTemperatures: unexpected response (%s)", res);
770 last_temp_update = std::chrono::system_clock::now();
776bool AllunaTCS2::getPosition()
778 char res[DRIVER_LEN] = {0};
780 if (sendCommand(
"GetFocuserPosition\n", res, 0) ==
false)
784 sscanf(res,
"%d", &pos);
797bool AllunaTCS2::getDustCover()
799 char res[DRIVER_LEN] = {0};
801 if (sendCommand(
"GetDustCover\n", res, 0) ==
false)
805 sscanf(res,
"%d", &value);
810 LOGF_DEBUG(
"Cover status read to be %s (%d)", (value == 1) ?
"open" :
"closed", value);
826 isCoverMoving =
true;
846 isCoverMoving =
true;
859bool AllunaTCS2::getStepping()
861 char res[DRIVER_LEN] = {0};
863 if (sendCommand(
"GetFocuserMode\n", res) ==
false)
867 sscanf(res,
"%d", &mode);
873 steppingMode = (mode == 0) ? SPEED : MICRO;
879 FocusAbsPosNP[0].setMax((steppingMode == MICRO) ? 22400 : 1400);
884bool AllunaTCS2::setStepping(SteppingMode mode)
887 char cmd[DRIVER_LEN] = {0};
889 value = (mode == SPEED) ? 0 : 1;
890 LOGF_DEBUG(
"Setting stepping mode to: %s", (mode == SPEED) ?
"SPEED" :
"micro");
891 LOGF_DEBUG(
"Setting stepping mode to: %d", value);
892 snprintf(
cmd, DRIVER_LEN,
"SetFocuserMode %d\n", value);
893 return sendCommand(
cmd);
896bool AllunaTCS2::setDustCover()
898 char cmd[DRIVER_LEN] = {0};
899 snprintf(
cmd, DRIVER_LEN,
"SetDustCover\n");
900 return sendCommandOnly(
cmd);
903bool AllunaTCS2::getClimateControl()
905 char res[DRIVER_LEN] = {0};
907 if (sendCommand(
"GetClimateControl\n", res, 0) ==
false)
911 sscanf(res,
"%d", &value);
925bool AllunaTCS2::setClimateControl(ClimateControlMode mode)
927 char cmd[DRIVER_LEN] = {0};
929 value = (mode == AUTO) ? 1 : 0;
930 snprintf(
cmd, DRIVER_LEN,
"SetClimateControl %d\n", value);
931 return sendCommand(
cmd);
934bool AllunaTCS2::getPrimaryDewHeater()
936 char res[DRIVER_LEN] = {0};
938 if (sendCommand(
"GetAux1\n", res, 0) ==
false)
942 sscanf(res,
"%d", &value);
955bool AllunaTCS2::setPrimaryDewHeater(DewHeaterMode mode)
957 char cmd[DRIVER_LEN] = {0};
959 value = (mode == ON) ? 1 : 0;
960 snprintf(
cmd, DRIVER_LEN,
"SetAux1 %d\n", value);
961 return sendCommand(
cmd);
964bool AllunaTCS2::getSecondaryDewHeater()
966 char res[DRIVER_LEN] = {0};
968 if (sendCommand(
"GetAux2\n", res, 0) ==
false)
972 sscanf(res,
"%d", &value);
985bool AllunaTCS2::setSecondaryDewHeater(DewHeaterMode mode)
987 char cmd[DRIVER_LEN] = {0};
989 value = (mode == ON) ? 1 : 0;
990 snprintf(
cmd, DRIVER_LEN,
"SetAux2 %d\n", value);
991 return sendCommand(
cmd);
994bool AllunaTCS2::getFanPower()
997 static std::chrono::system_clock::time_point last_temp_update = std::chrono::system_clock::now();
998 static bool first_run =
true;
1000 char res[DRIVER_LEN] = {0};
1002 std::chrono::duration<double> seconds = std::chrono::system_clock::now() - last_temp_update;
1003 if ( !first_run && seconds.count() < 30 )
1015 if (sendCommand(
"GetFanPower\n", res, 0) ==
false)
1019 sscanf(res,
"%d", &value);
1024 if (value != (
int)FanPowerNP[0].value)
1027 FanPowerNP[0].value = (double)value;
1034bool AllunaTCS2::setFanPower(
int value)
1036 char cmd[DRIVER_LEN] = {0};
1037 snprintf(
cmd, DRIVER_LEN,
"SetFanPower %d\n", value);
1038 return sendCommand(
cmd);
virtual IPState UnParkCap() override
unPark dust cap (open cover). Must be implemented by child.
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...
const char * getDefaultName() override
bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
virtual IPState ParkCap() override
Park dust cap (close cover). Must be implemented by child.
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...
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
bool AbortFocuser() override
AbortFocuser all focus motion.
bool saveConfigItems(FILE *fp) override
bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Provides interface to implement remotely controlled dust cover.
void addPollPeriodControl()
Add Polling period control to the driver.
void addConfigurationControl()
Add Configuration control to the driver.
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)
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::PropertySwitch ParkCapSP
bool updateProperties()
updateProperties Defines or Delete properties based on default device connection status
void initProperties(const char *group, uint32_t capabilities=0)
Initialize dust cap properties. It is recommended to call this function within initProperties() of yo...
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process dust cap switch properties.
INDI::PropertyNumber FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
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 saveConfigItems(FILE *fp) override
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 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...
void setSupportedConnections(const uint8_t &value)
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool isNameMatch(const char *otherName) const
void setPermission(IPerm permission)
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)
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device 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.
const char * IUFindOnSwitchName(ISState *states, char *names[], int n)
Returns the name of the first ON switch it finds in the supplied arguments.
#define LOGF_INFO(fmt,...)
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
#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,...)
#define DEBUGF(priority, msg,...)