34 #define SCOPEDOME_TIMEOUT 2
35 #define SCOPEDOME_MAX_READS 10
37 static size_t WriteCallback(
void *contents,
size_t size,
size_t nmemb,
void *userp)
39 static_cast<std::string *
>(userp)->append((
char *)contents, size * nmemb);
44 : parent(driver), interface(iface)
54 curl_global_init(CURL_GLOBAL_ALL);
55 curl = curl_easy_init();
58 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
60 curl_easy_setopt(curl, CURLOPT_USERNAME, credentials[0].getText());
61 curl_easy_setopt(curl, CURLOPT_PASSWORD, credentials[1].getText());
65 hostName = tcp->host();
67 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
71 LOG_ERROR(
"Error initializing curl library");
80 curl_global_cleanup();
83 curl_easy_cleanup(curl);
92 if(performCommand(
"getMode", res))
94 return (res ==
"MASTER");
99 bool ScopeDomeArduino::performCommand(
const std::string &command, std::string &response)
105 std::string readBuffer;
111 snprintf(requestURL,
MAXRBUF,
"http://%s/?%s", hostName.c_str(), command.c_str());
113 curl_easy_setopt(curl, CURLOPT_URL, requestURL);
114 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
115 curl_easy_perform(curl);
117 if(readBuffer.size() < 3)
119 LOGF_ERROR(
"Error reading: %s. Cmd: %s", readBuffer.c_str(), command.c_str());
123 std::string resp(readBuffer.begin(), readBuffer.end() - 2);
125 auto split = splitString(resp,
'|');
127 if (
split.size() != 3)
129 LOGF_ERROR(
"Invalid response: %s. Cmd: %s", resp.c_str(), command.c_str());
133 if (
split[1] !=
"OK")
135 LOGF_ERROR(
"Error from device: %s. Cmd: %s", resp.c_str(), command.c_str());
139 LOGF_DEBUG(
"read response: %s", response.c_str());
149 int nbytes_written = 0, rc = -1;
152 if (command.length() == 0)
155 tcflush(PortFD, TCIOFLUSH);
161 snprintf(lineBuf,
MAXRBUF,
"%s\r\n", command.c_str());
166 LOGF_ERROR(
"Error writing command: %s. Cmd: %s", errstr, command.c_str());
176 LOGF_ERROR(
"Error reading: %s. Cmd: %s", errstr, command.c_str());
179 lineBuf[nbytes_read] = 0;
180 int len = strlen(lineBuf);
183 LOGF_ERROR(
"Error reading: %s. Cmd: %s", errstr, command.c_str());
187 std::string resp(lineBuf, strlen(lineBuf) - 1);
189 auto split = splitString(resp,
'|');
191 if (
split.size() != 3)
193 LOGF_ERROR(
"Invalid response: %s. Cmd: %s", lineBuf, command.c_str());
197 if (
split[1] !=
"OK")
199 LOGF_ERROR(
"Error from device: %s. Cmd: %s", lineBuf, command.c_str());
203 LOGF_DEBUG(
"read response: %s", response.c_str());
211 if(performCommand(
"getFirmwareVersion", res))
213 main = std::stod(res);
216 if(performCommand(
"slave=getFirmwareVersion", res))
218 rotary = std::stod(res);
225 stepsPerRevolution = 0;
226 if(performCommand(
"getCalibratedRotation", res))
228 stepsPerRevolution = std::stoi(res);
230 if(stepsPerRevolution == 0)
232 LOG_INFO(
"Step count read as zero, run calibration");
233 stepsPerRevolution = 3240;
235 return stepsPerRevolution;
242 if(!performCommand(
"getStatus", status))
263 auto parts = splitString(status,
'#');
264 if(parts.size() == 3)
266 auto master = splitString(parts[0],
';');
268 if (master.size() == 12)
271 for(
auto &s : master)
276 auto digitalInputs = splitString(master[0],
':');
278 for(
const auto &input : digitalInputs)
280 inputs[i++] = (input ==
"0");
284 auto analogInputs = splitString(master[1],
':');
285 for(
const auto &input : analogInputs)
287 sensors[i++] = std::stod(input);
289 rotaryEncoder = std::stoi(master[2]);
290 auto temperatures = splitString(master[3],
':');
291 for(
const auto &temp : temperatures)
293 sensors[i++] = std::stod(temp);
295 auto pressure_humidity = splitString(master[4],
':');
296 for(
const auto &value : pressure_humidity)
298 sensors[i++] = std::stod(value);
300 std::string clouds = master[5];
301 std::string vcc = master[6];
302 std::string buttons = master[7];
303 auto relayPWM = splitString(master[8],
':');
305 for(
int r = 6; r < 9; r++)
307 relays[i++] = (relayPWM[r] ==
"1");
309 moving = (relayPWM[0] ==
"1" || relayPWM[1] ==
"1");
310 if(!moving && rotaryEncoder != previousEncoder)
312 previousEncoder = rotaryEncoder;
314 std::string emergency = master[9];
315 std::string loopTime = master[10];
316 std::string freshFlag = master[11];
319 sensors[0] *= 10.0 * (5.0 / 0.1955);
366 auto slave = splitString(parts[1],
';');
368 if (slave.size() == 12)
376 auto digitalInputs = splitString(slave[0],
':');
378 for(
const auto &input : digitalInputs)
380 inputs[i++] = (input ==
"0");
383 auto analogInputs = splitString(slave[1],
':');
384 for(
const auto &input : analogInputs)
386 sensors[i++] = std::stod(input);
388 shutterEncoder = std::stoi(slave[2]);
389 auto temperatures = splitString(slave[3],
':');
390 for(
const auto &temp : temperatures)
392 sensors[i++] = std::stod(temp);
394 auto pressure_humidity = splitString(slave[4],
':');
395 for(
const auto &value : pressure_humidity)
397 sensors[i++] = std::stod(value);
399 std::string clouds = slave[5];
400 std::string vcc = slave[6];
401 std::string buttons = slave[7];
402 auto relayPWM = splitString(slave[8],
':');
404 for(
int r = 6; r < 9; r++)
406 relays[i++] = (relayPWM[r] ==
"1");
408 std::string emergency = slave[9];
409 std::string loopTime = slave[10];
410 std::string freshFlag = slave[11];
413 sensors[14] *= 10.0 * (5.0 / 0.1955);
462 auto flags = splitString(parts[2],
':');
463 if (flags.size() == 4)
470 rotaryLink = (flags[0] ==
"1");
471 homing = (flags[1] ==
"1");
472 moveShutterOnHome = (flags[2] ==
"1");
473 calibrating = (flags[3] ==
"1");
484 LOGF_DEBUG(
"invalid status response: %s", status.c_str());
548 performCommand(
"moveDome=CW", res);
552 performCommand(
"stopDome", res);
558 performCommand(
"moveDome=CCW", res);
562 performCommand(
"stopDome", res);
575 return encoderBaseValue - rotaryEncoder;
581 return encoderBaseValue - rotaryEncoder;
592 performCommand(
"stopDome", res);
593 performCommand(
"stopShutter", res);
599 performCommand(
"calibrate", res);
605 performCommand(
"findHome", res);
614 performCommand(
"moveShutter=OPEN", res);
617 performCommand(
"moveShutter=CLOSE", res);
620 performCommand(
"stopShutter", res);
643 snprintf(
cmd, 31,
"moveDome=CCW:%d", -steps);
644 performCommand(
cmd, res);
649 snprintf(
cmd, 31,
"moveDome=CW:%d", steps);
650 performCommand(
cmd, res);
666 info.
label =
"Master 64V";
673 info.
label =
"T_PT100";
680 info.
label =
"T_PCB";
687 info.
label =
"PCB thermometer";
693 info.
propName =
"BAROMETER_TEMPERATURE";
694 info.
label =
"Barometer temperature";
700 info.
propName =
"THERMOMETER_ONEWIRE_MOTOR";
701 info.
label =
"Motor temperature";
707 info.
propName =
"THERMOMETER_ONEWIRE_OUTSIDE";
708 info.
label =
"Outside temperature";
714 info.
propName =
"THERMOMETER_ONEWIRE_MIRROR_1";
715 info.
label =
"Mirror 1 temperature";
721 info.
propName =
"THERMOMETER_ONEWIRE_MIRROR_2";
722 info.
label =
"Mirror 2 temperature";
728 info.
propName =
"HIGROMETER_TEMPERATURE";
729 info.
label =
"Higrometer temperature";
735 info.
propName =
"PIROMETER_AMBIENT";
736 info.
label =
"Pirometer ambient temperature";
743 info.
label =
"Pirometer sensor temperature";
749 info.
propName =
"BAROMETER_PRESSURE";
750 info.
label =
"Barometer pressure";
756 info.
propName =
"HIGROMETER_HUMIDITY";
757 info.
label =
"Higrometer humidity";
764 info.
label =
"Slave 64V";
771 info.
label =
"Slave T_PT100";
778 info.
label =
"Slave T_PCB";
784 info.
propName =
"S_THERMOMETER_PCB";
785 info.
label =
"Slave PCB thermometer";
791 info.
propName =
"S_BAROMETER_TEMPERATURE";
792 info.
label =
"Slave barometer temperature";
798 info.
propName =
"S_THERMOMETER_ONEWIRE_MOTOR";
799 info.
label =
"Slave motor temperature";
805 info.
propName =
"S_THERMOMETER_ONEWIRE_OUTSIDE";
806 info.
label =
"Slave outside temperature";
812 info.
propName =
"S_THERMOMETER_ONEWIRE_MIRROR_1";
813 info.
label =
"Slave mirror 1 temperature";
819 info.
propName =
"S_THERMOMETER_ONEWIRE_MIRROR_2";
820 info.
label =
"Slave mirror 2 temperature";
826 info.
propName =
"S_HIGROMETER_TEMPERATURE";
827 info.
label =
"Slave higrometer temperature";
833 info.
propName =
"S_PIROMETER_AMBIENT";
834 info.
label =
"Slave pirometer ambient temperature";
840 info.
propName =
"S_PIROMETER_SENSOR";
841 info.
label =
"Slave pirometer sensor temperature";
847 info.
propName =
"S_BAROMETER_PRESSURE";
848 info.
label =
"Slave barometer pressure";
854 info.
propName =
"S_HIGROMETER_HUMIDITY";
855 info.
label =
"Slave higrometer humidity";
869 return sensors[index];
884 info.
label =
"Relay 1";
888 info.
label =
"Relay 2";
892 info.
label =
"Relay 3";
896 info.
label =
"Slave relay 1";
900 info.
label =
"Slave relay 2";
904 info.
label =
"Slave relay 3";
929 cmd +=
"switchOnFreeRelay=";
933 cmd +=
"switchOffFreeRelay=";
936 performCommand(
cmd, res);
951 info.
label =
"Detect 230V loss";
955 info.
label =
"Rotary encoder";
959 info.
label =
"Home sensor";
963 info.
label =
"Free 1";
967 info.
label =
"Free 2";
971 info.
label =
"Rain sensor";
975 info.
label =
"Cloud sensor";
979 info.
label =
"Telescope at home";
983 info.
label =
"Slave detect 230V loss";
987 info.
label =
"Shutter encoder";
991 info.
label =
"Slave home sensor";
995 info.
label =
"Shutter 1 open";
999 info.
label =
"Shutter 1 closed";
1003 info.
label =
"Slave rain sensor";
1007 info.
label =
"Slave cloud sensor";
1011 info.
label =
"Slave telescope at home";
1028 std::string
cmd =
"setHomeSignalLow=";
1039 performCommand(
cmd, res);
1042 std::vector<std::string> ScopeDomeArduino::splitString(
const std::string &src,
char splitChar)
1044 std::vector<std::string> results;
1048 while( (end = src.find(splitChar, start)) != std::string::npos)
1050 results.push_back(src.substr(start, end - start));
1053 results.push_back(src.substr(start, std::string::npos));
The Interface class is the base class for all INDI connection plugins.
virtual Type type()
type Return connection type
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
The TCP class manages connection with devices over the network via TCP/IP. Upon successfull connectio...
virtual ~ScopeDomeArduino()
virtual SensorInfo getSensorInfo(size_t index) override
virtual void controlShutter(ShutterOperation operation) override
virtual size_t getNumberOfRelays() override
virtual void setHomeSensorPolarity(HomeSensorPolarity polarity) override
virtual ISState getInputValue(size_t index) override
ScopeDomeArduino(ScopeDome *driver, Connection::Interface *interface)
virtual int getRotationCounterExt() override
virtual uint32_t getStatus() override
virtual void resetCounter() override
virtual size_t getNumberOfSensors() override
virtual uint32_t getStepsPerRevolution() override
virtual void getFirmwareVersions(double &main, double &rotary) override
virtual bool isCalibrationNeeded() override
virtual bool detect() override
virtual void abort() override
virtual double getSensorValue(size_t index) override
virtual size_t getNumberOfInputs() override
virtual RelayInfo getRelayInfo(size_t index) override
virtual ISState getInputState(AbstractInput input) override
virtual int getRotationCounter() override
virtual void calibrate() override
virtual ISState getRelayState(size_t index) override
virtual void findHome() override
virtual void move(int steps) override
virtual void setRelayState(size_t index, ISState state) override
virtual int updateState() override
virtual int setOutputState(AbstractOutput output, ISState state) override
virtual InputInfo getInputInfo(size_t index) override
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_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,...)
std::vector< std::string > split(const std::string &input, const std::string ®ex)
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
#define SCOPEDOME_TIMEOUT