34 #include <sys/ioctl.h>
58 IUFillText(&InfoT[INFO_VERSION],
"INFO_VERSION",
"Version",
"NA");
62 IUFillNumber(&TemperatureN[TEMPERATURE_PRIMARY],
"TEMPERATURE_PRIMARY",
"Primary (c)",
"%.2f", -50, 70., 0., 0.);
63 IUFillNumber(&TemperatureN[TEMPERATURE_AMBIENT],
"TEMPERATURE_AMBIENT",
"Ambient (c)",
"%.2f", -50, 70., 0., 0.);
70 IUFillSwitchVector(&FanStateSP, FanStateS, 2,
getDeviceName(),
"FOCUS_FAN",
"Fans", FAN_TAB,
IP_RW,
ISR_1OFMANY, 0,
75 IUFillSwitch(&FanControlS[FAN_AUTOMATIC_ABSOLUTE],
"FAN_AUTOMATIC_ABSOLUTE",
"Auto. Absolute",
ISS_OFF);
76 IUFillSwitch(&FanControlS[FAN_AUTOMATIC_RELATIVE],
"FAN_AUTOMATIC_RELATIVE",
"Auto. Relative",
ISS_OFF);
81 IUFillNumber(&FanControlN[FAN_MAX_ABSOLUTE],
"FAN_MAX_ABSOLUTE",
"Max Primary (c)",
"%.2f", 0, 50., 5., 25.);
82 IUFillNumber(&FanControlN[FAN_MAX_RELATIVE],
"FAN_MAX_RELATIVE",
"Max Relative (c)",
"%.2f", 0., 30., 1., 2.5);
83 IUFillNumber(&FanControlN[FAN_DEADZONE],
"FAN_DEADZONE",
"Deadzone (c)",
"%.2f", 0.1, 10, 0.5, 0.5);
88 IUFillSwitch(&FanDisconnectS[FAN_OFF_ON_DISCONNECT],
"FAN_OFF_ON_DISCONNECT",
"Switch Off",
ISS_ON);
94 IUFillSwitch(&CalibrationStateS[CALIBRATION_OFF],
"CALIBRATION_OFF",
"Not Calibrated",
ISS_ON);
117 int bits = TIOCM_RTS;
118 (void) ioctl(
PortFD, TIOCMBIC, &bits);
166 if (FanDisconnectS[FAN_OFF_ON_DISCONNECT].s ==
ISS_ON)
167 setFanEnabled(
false);
179 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 6;
186 cmd[5] = calculateCheckSum(
cmd, len);
188 if (!validateLengths(
cmd, len))
191 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
195 IUSaveText(&InfoT[INFO_VERSION], version.c_str());
197 LOGF_INFO(
"Detected version %s", version.c_str());
207 return "PlaneWave EFA";
218 if (!strcmp(CalibrationStateSP.
name, name))
220 bool enabled = strcmp(CalibrationStateS[CALIBRATION_ON].name,
IUFindOnSwitchName(states, names, n)) == 0;
221 if (setCalibrationEnabled(enabled))
235 else if (!strcmp(FanStateSP.
name, name))
237 if (FanControlS[FAN_MANUAL].s ==
ISS_OFF)
240 LOG_WARN(
"Cannot control fan while manual control is turned off.");
245 bool enabled = strcmp(FanStateS[FAN_ON].name,
IUFindOnSwitchName(states, names, n)) == 0;
246 if (setFanEnabled(enabled))
260 else if (!strcmp(FanControlSP.
name, name))
263 if (FanControlS[FAN_MANUAL].s ==
ISS_ON)
266 LOG_INFO(
"Fan is now controlled manually.");
270 LOG_INFO(
"Fan is now controlled automatically per the control parameters.");
279 else if (!strcmp(FanDisconnectSP.
name, name))
283 if (FanDisconnectS[FAN_OFF_ON_DISCONNECT].s ==
ISS_ON)
284 LOG_INFO(
"Fan shall be turned off upon device disconnection.");
286 LOG_INFO(
"Fan shall left as-is upon device disconnection.");
300 bool EFA::ISNewNumber(
const char *dev,
const char *name,
double values[],
char *names[],
int n)
305 if (!strcmp(FanControlNP.
name, name))
322 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 9;
329 cmd[5] = (ticks >> 16) & 0xFF;
330 cmd[6] = (ticks >> 8) & 0xFF;
331 cmd[7] = (ticks >> 0) & 0xFF;
332 cmd[8] = calculateCheckSum(
cmd, len);
334 if (!validateLengths(
cmd, len))
337 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
340 return (res[5] == 1);
348 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 9;
355 cmd[5] = (targetTicks >> 16) & 0xFF;
356 cmd[6] = (targetTicks >> 8) & 0xFF;
357 cmd[7] = (targetTicks >> 0) & 0xFF;
358 cmd[8] = calculateCheckSum(
cmd, len);
360 if (!validateLengths(
cmd, len))
363 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
376 int relative =
static_cast<int>(ticks);
377 int targetAbsPosition =
FocusAbsPosN[0].value + (relative * direction * reversed);
397 if (readTemperature())
400 bool aboveThreshold =
false;
401 for (
int i = 0; i < TemperatureNP.
nnp; i++)
403 if (std::fabs(TemperatureN[i].value - m_LastTemperature[i]) > TEMPERATURE_THRESHOLD)
405 aboveThreshold =
true;
406 m_LastTemperature[i] = TemperatureN[i].value;
414 if (FanControlS[FAN_MANUAL].s ==
ISS_OFF)
416 bool turnOn =
false, turnOff =
false;
417 const bool isFanOn = FanStateS[FAN_ON].s ==
ISS_ON;
420 if (FanControlS[FAN_AUTOMATIC_ABSOLUTE].s ==
ISS_ON)
423 double min_delta = FanControlN[FAN_MAX_ABSOLUTE].value - FanControlN[FAN_DEADZONE].value;
424 double max_delta = FanControlN[FAN_MAX_ABSOLUTE].value + FanControlN[FAN_DEADZONE].value;
426 turnOn = TemperatureN[TEMPERATURE_PRIMARY].value > max_delta;
427 turnOff = TemperatureN[TEMPERATURE_PRIMARY].value < min_delta;
429 else if (FanControlS[FAN_AUTOMATIC_RELATIVE].s ==
ISS_ON)
432 double tDiff = TemperatureN[TEMPERATURE_PRIMARY].value - TemperatureN[TEMPERATURE_AMBIENT].value;
434 double min_delta = FanControlN[FAN_MAX_RELATIVE].value - FanControlN[FAN_DEADZONE].value;
435 double max_delta = FanControlN[FAN_MAX_RELATIVE].value + FanControlN[FAN_DEADZONE].value;
438 turnOn = tDiff > max_delta;
439 turnOff = tDiff < min_delta;
442 if (isFanOn && turnOff)
444 setFanEnabled(
false);
446 FanStateS[FAN_OFF].s =
ISS_ON;
450 else if (!isFanOn && turnOn)
453 FanStateS[FAN_ON].s =
ISS_ON;
454 FanStateS[FAN_OFF].s =
ISS_OFF;
463 if (isGOTOComplete())
469 LOG_INFO(
"Focuser reached requested position.");
474 else if (std::fabs(
FocusAbsPosN[0].value - m_LastPosition) > 0)
499 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 9;
506 cmd[5] = (ticks >> 16) & 0xFF;
507 cmd[6] = (ticks >> 8) & 0xFF;
508 cmd[7] = (ticks >> 0) & 0xFF;
509 cmd[8] = calculateCheckSum(
cmd, len);
511 if (!validateLengths(
cmd, len))
514 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
517 return (res[5] == 1);
546 void EFA::getStartupValues()
549 readCalibrationState();
553 if (readMaxSlewLimit())
574 inline int EFA::readByte(
int fd, uint8_t *buf,
int timeout,
int *nbytes_read)
576 return tty_read(
fd, (
char *)buf, 1, timeout, nbytes_read);
582 inline int EFA::readBytes(
int fd, uint8_t *buf,
int nbytes,
int timeout,
int *nbytes_read)
584 return tty_read(
fd, (
char *)buf, nbytes, timeout, nbytes_read);
590 inline int EFA::writeBytes(
int fd,
const uint8_t *buf,
int nbytes,
int *nbytes_written)
592 return tty_write(
fd, (
const char *)buf, nbytes, nbytes_written);
598 int EFA::readPacket(
int fd, uint8_t *buf,
int nbytes,
int timeout,
int *nbytes_read)
600 int len = 0, rc = 0, read_bytes = *nbytes_read = 0;
604 LOGF_ERROR(
"Read needs at least 6 bytes; exceeds supplied buffer size (%d)", nbytes);
608 for (
int i = 0; i < 10; i++)
611 rc = readByte(
fd, &buf[0], timeout, &read_bytes);
612 if (rc ==
TTY_OK && read_bytes == 1)
614 if (buf[0] == DRIVER_SOM)
620 LOGF_DEBUG(
"Looking for SOM (%02X); found %d byte (%02X)", DRIVER_SOM, read_bytes, buf[0]);
627 LOGF_DEBUG(
"Looking for SOM (%02X); found %s", DRIVER_SOM, errstr);
630 if (rc !=
TTY_OK || read_bytes != 1 || buf[0] != DRIVER_SOM)
638 if ((rc = readByte(
fd, &buf[1], timeout, &read_bytes)) !=
TTY_OK)
646 if ((rc = readByte(
fd, &buf[2], timeout, &read_bytes)) !=
TTY_OK)
652 if ((rc = readByte(
fd, &buf[3], timeout, &read_bytes)) !=
TTY_OK)
658 if ((rc = readByte(
fd, &buf[4], timeout, &read_bytes)) !=
TTY_OK)
664 if ((len + 3) > nbytes)
666 LOGF_ERROR(
"Read (%d) will exceed supplied buffer size (%d) for command %02X", (len + 3), nbytes, buf[4]);
672 for (n = 0; n < (len - 3); ++n)
674 if ((rc = readByte(
fd, &buf[5 + n], timeout, &read_bytes)) !=
TTY_OK)
676 LOGF_DEBUG(
"%s byte not encountered",
"DATA");
681 if ((rc = readByte(
fd, &buf[5 + n], timeout, &read_bytes)) !=
TTY_OK)
683 LOGF_DEBUG(
"%s byte not encountered",
"DATA");
687 uint8_t chk = calculateCheckSum(buf, (len + 3));
689 if (chk != buf[len + 2])
695 *nbytes_read = len + 3;
703 bool EFA::sendCommand(
const uint8_t *
cmd, uint8_t *res, uint32_t cmd_len, uint32_t res_len)
705 int nbytes_written = 0, nbytes_read = 0, bits = 0, rc = 0, hexbuflen = (DRIVER_LEN * 3 + 4);
706 char hexbuf[DRIVER_LEN * 3 + 4];
708 for (
int j = 0; j < 3; usleep(100000), j++)
712 (void) ioctl(
PortFD, TIOCMBIC, &bits);
716 for (
int i = 0; i < 10; i++)
718 if ((rc = ioctl(
PortFD, TIOCMGET, &bits)) == 0 && (bits & TIOCM_CTS) == 0)
723 if (rc < 0 || (bits & TIOCM_CTS) != 0)
731 ioctl(
PortFD, TIOCMBIS, &bits);
733 if (!IN_TIMER && efaDump(hexbuf, hexbuflen,
cmd, cmd_len) != NULL)
737 rc = writeBytes(
PortFD,
cmd, cmd_len, &nbytes_written);
744 rc = readPacket(
PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
746 if (rc !=
TTY_OK || nbytes_read == 0)
751 if ((
int)cmd_len == nbytes_read && memcmp(
cmd, res, cmd_len) == 0)
756 ioctl(
PortFD, TIOCMBIC, &bits);
759 rc = readPacket(
PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
761 if (rc !=
TTY_OK || nbytes_read == 0)
766 else if (efaDump(hexbuf, hexbuflen,
cmd, cmd_len) != NULL)
769 LOGF_DEBUG(
"no echo for command packet: %s", hexbuf);
772 if (!IN_TIMER && efaDump(hexbuf, hexbuflen, res, nbytes_read) != NULL)
777 if (
cmd[2] != res[3] ||
cmd[3] != res[2] ||
cmd[4] != res[4])
779 LOGF_DEBUG(
"Send/Receive mismatch - %s!",
"packet not for us");
787 ioctl(
PortFD, TIOCMBIC, &bits);
797 if (
cmd[2] != res[3] ||
cmd[3] != res[2] ||
cmd[4] != res[4])
799 LOGF_ERROR(
"Send/Receive mismatch and %s",
"timeout");
809 bool EFA::readPosition()
811 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 6;
818 cmd[5] = calculateCheckSum(
cmd, len);
820 if (!validateLengths(
cmd, len))
823 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
826 FocusAbsPosN[0].value = res[5] << 16 | res[6] << 8 | res[7];
833 bool EFA::readMaxSlewLimit()
835 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 6;
842 cmd[5] = calculateCheckSum(
cmd, len);
844 if (!validateLengths(
cmd, len))
847 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
850 uint32_t limit = res[5] << 16 | res[6] << 8 | res[7];
864 bool EFA::isGOTOComplete()
866 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 6;
873 cmd[5] = calculateCheckSum(
cmd, len);
875 if (!validateLengths(
cmd, len))
878 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
881 return (res[5] != 0);
887 bool EFA::setFanEnabled(
bool enabled)
889 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 7;
896 cmd[5] = enabled ? 1 : 0;
897 cmd[6] = calculateCheckSum(
cmd, len);
899 if (!validateLengths(
cmd, len))
902 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
905 return (res[5] == 1);
911 bool EFA::readFanState()
913 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 6;
920 cmd[5] = calculateCheckSum(
cmd, len);
922 if (!validateLengths(
cmd, len))
925 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
928 bool enabled = (res[5] == 0);
939 bool EFA::setCalibrationEnabled(
bool enabled)
941 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 8;
949 cmd[6] = enabled ? 1 : 0;
950 cmd[7] = calculateCheckSum(
cmd, len);
952 if (!validateLengths(
cmd, len))
955 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
958 return (res[5] == 1);
964 bool EFA::readCalibrationState()
966 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 7;
974 cmd[6] = calculateCheckSum(
cmd, len);
976 if (!validateLengths(
cmd, len))
979 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
982 bool enabled = (res[5] == 1);
984 CalibrationStateS[CALIBRATION_ON].s = enabled ?
ISS_ON :
ISS_OFF;
985 CalibrationStateS[CALIBRATION_OFF].s = enabled ?
ISS_OFF :
ISS_ON;
993 bool EFA::readTemperature()
995 uint8_t
cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 7;
997 for (uint8_t i = 0; i < 2; i++)
1005 cmd[6] = calculateCheckSum(
cmd, len);
1007 if (!validateLengths(
cmd, len))
1010 if (!sendCommand(
cmd, res, len, DRIVER_LEN))
1013 TemperatureN[i].value = calculateTemperature(res[5], res[6]);
1022 double EFA::calculateTemperature(uint8_t byte2, uint8_t byte3)
1024 if (byte2 == 0x7F && byte3 == 0x7F)
1027 int raw_temperature = byte3 << 8 | byte2;
1028 if (raw_temperature & 0x8000)
1029 raw_temperature = raw_temperature - 0x10000;
1031 return raw_temperature / 16.0;
1037 char * EFA::efaDump(
char * buf,
int buflen,
const uint8_t * data, uint32_t size)
1039 int needed = 0, idx = 0;
1041 needed = size * 3 + 4;
1043 if (needed > buflen)
1048 for (uint32_t i = 0; i < size; i++)
1052 (void) sprintf(buf + idx,
"<%02X> ", data[i]);
1055 else if (i == 5 && i < (size - 1))
1058 for (uint32_t j = i, k = 3; j < (size - 1) && k < data[1]; j++, k++)
1060 (void) sprintf(buf + idx,
"%02X ", data[j]);
1069 (void) sprintf(buf + idx,
"%02X ", data[i]);
1074 buf[idx - 1] =
'\0';
1082 std::vector<std::string> EFA::split(
const std::string &input,
const std::string ®ex)
1085 std::regex re(regex);
1086 std::sregex_token_iterator
1087 first{input.begin(), input.end(), re, -1},
1089 return {first, last};
1095 template <
typename T>
1096 std::string EFA::to_string(
const T a_value,
const int n)
1098 std::ostringstream out;
1100 out << std::fixed << a_value;
1107 bool EFA::validateLengths(
const uint8_t *
cmd, uint32_t len)
1111 LOGF_ERROR(
"packet length (%d) is too short for command %02X", len,
cmd[4]);
1114 if (
cmd[1] + 3 != (
int)len)
1116 LOGF_ERROR(
"packet length (%d) and data length (%d) discrepancy for command %02X", len,
cmd[1],
cmd[4]);
1126 uint8_t EFA::calculateCheckSum(
const uint8_t *
cmd, uint32_t len)
1130 for (uint32_t i = 1; i < len - 1; i++)
1133 return ((-sum) & 0xFF);
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
virtual bool SyncFocuser(uint32_t ticks) override
Sync focuser.
virtual IPState MoveRelFocuser(FocusDirection dir, unsigned int ticks) override
Move Focuser relatively.
@ MTR_SET_CALIBRATION_STATE
@ MTR_GET_CALIBRATION_STATE
virtual bool ReverseFocuser(bool enabled) override
Reverse Focuser Motion.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
Set Maximum Position.
const char * getDefaultName() override
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch 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 MoveAbsFocuser(uint32_t targetTicks) override
Move Absolute Focuser.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
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.
virtual bool Disconnect() override
Disconnect from device.
const char * getDeviceName() const
virtual bool Disconnect()
Disconnect from device.
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 loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
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.
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
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
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Implementations for common driver routines.
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
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 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 IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
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.
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
#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,...)
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
std::unique_ptr< SteelDrive > steelDrive(new SteelDrive())