Instrument Neutral Distributed Interface INDI 2.2.5
indi_astrolink4.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2019 astrojolo.com
3 .
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
7 .
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12 .
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17*******************************************************************************/
18#include "indi_astrolink4.h"
19#include "config.h"
20
21#include "indicom.h"
22
23#define ASTROLINK4_LEN 100
24#define ASTROLINK4_TIMEOUT 3
25
29static std::unique_ptr<IndiAstrolink4> indiAstrolink4(new IndiAstrolink4());
30
35{
36 setVersion(ASTROLINK4_VERSION_MAJOR, ASTROLINK4_VERSION_MINOR);
37}
38
40{
41 return "AstroLink 4";
42}
43
47bool IndiAstrolink4::Handshake()
48{
49 PortFD = serialConnection->getPortFD();
50
51 char res[ASTROLINK4_LEN] = {0};
52 if(sendCommand("#", res))
53 {
54 if(strncmp(res, "#:AstroLink4mini", 15) != 0)
55 {
56 LOG_ERROR("Device not recognized.");
57 return false;
58 }
59 else
60 {
62 return true;
63 }
64 }
65 return false;
66}
67
69{
70 if(!isConnected())
71 return;
72
73 sensorRead();
75}
76
81{
83
85
92
94 WI::initProperties(ENVIRONMENT_TAB, ENVIRONMENT_TAB);
95
99
100 // focuser settings
101 IUFillNumber(&FocuserSettingsN[FS_SPEED], "FS_SPEED", "Speed [pps]", "%.0f", 0, 4000, 50, 250);
102 IUFillNumber(&FocuserSettingsN[FS_STEP_SIZE], "FS_STEP_SIZE", "Step size [um]", "%.2f", 0, 100, 0.1, 5.0);
103 IUFillNumber(&FocuserSettingsN[FS_COMPENSATION], "FS_COMPENSATION", "Compensation [steps/C]", "%.2f", -1000, 1000, 1, 0);
104 IUFillNumber(&FocuserSettingsN[FS_COMP_THRESHOLD], "FS_COMP_THRESHOLD", "Compensation threshold [steps]", "%.0f", 1, 1000,
105 10, 10);
106 IUFillNumberVector(&FocuserSettingsNP, FocuserSettingsN, 4, getDeviceName(), "FOCUSER_SETTINGS", "Focuser settings",
107 SETTINGS_TAB, IP_RW, 60, IPS_IDLE);
108
109 IUFillSwitch(&FocuserModeS[FS_MODE_UNI], "FS_MODE_UNI", "Unipolar", ISS_ON);
110 IUFillSwitch(&FocuserModeS[FS_MODE_BI], "FS_MODE_BI", "Bipolar", ISS_OFF);
111 IUFillSwitch(&FocuserModeS[FS_MODE_MICRO], "FS_MODE_MICRO", "Microstep", ISS_OFF);
112 IUFillSwitchVector(&FocuserModeSP, FocuserModeS, 3, getDeviceName(), "FOCUSER_MODE", "Focuser mode", SETTINGS_TAB, IP_RW,
113 ISR_1OFMANY, 60, IPS_IDLE);
114
115 IUFillSwitch(&FocuserCompModeS[FS_COMP_AUTO], "FS_COMP_AUTO", "AUTO", ISS_OFF);
116 IUFillSwitch(&FocuserCompModeS[FS_COMP_MANUAL], "FS_COMP_MANUAL", "MANUAL", ISS_ON);
117 IUFillSwitchVector(&FocuserCompModeSP, FocuserCompModeS, 2, getDeviceName(), "COMP_MODE", "Compensation mode", SETTINGS_TAB,
119
120 IUFillSwitch(&FocuserManualS[FS_MANUAL_ON], "FS_MANUAL_ON", "ON", ISS_ON);
121 IUFillSwitch(&FocuserManualS[FS_MANUAL_OFF], "FS_MANUAL_OFF", "OFF", ISS_OFF);
122 IUFillSwitchVector(&FocuserManualSP, FocuserManualS, 2, getDeviceName(), "MANUAL_CONTROLLER", "Hand controller",
123 SETTINGS_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
124
125 // other settings
126 IUFillNumber(&OtherSettingsN[SET_AREF_COEFF], "SET_AREF_COEFF", "V ref coefficient", "%.3f", 0.9, 1.2, 0.001, 1.09);
127 IUFillNumber(&OtherSettingsN[SET_OVER_TIME], "SET_OVER_TIME", "Protection sensitivity [ms]", "%.0f", 10, 500, 10, 100);
128 IUFillNumber(&OtherSettingsN[SET_OVER_VOLT], "SET_OVER_VOLT", "Protection voltage [V]", "%.1f", 10, 14, 0.1, 14);
129 IUFillNumber(&OtherSettingsN[SET_OVER_AMP], "SET_OVER_AMP", "Protection current [A]", "%.1f", 1, 10, 0.1, 10);
130 IUFillNumberVector(&OtherSettingsNP, OtherSettingsN, 4, getDeviceName(), "OTHER_SETTINGS", "Device settings", SETTINGS_TAB,
131 IP_RW, 60, IPS_IDLE);
132
133 IUFillSwitch(&BuzzerS[0], "BUZZER", "Buzzer", ISS_OFF);
134 IUFillSwitchVector(&BuzzerSP, BuzzerS, 1, getDeviceName(), "BUZZER", "ONOFF", SETTINGS_TAB, IP_RW, ISR_NOFMANY, 60,
135 IPS_IDLE);
136
137 // focuser compensation
138 IUFillNumber(&CompensationValueN[0], "COMP_VALUE", "Compensation steps", "%.0f", -10000, 10000, 1, 0);
139 IUFillNumberVector(&CompensationValueNP, CompensationValueN, 1, getDeviceName(), "COMP_STEPS", "Compensation steps",
140 FOCUS_TAB, IP_RO, 60, IPS_IDLE);
141
142 IUFillSwitch(&CompensateNowS[0], "COMP_NOW", "Compensate now", ISS_OFF);
143 IUFillSwitchVector(&CompensateNowSP, CompensateNowS, 1, getDeviceName(), "COMP_NOW", "Compensate now", FOCUS_TAB, IP_RW,
144 ISR_ATMOST1, 60, IPS_IDLE);
145
146 IUFillNumber(&FocusPosMMN[0], "FOC_POS_MM", "Position [mm]", "%.3f", 0.0, 200.0, 0.001, 0.0);
147 IUFillNumberVector(&FocusPosMMNP, FocusPosMMN, 1, getDeviceName(), "FOC_POS_MM", "Position [mm]", FOCUS_TAB, IP_RO, 60,
148 IPS_IDLE);
149
150 // power lines
151 IUFillText(&PowerControlsLabelsT[0], "POWER_LABEL_1", "Port 1", "Port 1");
152 IUFillText(&PowerControlsLabelsT[1], "POWER_LABEL_2", "Port 2", "Port 2");
153 IUFillText(&PowerControlsLabelsT[2], "POWER_LABEL_3", "Port 3", "Port 3");
154 IUFillTextVector(&PowerControlsLabelsTP, PowerControlsLabelsT, 3, getDeviceName(), "POWER_CONTROL_LABEL", "Power Labels",
155 POWER_TAB, IP_WO, 60, IPS_IDLE);
156
157 char portLabel1[MAXINDILABEL], portLabel2[MAXINDILABEL], portLabel3[MAXINDILABEL];
158
159 memset(portLabel1, 0, MAXINDILABEL);
160 int portRC1 = IUGetConfigText(getDeviceName(), PowerControlsLabelsTP.name, PowerControlsLabelsT[0].name, portLabel1,
162
163 IUFillSwitch(&Power1S[0], "PWR1BTN_ON", "ON", ISS_OFF);
164 IUFillSwitch(&Power1S[1], "PWR1BTN_OFF", "OFF", ISS_ON);
165 IUFillSwitchVector(&Power1SP, Power1S, 2, getDeviceName(), "DC1", portRC1 == -1 ? "Port 1" : portLabel1, POWER_TAB, IP_RW,
167
168 memset(portLabel2, 0, MAXINDILABEL);
169 int portRC2 = IUGetConfigText(getDeviceName(), PowerControlsLabelsTP.name, PowerControlsLabelsT[1].name, portLabel2,
171
172 IUFillSwitch(&Power2S[0], "PWR2BTN_ON", "ON", ISS_OFF);
173 IUFillSwitch(&Power2S[1], "PWR2BTN_OFF", "OFF", ISS_ON);
174 IUFillSwitchVector(&Power2SP, Power2S, 2, getDeviceName(), "DC2", portRC2 == -1 ? "Port 2" : portLabel2, POWER_TAB, IP_RW,
176
177 memset(portLabel3, 0, MAXINDILABEL);
178 int portRC3 = IUGetConfigText(getDeviceName(), PowerControlsLabelsTP.name, PowerControlsLabelsT[2].name, portLabel3,
180
181 IUFillSwitch(&Power3S[0], "PWR3BTN_ON", "ON", ISS_OFF);
182 IUFillSwitch(&Power3S[1], "PWR3BTN_OFF", "OFF", ISS_ON);
183 IUFillSwitchVector(&Power3SP, Power3S, 2, getDeviceName(), "DC3", portRC3 == -1 ? "Port 3" : portLabel3, POWER_TAB, IP_RW,
185
186 IUFillSwitch(&PowerDefaultOnS[0], "POW_DEF_ON1", "DC1", ISS_OFF);
187 IUFillSwitch(&PowerDefaultOnS[1], "POW_DEF_ON2", "DC2", ISS_OFF);
188 IUFillSwitch(&PowerDefaultOnS[2], "POW_DEF_ON3", "DC3", ISS_OFF);
189 IUFillSwitchVector(&PowerDefaultOnSP, PowerDefaultOnS, 3, getDeviceName(), "POW_DEF_ON", "Power default ON", SETTINGS_TAB,
191
192 // pwm
193 IUFillNumber(&PWMN[0], "PWM1_VAL", "A", "%3.0f", 0, 100, 10, 0);
194 IUFillNumber(&PWMN[1], "PWM2_VAL", "B", "%3.0f", 0, 100, 10, 0);
195 IUFillNumberVector(&PWMNP, PWMN, 2, getDeviceName(), "PWM", "PWM", POWER_TAB, IP_RW, 60, IPS_IDLE);
196
197 // Auto pwm
198 IUFillSwitch(&AutoPWMDefaultOnS[0], "PWMA_A_DEF_ON", "A", ISS_OFF);
199 IUFillSwitch(&AutoPWMDefaultOnS[1], "PWMA_B_DEF_ON", "B", ISS_OFF);
200 IUFillSwitchVector(&AutoPWMDefaultOnSP, AutoPWMDefaultOnS, 2, getDeviceName(), "AUTO_PWM_DEF_ON", "Auto PWM default ON",
201 SETTINGS_TAB,
203
204 ISState pwmAutoA = ISS_OFF;
205 IUGetConfigSwitch(getDeviceName(), AutoPWMDefaultOnSP.name, AutoPWMDefaultOnS[0].name, &pwmAutoA);
206
207 ISState pwmAutoB = ISS_OFF;
208 IUGetConfigSwitch(getDeviceName(), AutoPWMDefaultOnSP.name, AutoPWMDefaultOnS[1].name, &pwmAutoB);
209
210 IUFillSwitch(&AutoPWMS[0], "PWMA_A", "A", pwmAutoA);
211 IUFillSwitch(&AutoPWMS[1], "PWMA_B", "B", pwmAutoB);
212 IUFillSwitchVector(&AutoPWMSP, AutoPWMS, 2, getDeviceName(), "AUTO_PWM", "Auto PWM", POWER_TAB, IP_RW, ISR_NOFMANY, 60,
213 IPS_OK);
214
215 IUFillNumber(&PowerDataN[POW_VIN], "VIN", "Input voltage", "%.1f", 0, 15, 10, 0);
216 IUFillNumber(&PowerDataN[POW_VREG], "VREG", "Regulated voltage", "%.1f", 0, 15, 10, 0);
217 IUFillNumber(&PowerDataN[POW_ITOT], "ITOT", "Total current", "%.1f", 0, 15, 10, 0);
218 IUFillNumber(&PowerDataN[POW_AH], "AH", "Energy consumed [Ah]", "%.1f", 0, 1000, 10, 0);
219 IUFillNumber(&PowerDataN[POW_WH], "WH", "Energy consumed [Wh]", "%.1f", 0, 10000, 10, 0);
220 IUFillNumberVector(&PowerDataNP, PowerDataN, 5, getDeviceName(), "POWER_DATA", "Power data", POWER_TAB, IP_RO, 60,
221 IPS_IDLE);
222
223 // Environment Group
224 addParameter("WEATHER_TEMPERATURE", "Temperature (C)", -15, 35, 15);
225 addParameter("WEATHER_HUMIDITY", "Humidity %", 0, 100, 15);
226 addParameter("WEATHER_DEWPOINT", "Dew Point (C)", 0, 100, 15);
227
228 // Sensor 2
229 IUFillNumber(&Sensor2N[0], "TEMP_2", "Temperature (C)", "%.1f", -50, 100, 1, 0);
230 IUFillNumberVector(&Sensor2NP, Sensor2N, 1, getDeviceName(), "SENSOR_2", "Sensor 2", ENVIRONMENT_TAB, IP_RO, 60, IPS_IDLE);
231
232 // DC focuser
233 IUFillNumber(&DCFocTimeN[DC_PERIOD], "DC_PERIOD", "Time [ms]", "%.0f", 10, 5000, 10, 500);
234 IUFillNumber(&DCFocTimeN[DC_PWM], "DC_PWM", "PWM [%]", "%.0f", 10, 100, 10, 50);
235 IUFillNumberVector(&DCFocTimeNP, DCFocTimeN, 2, getDeviceName(), "DC_FOC_TIME", "DC Focuser", DCFOCUSER_TAB, IP_RW, 60,
236 IPS_OK);
237
238 IUFillSwitch(&DCFocDirS[0], "DIR_IN", "IN", ISS_OFF);
239 IUFillSwitch(&DCFocDirS[1], "DIR_OUT", "OUT", ISS_ON);
240 IUFillSwitchVector(&DCFocDirSP, DCFocDirS, 2, getDeviceName(), "DC_FOC_DIR", "DC Focuser direction", DCFOCUSER_TAB, IP_RW,
241 ISR_1OFMANY, 60, IPS_OK);
242
243 IUFillSwitch(&DCFocAbortS[0], "DC_FOC_ABORT", "STOP", ISS_OFF);
244 IUFillSwitchVector(&DCFocAbortSP, DCFocAbortS, 1, getDeviceName(), "DC_FOC_ABORT", "DC Focuser stop", DCFOCUSER_TAB, IP_RW,
245 ISR_ATMOST1, 60, IPS_IDLE);
246
247 serialConnection = new Connection::Serial(this);
248 serialConnection->registerHandshake([&]()
249 {
250 return Handshake();
251 });
252 registerConnection(serialConnection);
253
254 serialConnection->setDefaultPort("/dev/ttyUSB0");
255 serialConnection->setDefaultBaudRate(serialConnection->B_115200);
256
257 return true;
258}
259
261{
262 // Call parent update properties first
264
265 if (isConnected())
266 {
267 defineProperty(&FocusPosMMNP);
270 defineProperty(&Power1SP);
271 defineProperty(&Power2SP);
272 defineProperty(&Power3SP);
273 defineProperty(&AutoPWMSP);
274 defineProperty(&Sensor2NP);
275 defineProperty(&PWMNP);
276 defineProperty(&PowerDataNP);
277 defineProperty(&FocuserSettingsNP);
278 defineProperty(&FocuserModeSP);
279 defineProperty(&FocuserCompModeSP);
280 defineProperty(&FocuserManualSP);
281 defineProperty(&CompensationValueNP);
282 defineProperty(&CompensateNowSP);
283 defineProperty(&PowerDefaultOnSP);
284 defineProperty(&AutoPWMDefaultOnSP);
285 defineProperty(&OtherSettingsNP);
286 defineProperty(&DCFocDirSP);
287 defineProperty(&DCFocTimeNP);
288 defineProperty(&DCFocAbortSP);
289 defineProperty(&PowerControlsLabelsTP);
290 defineProperty(&BuzzerSP);
291 }
292 else
293 {
294 deleteProperty(Power1SP.name);
295 deleteProperty(Power2SP.name);
296 deleteProperty(Power3SP.name);
297 deleteProperty(AutoPWMSP.name);
298 deleteProperty(Sensor2NP.name);
299 deleteProperty(PWMNP.name);
300 deleteProperty(PowerDataNP.name);
301 deleteProperty(FocuserSettingsNP.name);
302 deleteProperty(FocuserModeSP.name);
303 deleteProperty(CompensateNowSP.name);
304 deleteProperty(CompensationValueNP.name);
305 deleteProperty(PowerDefaultOnSP.name);
306 deleteProperty(AutoPWMDefaultOnSP.name);
307 deleteProperty(OtherSettingsNP.name);
308 deleteProperty(DCFocTimeNP.name);
309 deleteProperty(DCFocDirSP.name);
310 deleteProperty(DCFocAbortSP.name);
311 deleteProperty(BuzzerSP.name);
312 deleteProperty(FocuserCompModeSP.name);
313 deleteProperty(FocuserManualSP.name);
314 deleteProperty(FocusPosMMNP.name);
315 deleteProperty(PowerControlsLabelsTP.name);
318 }
319
320 return true;
321}
322
323bool IndiAstrolink4::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
324{
325 if (dev && !strcmp(dev, getDeviceName()))
326 {
327 char cmd[ASTROLINK4_LEN] = {0};
328 char res[ASTROLINK4_LEN] = {0};
329
330 // handle PWM
331 if (!strcmp(name, PWMNP.name))
332 {
333 bool allOk = true;
334 if(PWMN[0].value != values[0])
335 {
336 if(AutoPWMS[0].s == ISS_OFF)
337 {
338 sprintf(cmd, "B:0:%d", static_cast<uint8_t>(values[0]));
339 allOk = allOk && sendCommand(cmd, res);
340 }
341 else
342 {
343 LOG_WARN("Cannot set PWM output, it is in AUTO mode.");
344 }
345 }
346 if(PWMN[1].value != values[1])
347 {
348 if(AutoPWMS[1].s == ISS_OFF)
349 {
350 sprintf(cmd, "B:1:%d", static_cast<uint8_t>(values[1]));
351 allOk = allOk && sendCommand(cmd, res);
352 }
353 else
354 {
355 LOG_WARN("Cannot set PWM output, it is in AUTO mode.");
356 }
357 }
358 PWMNP.s = (allOk) ? IPS_BUSY : IPS_ALERT;
359 if(allOk)
360 IUUpdateNumber(&PWMNP, values, names, n);
361 IDSetNumber(&PWMNP, nullptr);
362 IDSetSwitch(&AutoPWMSP, nullptr);
363 return true;
364 }
365
366 // Focuser settings
367 if(!strcmp(name, FocuserSettingsNP .name))
368 {
369 bool allOk = true;
370 std::map<int, std::string> updates;
371 updates[U_SPEED] = doubleToStr(values[FS_SPEED]);
372 updates[U_ACC] = doubleToStr(values[FS_SPEED] * 2.0);
373 updates[U_STEPSIZE] = doubleToStr(values[FS_STEP_SIZE] * 100.0);
374 allOk = allOk && updateSettings("u", "U", updates);
375 updates.clear();
376 updates[E_COMP_CYCLE] = "30"; // cycle [s]
377 updates[E_COMP_STEPS] = doubleToStr(values[FS_COMPENSATION] * 100.0);
378 updates[E_COMP_SENSR] = "0"; // sensor
379 updates[E_COMP_TRGR] = doubleToStr(values[FS_COMP_THRESHOLD]);
380 allOk = allOk && updateSettings("e", "E", updates);
381 if(allOk)
382 {
383 FocuserSettingsNP.s = IPS_BUSY;
384 IUUpdateNumber(&FocuserSettingsNP, values, names, n);
385 IDSetNumber(&FocuserSettingsNP, nullptr);
386 LOG_INFO(values[FS_COMPENSATION] > 0 ? "Temperature compensation is enabled." : "Temperature compensation is disabled.");
387 return true;
388 }
389 FocuserSettingsNP.s = IPS_ALERT;
390 return true;
391 }
392
393 // Other settings
394 if(!strcmp(name, OtherSettingsNP .name))
395 {
396 std::map<int, std::string> updates;
397 updates[N_AREF_COEFF] = doubleToStr(values[SET_AREF_COEFF] * 1000.0);
398 updates[N_OVER_VOLT] = doubleToStr(values[SET_OVER_VOLT] * 10.0);
399 updates[N_OVER_AMP] = doubleToStr(values[SET_OVER_AMP] * 10.0);
400 updates[N_OVER_TIME] = doubleToStr(values[SET_OVER_TIME]);
401 if(updateSettings("n", "N", updates))
402 {
403 OtherSettingsNP.s = IPS_BUSY;
404 IUUpdateNumber(&OtherSettingsNP, values, names, n);
405 IDSetNumber(&OtherSettingsNP, nullptr);
406 return true;
407 }
408 OtherSettingsNP.s = IPS_ALERT;
409 return true;
410 }
411
412 // DC Focuser
413 if(!strcmp(name, DCFocTimeNP.name))
414 {
415 IUUpdateNumber(&DCFocTimeNP, values, names, n);
416 IDSetNumber(&DCFocTimeNP, nullptr);
417 saveConfig(true);
418 sprintf(cmd, "G:%d:%.0f:%.0f", (DCFocDirS[0].s == ISS_ON) ? 1 : 0, DCFocTimeN[DC_PWM].value, DCFocTimeN[DC_PERIOD].value);
419 if(sendCommand(cmd, res))
420 {
421 DCFocAbortS[0].s = ISS_OFF;
422 DCFocAbortSP.s = IPS_OK;
423 IDSetSwitch(&DCFocAbortSP, nullptr);
424
425 DCFocTimeNP.s = IPS_BUSY;
426 return true;
427 }
428 DCFocTimeNP.s = IPS_ALERT;
429 return true;
430 }
431
432 if (strstr(name, "FOCUS_"))
433 return FI::processNumber(dev, name, values, names, n);
434 if (strstr(name, "WEATHER_"))
435 return WI::processNumber(dev, name, values, names, n);
436 }
437
438 return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
439}
440
441
442bool IndiAstrolink4::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
443{
444 if (dev && !strcmp(dev, getDeviceName()))
445 {
446 char cmd[ASTROLINK4_LEN] = {0};
447 char res[ASTROLINK4_LEN] = {0};
448
449 // handle power line 1
450 if (!strcmp(name, Power1SP.name))
451 {
452 sprintf(cmd, "C:0:%s", (strcmp(Power1S[0].name, names[0])) ? "0" : "1");
453 bool allOk = sendCommand(cmd, res);
454 Power1SP.s = allOk ? IPS_BUSY : IPS_ALERT;
455 if(allOk)
456 IUUpdateSwitch(&Power1SP, states, names, n);
457
458 IDSetSwitch(&Power1SP, nullptr);
459 return true;
460 }
461
462 // handle power line 2
463 if (!strcmp(name, Power2SP.name))
464 {
465 sprintf(cmd, "C:1:%s", (strcmp(Power2S[0].name, names[0])) ? "0" : "1");
466 bool allOk = sendCommand(cmd, res);
467 Power2SP.s = allOk ? IPS_BUSY : IPS_ALERT;
468 if(allOk)
469 IUUpdateSwitch(&Power2SP, states, names, n);
470
471 IDSetSwitch(&Power2SP, nullptr);
472 return true;
473 }
474
475 // handle power line 3
476 if (!strcmp(name, Power3SP.name))
477 {
478 sprintf(cmd, "C:2:%s", (strcmp(Power3S[0].name, names[0])) ? "0" : "1");
479 bool allOk = sendCommand(cmd, res);
480 Power3SP.s = allOk ? IPS_BUSY : IPS_ALERT;
481 if(allOk)
482 IUUpdateSwitch(&Power3SP, states, names, n);
483
484 IDSetSwitch(&Power3SP, nullptr);
485 return true;
486 }
487
488 // compensate now
489 if(!strcmp(name, CompensateNowSP.name))
490 {
491 sprintf(cmd, "S:%d", static_cast<uint8_t>(CompensationValueN[0].value));
492 bool allOk = sendCommand(cmd, res);
493 CompensateNowSP.s = allOk ? IPS_BUSY : IPS_ALERT;
494 if(allOk)
495 IUUpdateSwitch(&CompensateNowSP, states, names, n);
496
497 IDSetSwitch(&CompensateNowSP, nullptr);
498 return true;
499 }
500
501 // Auto PWM
502 if (!strcmp(name, AutoPWMSP.name))
503 {
504 IUUpdateSwitch(&AutoPWMSP, states, names, n);
505 AutoPWMSP.s = (setAutoPWM()) ? IPS_OK : IPS_ALERT;
506 IDSetSwitch(&AutoPWMSP, nullptr);
507 return true;
508 }
509
510 // DC Focuser
511 if (!strcmp(name, DCFocDirSP.name))
512 {
513 DCFocDirSP.s = IPS_OK;
514 IUUpdateSwitch(&DCFocDirSP, states, names, n);
515 IDSetSwitch(&DCFocDirSP, nullptr);
516 return true;
517 }
518
519 if (!strcmp(name, DCFocAbortSP.name))
520 {
521 sprintf(cmd, "%s", "K");
522 if(sendCommand(cmd, res))
523 {
524 DCFocAbortSP.s = IPS_BUSY;
525 IUUpdateSwitch(&DCFocAbortSP, states, names, n);
526 IDSetSwitch(&DCFocAbortSP, nullptr);
527 }
528 DCFocAbortSP.s = IPS_ALERT;
529 return true;
530 }
531
532 // Power default on
533 if(!strcmp(name, PowerDefaultOnSP.name))
534 {
535 std::map<int, std::string> updates;
536 updates[U_OUT1_DEF] = (states[0] == ISS_ON) ? "1" : "0";
537 updates[U_OUT2_DEF] = (states[1] == ISS_ON) ? "1" : "0";
538 updates[U_OUT3_DEF] = (states[2] == ISS_ON) ? "1" : "0";
539 if(updateSettings("u", "U", updates))
540 {
541 PowerDefaultOnSP.s = IPS_BUSY;
542 IUUpdateSwitch(&PowerDefaultOnSP, states, names, n);
543 IDSetSwitch(&PowerDefaultOnSP, nullptr);
544 return true;
545 }
546 PowerDefaultOnSP.s = IPS_ALERT;
547 return true;
548 }
549
550 // Auto PWM default on
551 if (!strcmp(name, AutoPWMDefaultOnSP.name))
552 {
553 IUUpdateSwitch(&AutoPWMDefaultOnSP, states, names, n);
554 AutoPWMDefaultOnSP.s = IPS_OK;
555 saveConfig();
556 IDSetSwitch(&AutoPWMDefaultOnSP, nullptr);
557 return true;
558 }
559
560 // Buzzer
561 if(!strcmp(name, BuzzerSP.name))
562 {
563 if(updateSettings("j", "J", 1, (states[0] == ISS_ON) ? "1" : "0"))
564 {
565 BuzzerSP.s = IPS_BUSY;
566 IUUpdateSwitch(&BuzzerSP, states, names, n);
567 IDSetSwitch(&BuzzerSP, nullptr);
568 return true;
569 }
570 BuzzerSP.s = IPS_ALERT;
571 return true;
572 }
573
574 // Manual mode
575 if(!strcmp(name, FocuserManualSP.name))
576 {
577 sprintf(cmd, "F:%s", (strcmp(FocuserManualS[0].name, names[0])) ? "0" : "1");
578 if(sendCommand(cmd, res))
579 {
580 FocuserManualSP.s = IPS_BUSY;
581 IUUpdateSwitch(&FocuserManualSP, states, names, n);
582 IDSetSwitch(&FocuserManualSP, nullptr);
583 return true;
584 }
585 FocuserManualSP.s = IPS_ALERT;
586 return true;
587 }
588
589 // Focuser Mode
590 if(!strcmp(name, FocuserModeSP.name))
591 {
592 std::string value = "0";
593 if(!strcmp(FocuserModeS[FS_MODE_UNI].name, names[0])) value = "0";
594 if(!strcmp(FocuserModeS[FS_MODE_BI].name, names[0])) value = "1";
595 if(!strcmp(FocuserModeS[FS_MODE_MICRO].name, names[0])) value = "2";
596 if(updateSettings("u", "U", U_STEPPER_MODE, value.c_str()))
597 {
598 FocuserModeSP.s = IPS_BUSY;
599 IUUpdateSwitch(&FocuserModeSP, states, names, n);
600 IDSetSwitch(&FocuserModeSP, nullptr);
601 return true;
602 }
603 FocuserModeSP.s = IPS_ALERT;
604 return true;
605 }
606
607 // Focuser compensation mode
608 if(!strcmp(name, FocuserCompModeSP.name))
609 {
610 std::string value = "0";
611 if(!strcmp(FocuserCompModeS[FS_COMP_AUTO].name, names[0])) value = "1";
612 if(updateSettings("e", "E", E_COMP_AUTO, value.c_str()))
613 {
614 FocuserCompModeSP.s = IPS_BUSY;
615 IUUpdateSwitch(&FocuserCompModeSP, states, names, n);
616 IDSetSwitch(&FocuserCompModeSP, nullptr);
617 return true;
618 }
619 FocuserCompModeSP.s = IPS_ALERT;
620 return true;
621 }
622
623 if (strstr(name, "FOCUS"))
624 return FI::processSwitch(dev, name, states, names, n);
625
626 }
627
628 return INDI::DefaultDevice::ISNewSwitch (dev, name, states, names, n);
629}
630
631bool IndiAstrolink4::ISNewText(const char * dev, const char * name, char * texts[], char * names[], int n)
632{
633 if (dev && !strcmp(dev, getDeviceName()))
634 {
635 // Power Labels
636 if (!strcmp(name, PowerControlsLabelsTP.name))
637 {
638 IUUpdateText(&PowerControlsLabelsTP, texts, names, n);
639 PowerControlsLabelsTP.s = IPS_OK;
640 LOG_INFO("Power port labels saved. Driver must be restarted for the labels to take effect.");
641 saveConfig();
642 IDSetText(&PowerControlsLabelsTP, nullptr);
643 return true;
644 }
645 }
646 return INDI::DefaultDevice::ISNewText(dev, name, texts, names, n);
647}
648
649
651{
654
655 IUSaveConfigNumber(fp, &DCFocTimeNP);
656 IUSaveConfigSwitch(fp, &DCFocDirSP);
657 IUSaveConfigText(fp, &PowerControlsLabelsTP);
658 IUSaveConfigSwitch(fp, &AutoPWMDefaultOnSP);
659 return true;
660}
661
665bool IndiAstrolink4::setAutoPWM()
666{
667 char cmd[ASTROLINK4_LEN] = {0}, res[ASTROLINK4_LEN] = {0};
668 bool allOk = true;
669
670 uint8_t valA = (AutoPWMS[0].s == ISS_ON) ? 255 : static_cast<uint8_t>(PWMN[0].value);
671 uint8_t valB = (AutoPWMS[1].s == ISS_ON) ? 255 : static_cast<uint8_t>(PWMN[1].value);
672
673 snprintf(cmd, ASTROLINK4_LEN, "B:0:%d", valA);
674 allOk = allOk && sendCommand(cmd, res);
675 snprintf(cmd, ASTROLINK4_LEN, "B:1:%d", valB);
676 allOk = allOk && sendCommand(cmd, res);
677
678 return allOk;
679}
680
685{
686 int32_t backlash = 0;
687 if(backlashEnabled)
688 {
689 if((targetTicks > FocusAbsPosNP[0].getValue()) == (backlashSteps > 0))
690 {
691 if(((int32_t)targetTicks + backlash) < 0 || (targetTicks + backlash) > FocusMaxPosNP[0].getValue())
692 {
693 backlash = 0;
694 }
695 else
696 {
697 backlash = backlashSteps;
698 requireBacklashReturn = true;
699 }
700 }
701 }
702 char cmd[ASTROLINK4_LEN] = {0}, res[ASTROLINK4_LEN] = {0};
703 snprintf(cmd, ASTROLINK4_LEN, "R:0:%u", targetTicks + backlash);
704 return (sendCommand(cmd, res)) ? IPS_BUSY : IPS_ALERT;
705}
706
708{
709 return MoveAbsFocuser(dir == FOCUS_INWARD ? FocusAbsPosNP[0].getValue() - ticks : FocusAbsPosNP[0].getValue() + ticks);
710}
711
713{
714 char res[ASTROLINK4_LEN] = {0};
715 return (sendCommand("H", res));
716}
717
719{
720 return updateSettings("u", "U", U_REVERSED, (enabled) ? "1" : "0");
721}
722
723bool IndiAstrolink4::SyncFocuser(uint32_t ticks)
724{
725 char cmd[ASTROLINK4_LEN] = {0}, res[ASTROLINK4_LEN] = {0};
726 snprintf(cmd, ASTROLINK4_LEN, "P:0:%u", ticks);
727 return sendCommand(cmd, res);
728}
729
731{
732 if(updateSettings("u", "U", U_MAX_POS, std::to_string(ticks).c_str()))
733 {
734 FocuserSettingsNP.s = IPS_BUSY;
735 return true;
736 }
737 else
738 {
739 return false;
740 }
741}
742
744{
745 backlashSteps = steps;
746 return true;
747}
748
750{
751 backlashEnabled = enabled;
752 return true;
753}
754
758bool IndiAstrolink4::sendCommand(const char * cmd, char * res)
759{
760 int nbytes_read = 0, nbytes_written = 0, tty_rc = 0;
761 char command[ASTROLINK4_LEN];
762
763 if(isSimulation())
764 {
765 if(strcmp(cmd, "#") == 0) sprintf(res, "%s\n", "#:AstroLink4mini");
766 if(strcmp(cmd, "q") == 0) sprintf(res, "%s\n",
767 "q:1234:0:1.47:1:2.12:45.1:-12.81:1:-25.22:45:0:0:0:1:12.1:5.0:1.12:13.41:0:34:0:0");
768 if(strcmp(cmd, "p") == 0) sprintf(res, "%s\n", "p:1234");
769 if(strcmp(cmd, "i") == 0) sprintf(res, "%s\n", "i:0");
770 if(strcmp(cmd, "n") == 0) sprintf(res, "%s\n", "n:1077:14.0:10.0:100");
771 if(strcmp(cmd, "e") == 0) sprintf(res, "%s\n", "e:30:1200:1:0:20");
772 if(strcmp(cmd, "u") == 0) sprintf(res, "%s\n", "u:25000:220:0:100:440:0:0:1:257:0:0:0:0:0:1:0:0");
773 if(strncmp(cmd, "R", 1) == 0) sprintf(res, "%s\n", "R:");
774 if(strncmp(cmd, "C", 1) == 0) sprintf(res, "%s\n", "C:");
775 if(strncmp(cmd, "B", 1) == 0) sprintf(res, "%s\n", "B:");
776 if(strncmp(cmd, "H", 1) == 0) sprintf(res, "%s\n", "H:");
777 if(strncmp(cmd, "P", 1) == 0) sprintf(res, "%s\n", "P:");
778 if(strncmp(cmd, "U", 1) == 0) sprintf(res, "%s\n", "U:");
779 if(strncmp(cmd, "S", 1) == 0) sprintf(res, "%s\n", "S:");
780 if(strncmp(cmd, "G", 1) == 0) sprintf(res, "%s\n", "G:");
781 if(strncmp(cmd, "K", 1) == 0) sprintf(res, "%s\n", "K:");
782 if(strncmp(cmd, "N", 1) == 0) sprintf(res, "%s\n", "N:");
783 if(strncmp(cmd, "E", 1) == 0) sprintf(res, "%s\n", "E:");
784 }
785 else
786 {
787 tcflush(PortFD, TCIOFLUSH);
788 sprintf(command, "%s\n", cmd);
789 LOGF_DEBUG("CMD %s", command);
790 if ( (tty_rc = tty_write_string(PortFD, command, &nbytes_written)) != TTY_OK)
791 return false;
792
793 if (!res)
794 {
795 tcflush(PortFD, TCIOFLUSH);
796 return true;
797 }
798
799 if ( (tty_rc = tty_nread_section(PortFD, res, ASTROLINK4_LEN, stopChar, ASTROLINK4_TIMEOUT, &nbytes_read)) != TTY_OK
800 || nbytes_read == 1)
801 return false;
802
803 tcflush(PortFD, TCIOFLUSH);
804 res[nbytes_read - 1] = '\0';
805 LOGF_DEBUG("RES %s", res);
806
807 if (tty_rc != TTY_OK)
808 {
809 char errorMessage[MAXRBUF];
810 tty_error_msg(tty_rc, errorMessage, MAXRBUF);
811 LOGF_ERROR("Serial error: %s", errorMessage);
812 return false;
813 }
814 }
815 return (cmd[0] == res[0]);
816}
817
821bool IndiAstrolink4::sensorRead()
822{
823 char res[ASTROLINK4_LEN] = {0};
824 if (sendCommand("q", res))
825 {
826 std::vector<std::string> result = split(res, ":");
827
828 float focuserPosition = std::stod(result[Q_STEPPER_POS]);
829 FocusAbsPosNP[0].setValue(focuserPosition);
830 FocusPosMMNP[0].setValue(focuserPosition * FocuserSettingsN[FS_STEP_SIZE].value / 1000.0);
831 float stepsToGo = std::stod(result[Q_STEPS_TO_GO]);
832 if(stepsToGo == 0)
833 {
834 if(requireBacklashReturn)
835 {
836 requireBacklashReturn = false;
837 MoveAbsFocuser(focuserPosition - backlashSteps);
838 }
841 FocusPosMMNP.s = IPS_OK;
843 }
844 else
845 {
848 FocusPosMMNP.s = IPS_BUSY;
849 }
850 IDSetNumber(&FocusPosMMNP, nullptr);
852 PowerDataN[POW_ITOT].value = std::stod(result[Q_CURRENT]);
853
854 if(result.size() > 5)
855 {
856 if(std::stod(result[Q_SENS1_TYPE]) > 0)
857 {
858 setParameterValue("WEATHER_TEMPERATURE", std::stod(result[Q_SENS1_TEMP]));
859 setParameterValue("WEATHER_HUMIDITY", std::stod(result[Q_SENS1_HUM]));
860 setParameterValue("WEATHER_DEWPOINT", std::stod(result[Q_SENS1_DEW]));
863 }
864 else
865 {
867 }
868
869 if(std::stod(result[Q_SENS2_TYPE]) > 0)
870 {
871 Sensor2N[0].value = std::stod(result[Q_SENS2_TEMP]);
872 Sensor2NP.s = IPS_OK;
873 IDSetNumber(&Sensor2NP, nullptr);
874 }
875 else
876 {
877 Sensor2NP.s = IPS_IDLE;
878 }
879
880 PWMN[0].value = std::stod(result[Q_PWM1]);
881 PWMN[1].value = std::stod(result[Q_PWM2]);
882 PWMNP.s = IPS_OK;
883 IDSetNumber(&PWMNP, nullptr);
884
885 bool dcMotorMoving = (std::stod(result[Q_DC_MOVE]) > 0);
886 if(dcMotorMoving)
887 {
888 DCFocTimeNP.s = IPS_BUSY;
889 IDSetNumber(&DCFocTimeNP, nullptr);
890 }
891 else if (DCFocTimeNP.s == IPS_BUSY)
892 {
893 DCFocTimeNP.s = IPS_OK;
894 DCFocAbortSP.s = IPS_IDLE;
895 IDSetNumber(&DCFocTimeNP, nullptr);
896 IDSetSwitch(&DCFocAbortSP, nullptr);
897 }
898
899 if(Power1SP.s != IPS_OK || Power2SP.s != IPS_OK || Power3SP.s != IPS_OK)
900 {
901 Power1S[0].s = (std::stod(result[Q_OUT1]) > 0) ? ISS_ON : ISS_OFF;
902 Power1S[1].s = (std::stod(result[Q_OUT1]) == 0) ? ISS_ON : ISS_OFF;
903 Power1SP.s = IPS_OK;
904 IDSetSwitch(&Power1SP, nullptr);
905 Power2S[0].s = (std::stod(result[Q_OUT2]) > 0) ? ISS_ON : ISS_OFF;
906 Power2S[1].s = (std::stod(result[Q_OUT2]) == 0) ? ISS_ON : ISS_OFF;
907 Power2SP.s = IPS_OK;
908 IDSetSwitch(&Power2SP, nullptr);
909 Power3S[0].s = (std::stod(result[Q_OUT3]) > 0) ? ISS_ON : ISS_OFF;
910 Power3S[1].s = (std::stod(result[Q_OUT3]) == 0) ? ISS_ON : ISS_OFF;
911 Power3SP.s = IPS_OK;
912 IDSetSwitch(&Power3SP, nullptr);
913 }
914
915 CompensationValueN[0].value = std::stod(result[Q_COMP_DIFF]);
916 CompensateNowSP.s = CompensationValueNP.s = (CompensationValueN[0].value > 0) ? IPS_OK : IPS_IDLE;
917 CompensateNowS[0].s = (CompensationValueN[0].value > 0) ? ISS_OFF : ISS_ON;
918 IDSetNumber(&CompensationValueNP, nullptr);
919 IDSetSwitch(&CompensateNowSP, nullptr);
920
921 PowerDataN[POW_VIN].value = std::stod(result[Q_VIN]);
922 PowerDataN[POW_VREG].value = std::stod(result[Q_VREG]);
923 PowerDataN[POW_AH].value = std::stod(result[Q_AH]);
924 PowerDataN[POW_WH].value = std::stod(result[Q_WH]);
925
926 if(strcmp(result[Q_OP_FLAG].c_str(), "0"))
927 {
928 int opFlag = std::stoi(result[Q_OP_FLAG]);
929 LOGF_WARN("Protection triggered, outputs were disabled. Reason: %s was too high, value: %.1f",
930 (opFlag == 1) ? "voltage" : "current", std::stod(result[Q_OP_VALUE]));
931 }
932 }
933
934 PowerDataNP.s = IPS_OK;
935 IDSetNumber(&PowerDataNP, nullptr);
936
937 }
938
939 // update settings data if was changed
940 if(FocuserSettingsNP.s != IPS_OK || FocuserModeSP.s != IPS_OK || PowerDefaultOnSP.s != IPS_OK || BuzzerSP.s != IPS_OK
941 || FocuserCompModeSP.s != IPS_OK)
942 {
943 if (sendCommand("u", res))
944 {
945 std::vector<std::string> result = split(res, ":");
946
947 FocuserModeS[FS_MODE_UNI].s = FocuserModeS[FS_MODE_BI].s = FocuserModeS[FS_MODE_MICRO].s = ISS_OFF;
948 if(!strcmp("0", result[U_STEPPER_MODE].c_str())) FocuserModeS[FS_MODE_UNI].s = ISS_ON;
949 if(!strcmp("1", result[U_STEPPER_MODE].c_str())) FocuserModeS[FS_MODE_BI].s = ISS_ON;
950 if(!strcmp("2", result[U_STEPPER_MODE].c_str())) FocuserModeS[FS_MODE_MICRO].s = ISS_ON;
951 FocuserModeSP.s = IPS_OK;
952 IDSetSwitch(&FocuserModeSP, nullptr);
953
954 PowerDefaultOnS[0].s = (std::stod(result[U_OUT1_DEF]) > 0) ? ISS_ON : ISS_OFF;
955 PowerDefaultOnS[1].s = (std::stod(result[U_OUT2_DEF]) > 0) ? ISS_ON : ISS_OFF;
956 PowerDefaultOnS[2].s = (std::stod(result[U_OUT3_DEF]) > 0) ? ISS_ON : ISS_OFF;
957 PowerDefaultOnSP.s = IPS_OK;
958 IDSetSwitch(&PowerDefaultOnSP, nullptr);
959
960 FocuserSettingsN[FS_SPEED].value = std::stod(result[U_SPEED]);
961 FocuserSettingsN[FS_STEP_SIZE].value = std::stod(result[U_STEPSIZE]) / 100.0;
962 FocusMaxPosNP[0].setValue(std::stod(result[U_MAX_POS]));
963 FocuserSettingsNP.s = IPS_OK;
964 IDSetNumber(&FocuserSettingsNP, nullptr);
966 }
967
968 if(sendCommand("j", res))
969 {
970 std::vector<std::string> result = split(res, ":");
971 BuzzerS[0].s = (std::stod(result[1]) > 0) ? ISS_ON : ISS_OFF;
972 BuzzerSP.s = IPS_OK;
973 IDSetSwitch(&BuzzerSP, nullptr);
974 }
975
976 if (sendCommand("e", res))
977 {
978 std::vector<std::string> result = split(res, ":");
979 FocuserSettingsN[FS_COMPENSATION].value = std::stod(result[E_COMP_STEPS]) / 100.0;
980 FocuserSettingsN[FS_COMP_THRESHOLD].value = std::stod(result[E_COMP_TRGR]);
981 FocuserSettingsNP.s = IPS_OK;
982 IDSetNumber(&FocuserSettingsNP, nullptr);
983
984 FocuserCompModeS[FS_COMP_MANUAL].s = (std::stod(result[E_COMP_AUTO]) == 0) ? ISS_ON : ISS_OFF;
985 FocuserCompModeS[FS_COMP_AUTO].s = (std::stod(result[E_COMP_AUTO]) > 0) ? ISS_ON : ISS_OFF;
986 FocuserCompModeSP.s = IPS_OK;
987 IDSetSwitch(&FocuserCompModeSP, nullptr);
988 }
989 }
990
991 if(FocuserManualSP.s != IPS_OK)
992 {
993 if (sendCommand("f", res))
994 {
995 std::vector<std::string> result = split(res, ":");
996 FocuserManualS[FS_MANUAL_OFF].s = (std::stod(result[1]) == 0) ? ISS_ON : ISS_OFF;
997 FocuserManualS[FS_MANUAL_ON].s = (std::stod(result[1]) > 0) ? ISS_ON : ISS_OFF;
998 FocuserManualSP.s = IPS_OK;
999 IDSetSwitch(&FocuserManualSP, nullptr);
1000 }
1001 }
1002
1003 if(OtherSettingsNP.s != IPS_OK)
1004 {
1005 if (sendCommand("n", res))
1006 {
1007 std::vector<std::string> result = split(res, ":");
1008 OtherSettingsN[SET_AREF_COEFF].value = std::stod(result[N_AREF_COEFF]) / 1000.0;
1009 OtherSettingsN[SET_OVER_TIME].value = std::stod(result[N_OVER_TIME]);
1010 OtherSettingsN[SET_OVER_VOLT].value = std::stod(result[N_OVER_VOLT]) / 10.0;
1011 OtherSettingsN[SET_OVER_AMP].value = std::stod(result[N_OVER_AMP]) / 10.0;
1012 OtherSettingsNP.s = IPS_OK;
1013 IDSetNumber(&OtherSettingsNP, nullptr);
1014 }
1015 }
1016
1017 return true;
1018}
1019
1023std::vector<std::string> IndiAstrolink4::split(const std::string &input, const std::string &regex)
1024{
1025 // passing -1 as the submatch index parameter performs splitting
1026 std::regex re(regex);
1027 std::sregex_token_iterator
1028 first{input.begin(), input.end(), re, -1},
1029 last;
1030 return {first, last};
1031}
1032
1033std::string IndiAstrolink4::doubleToStr(double val)
1034{
1035 char buf[10];
1036 sprintf(buf, "%.0f", val);
1037 return std::string(buf);
1038}
1039
1040bool IndiAstrolink4::updateSettings(const char * getCom, const char * setCom, int index, const char * value)
1041{
1042 std::map<int, std::string> values;
1043 values[index] = value;
1044 return updateSettings(getCom, setCom, values);
1045}
1046
1047bool IndiAstrolink4::updateSettings(const char * getCom, const char * setCom, std::map<int, std::string> values)
1048{
1049 char cmd[ASTROLINK4_LEN] = {0}, res[ASTROLINK4_LEN] = {0};
1050 snprintf(cmd, ASTROLINK4_LEN, "%s", getCom);
1051 if(sendCommand(cmd, res))
1052 {
1053 std::string concatSettings = "";
1054 std::vector<std::string> result = split(res, ":");
1055 if(result.size() >= values.size())
1056 {
1057 result[0] = setCom;
1058 for(std::map<int, std::string>::iterator it = values.begin(); it != values.end(); ++it)
1059 result[it->first] = it->second;
1060
1061 for (const auto &piece : result) concatSettings += piece + ":";
1062 snprintf(cmd, ASTROLINK4_LEN, "%s", concatSettings.c_str());
1063 if(sendCommand(cmd, res)) return true;
1064 }
1065 }
1066 return false;
1067}
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...
void setDefaultPort(const char *port)
setDefaultPort Set default port. Call this function in initProperties() of your driver if you want to...
bool isConnected() const
const char * getDeviceName() const
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void addConfigurationControl()
Add Configuration control to the driver.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
void addSimulationControl()
Add Simulation control to the driver.
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.
bool isSimulation() const
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.
void addDebugControl()
Add Debug control to the driver.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
Provides interface to implement focuser functionality.
INDI::PropertyNumber FocusRelPosNP
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
void initProperties(const char *groupName)
Initialize focuser properties. It is recommended to call this function within initProperties() of you...
INDI::PropertyNumber FocusMaxPosNP
bool saveConfigItems(FILE *fp)
saveConfigItems save focuser properties defined in the interface in config file
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process focus number properties.
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process focus switch properties.
INDI::PropertyNumber FocusAbsPosNP
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
Provides interface to implement weather reporting and safety monitoring functionality.
void addParameter(std::string name, std::string label, double numMinOk, double numMaxOk, double percWarning, bool flipWarning=false)
Add a physical weather measurable parameter to the weather driver.
void setParameterValue(std::string name, double value)
setParameterValue Update weather parameter value
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process weather number properties.
INDI::PropertyNumber ParametersNP
void initProperties(const char *statusGroup, const char *paramsGroup)
Initialize focuser properties. It is recommended to call this function within initProperties() of you...
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Set Focuser Maximum position limit in the hardware.
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
Focuser interface.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool sendCommand(const char *cmd, char *res)
Serial commands.
virtual bool initProperties() override
Overrides.
virtual bool SetFocuserBacklashEnabled(bool enabled) override
SetFocuserBacklashEnabled Enables or disables the focuser backlash compensation.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
IndiAstrolink4()
Constructor.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual const char * getDefaultName() override
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
const char * FOCUS_TAB
FOCUS_TAB Where all the properties for focuser are located.
#define ASTROLINK4_LEN
#define ASTROLINK4_TIMEOUT
#define Q_OUT2
#define Q_CURRENT
#define E_COMP_SENSR
#define Q_DC_MOVE
#define U_REVERSED
#define N_OVER_VOLT
#define Q_SENS2_TYPE
#define E_COMP_CYCLE
#define U_ACC
#define N_OVER_AMP
#define U_STEPSIZE
#define E_COMP_AUTO
#define U_OUT3_DEF
#define Q_WH
#define N_OVER_TIME
#define Q_SENS1_TYPE
#define Q_OP_VALUE
#define Q_AH
#define E_COMP_TRGR
#define U_OUT1_DEF
#define E_COMP_STEPS
#define Q_SENS1_TEMP
#define U_MAX_POS
#define Q_PWM2
#define N_AREF_COEFF
#define U_STEPPER_MODE
#define Q_VIN
#define Q_PWM1
#define U_OUT2_DEF
#define Q_STEPS_TO_GO
#define Q_STEPPER_POS
#define Q_VREG
#define Q_COMP_DIFF
#define Q_OUT3
#define Q_OUT1
#define Q_SENS1_HUM
#define Q_SENS2_TEMP
#define Q_SENS1_DEW
#define Q_OP_FLAG
#define U_SPEED
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
@ IP_WO
Definition indiapi.h:183
IPState
Property state.
Definition indiapi.h:158
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
#define MAXINDILABEL
Definition indiapi.h:190
@ ISR_1OFMANY
Definition indiapi.h:171
@ ISR_NOFMANY
Definition indiapi.h:173
@ ISR_ATMOST1
Definition indiapi.h:172
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition indicom.c:473
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
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
Definition indicom.c:759
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition indidevapi.c:33
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.
Definition indidevapi.c:490
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.
Definition indidevapi.c:509
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition indidevapi.c:23
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.
Definition indidevapi.c:376
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.
Definition indidevapi.c:416
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.
Definition indidevapi.c:398
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition indidevapi.c:28
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.
Definition indidevapi.c:453
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 IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
#define MAXRBUF
Definition indidriver.c:52
int IUGetConfigText(const char *dev, const char *property, const char *member, char *value, int len)
IUGetConfigText Opens configuration file and reads single text property.
Definition indidriver.c:908
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
int IUGetConfigSwitch(const char *dev, const char *property, const char *member, ISState *value)
IUGetConfigSwitch Opens configuration file and reads single switch property.
Definition indidriver.c:657
#define LOGF_WARN(fmt,...)
Definition indilogger.h:81
#define LOG_WARN(txt)
Definition indilogger.h:73
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOG_INFO(txt)
Definition indilogger.h:74
uint8_t cmd[4]
Definition pwc-ioctl.h:2
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369
char name[MAXINDINAME]
Definition indiapi.h:248