Instrument Neutral Distributed Interface INDI  2.0.2
lacerta_mfoc.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2018 Franck Le Rhun. All rights reserved.
3  Copyright(c) 2018 Christian Liska. All rights reserved.
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8  .
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13  .
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 *******************************************************************************/
19 
20 #include "lacerta_mfoc.h"
21 #include "indicom.h"
23 
24 #include <cmath>
25 #include <memory>
26 #include <cstring>
27 #include <unistd.h>
28 
29 // We declare an auto pointer to lacerta_mfoc.
30 static std::unique_ptr<lacerta_mfoc> Lacerta_mfoc(new lacerta_mfoc());
31 
32 // Delay for receiving messages
33 #define FOCUSMFOC_TIMEOUT 1000
34 // According to documentation for v2
35 #define MFOC_POSMAX_HARDWARE 250000
36 #define MFOC_POSMIN_HARDWARE 300
37 
38 /************************************************************************************
39  *
40 ************************************************************************************/
42 {
44 }
45 
46 /************************************************************************************
47  *
48 ************************************************************************************/
50 {
51  return "Lacerta MFOC";
52 }
53 
54 /************************************************************************************
55  *
56 ************************************************************************************/
57 void lacerta_mfoc::ISGetProperties(const char *dev)
58 {
59  if (dev != nullptr && strcmp(dev, getDeviceName()) != 0)
60  return;
61 
63 
64  defineProperty(&TempTrackDirSP);
65  loadConfig(true, TempTrackDirSP.name);
66 
67  defineProperty(&StartSavedPositionSP);
68  loadConfig(true, StartSavedPositionSP.name);
69 }
70 
71 /************************************************************************************
72  *
73 ************************************************************************************/
75 {
77 
78  FocusBacklashN[0].min = 0;
79  FocusBacklashN[0].max = 255;
80  FocusBacklashN[0].step = 1;
81  FocusBacklashN[0].value = 12;
82 
83  // IUFillNumber(&BacklashN[0], "BACKLASH", "step", "%4.2f", 0, 255, 1, 12);
84  // IUFillNumberVector(&BacklashNP, BacklashN, 1, getDeviceName(), "BACKLASH_SETTINGS", "Backlash", MAIN_CONTROL_TAB, IP_RW, 60,
85  // IPS_IDLE);
86 
87  IUFillNumber(&TempCompN[0], "TEMPCOMP", "step/10 degC", "%4.2f", -5000, 5000, 1, 65);
88  IUFillNumberVector(&TempCompNP, TempCompN, 1, getDeviceName(), "TEMPCOMP_SETTINGS", "T Comp.", MAIN_CONTROL_TAB, IP_RW, 60,
89  IPS_IDLE);
90 
93  FocusMaxPosN[0].step = (FocusMaxPosN[0].max - FocusMaxPosN[0].min) / 20.0;
94  FocusMaxPosN[0].value = 110000;
95 
96  FocusAbsPosN[0].min = 0;
97  FocusAbsPosN[0].max = FocusMaxPosN[0].value;
98  FocusAbsPosN[0].step = FocusAbsPosN[0].max / 50.0;
99 
100  IUFillSwitch(&TempTrackDirS[MODE_TDIR_BOTH], "Both", "Both", ISS_ON);
101  IUFillSwitch(&TempTrackDirS[MODE_TDIR_IN], "In", "In", ISS_ON);
102  IUFillSwitch(&TempTrackDirS[MODE_TDIR_OUT], "Out", "Out", ISS_ON);
103  IUFillSwitchVector(&TempTrackDirSP, TempTrackDirS, MODE_COUNT_TEMP_DIR, getDeviceName(), "Temp. dir.", "Temp. dir.",
105  ISR_1OFMANY, 60, IPS_IDLE);
106 
107  IUFillSwitch(&StartSavedPositionS[MODE_SAVED_ON], "Yes", "Yes", ISS_ON);
108  IUFillSwitch(&StartSavedPositionS[MODE_SAVED_OFF], "No", "No", ISS_OFF);
109  IUFillSwitchVector(&StartSavedPositionSP, StartSavedPositionS, MODE_COUNT_SAVED, getDeviceName(), "Start saved pos.",
110  "Start saved pos.", MAIN_CONTROL_TAB, IP_RW,
111  ISR_1OFMANY, 60, IPS_IDLE);
112 
113  return true;
114 }
115 
116 /************************************************************************************
117  *
118 ************************************************************************************/
120 {
121  // Get Initial Position before we define it in the INDI::Focuser class
122  FocusAbsPosN[0].value = GetAbsFocuserPosition();
123 
125 
126  if (isConnected())
127  {
128  //defineProperty(&BacklashNP);
129  defineProperty(&TempCompNP);
130  defineProperty(&TempTrackDirSP);
131  defineProperty(&StartSavedPositionSP);
132 
133  }
134  else
135  {
136  //deleteProperty(BacklashNP.name);
137  deleteProperty(TempCompNP.name);
138  deleteProperty(TempTrackDirSP.name);
139  deleteProperty(StartSavedPositionSP.name);
140  }
141 
142  return true;
143 }
144 
145 /************************************************************************************
146  *
147 ************************************************************************************/
149 {
150  char MFOC_cmd[32] = ": Q #";
151  char MFOC_res[32] = {0};
152  char MFOC_res_type[32] = "0";
153  int MFOC_pos_measd = 0;
154  int nbytes_written = 0;
155  int nbytes_read = 0;
156 
157 
158  tty_write_string(PortFD, MFOC_cmd, &nbytes_written);
159  LOGF_DEBUG("CMD <%s>", MFOC_cmd);
160  tty_read_section(PortFD, MFOC_res, 0xD, FOCUSMFOC_TIMEOUT, &nbytes_read);
161  LOGF_DEBUG("RES <%s>", MFOC_res_type);
162 
163  sscanf(MFOC_res, "%s %d", MFOC_res_type, &MFOC_pos_measd);
164 
165  if (MFOC_res_type[0] == 'P')
166  {
167  FocusAbsPosN[0].value = MFOC_pos_measd;
169  return true;
170  }
171 
172  return false;
173 }
174 
175 /************************************************************************************
176  *
177 ************************************************************************************/
178 bool lacerta_mfoc::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
179 {
180  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
181  {
182  // Temp. Track Direction
183  if (strcmp(TempTrackDirSP.name, name) == 0)
184  {
185  IUUpdateSwitch(&TempTrackDirSP, states, names, n);
186  int tdir = 0;
187  int index = IUFindOnSwitchIndex(&TempTrackDirSP);
188  char MFOC_cmd[32] = ": I ";
189  char MFOC_res[32] = {0};
190  int nbytes_read = 0;
191  int nbytes_written = 0;
192  int MFOC_tdir_measd = 0;
193  char MFOC_res_type[32] = "0";
194 
195  switch (index)
196  {
197  case MODE_TDIR_BOTH:
198  tdir = 0;
199  strcat(MFOC_cmd, "0 #");
200  break;
201 
202  case MODE_TDIR_IN:
203  tdir = 1;
204  strcat(MFOC_cmd, "1 #");
205  break;
206 
207  case MODE_TDIR_OUT:
208  tdir = 2;
209  strcat(MFOC_cmd, "2 #");
210  break;
211 
212  default:
213  TempTrackDirSP.s = IPS_ALERT;
214  IDSetSwitch(&TempTrackDirSP, "Unknown mode index %d", index);
215  return true;
216  }
217 
218 
219  tty_write_string(PortFD, MFOC_cmd, &nbytes_written);
220  LOGF_DEBUG("CMD <%s>", MFOC_cmd);
221  tty_write_string(PortFD, ": W #", &nbytes_written);
222  tty_read_section(PortFD, MFOC_res, 0xD, FOCUSMFOC_TIMEOUT, &nbytes_read);
223  sscanf (MFOC_res, "%s %d", MFOC_res_type, &MFOC_tdir_measd);
224  LOGF_DEBUG("RES <%s>", MFOC_res);
225 
226  if (MFOC_tdir_measd == tdir)
227  {
228  TempTrackDirSP.s = IPS_OK;
229  }
230  else
231  {
232  TempTrackDirSP.s = IPS_ALERT;
233  }
234 
235  IDSetSwitch(&TempTrackDirSP, nullptr);
236  return true;
237  }
238 
239 
240  // Start at saved position
241  if (strcmp(StartSavedPositionSP.name, name) == 0)
242  {
243  IUUpdateSwitch(&StartSavedPositionSP, states, names, n);
244  int svstart = 0;
245  int index = IUFindOnSwitchIndex(&StartSavedPositionSP);
246  char MFOC_cmd[32] = ": F ";
247  char MFOC_res[32] = {0};
248  int nbytes_read = 0;
249  int nbytes_written = 0;
250  int MFOC_svstart_measd = 0;
251  char MFOC_res_type[32] = "0";
252 
253  switch (index)
254  {
255  case MODE_SAVED_ON:
256  svstart = 1;
257  strcat(MFOC_cmd, "1 #");
258  break;
259 
260  case MODE_SAVED_OFF:
261  svstart = 0;
262  strcat(MFOC_cmd, "0 #");
263  break;
264 
265  default:
266  StartSavedPositionSP.s = IPS_ALERT;
267  IDSetSwitch(&StartSavedPositionSP, "Unknown mode index %d", index);
268  return true;
269  }
270 
271  tty_write_string(PortFD, MFOC_cmd, &nbytes_written);
272  LOGF_DEBUG("CMD <%s>", MFOC_cmd);
273  tty_write_string(PortFD, ": N #", &nbytes_written);
274  tty_read_section(PortFD, MFOC_res, 0xD, FOCUSMFOC_TIMEOUT, &nbytes_read);
275  sscanf (MFOC_res, "%s %d", MFOC_res_type, &MFOC_svstart_measd);
276 
277  LOGF_DEBUG("RES <%s>", MFOC_res);
278  // LOGF_DEBUG("Debug MFOC cmd sent %s", MFOC_cmd);
279  if (MFOC_svstart_measd == svstart)
280  {
281  StartSavedPositionSP.s = IPS_OK;
282  }
283  else
284  {
285  StartSavedPositionSP.s = IPS_ALERT;
286  }
287 
288  IDSetSwitch(&StartSavedPositionSP, nullptr);
289  return true;
290  }
291  }
292 
293  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
294 }
295 
296 bool lacerta_mfoc::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
297 {
298  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
299  {
300  // if (strcmp(name, "BACKLASH_SETTINGS") == 0)
301  // {
302  // return SetBacklash(values, names, n);
303  // }
304 
305 
306  if (strcmp(name, "TEMPCOMP_SETTINGS") == 0)
307  {
308  return SetTempComp(values, names, n);
309  }
310  }
311 
312  // Let INDI::Focuser handle any other number properties
313  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
314 }
315 
316 /************************************************************************************
317  *
318 ************************************************************************************/
319 //bool lacerta_mfoc::SetBacklash(double values[], char *names[], int n)
321 {
322  LOGF_DEBUG("-> BACKLASH_SETTINGS", 0);
323  char MFOC_cmd[32] = ": B ";
324  char MFOC_res[32] = {0};
325  int nbytes_read = 0;
326  int nbytes_written = 0;
327  int MFOC_tdir_measd = 0;
328  //int bl_int = 0;
329  char bl_char[32] = {0};
330  char MFOC_res_type[32] = "0";
331  // BacklashNP.s = IPS_OK;
332  // IUUpdateNumber(&BacklashNP, values, names, n);
333  // bl_int = BacklashN[0].value;
334  sprintf(bl_char, "%d", steps);
335  strcat(bl_char, " #");
336  strcat(MFOC_cmd, bl_char);
337 
338  tty_write_string(PortFD, MFOC_cmd, &nbytes_written);
339  LOGF_DEBUG("CMD <%s>", MFOC_cmd);
340  tty_write_string(PortFD, ": J #", &nbytes_written);
341 
342  tty_read_section(PortFD, MFOC_res, 0xD, FOCUSMFOC_TIMEOUT, &nbytes_read);
343 
344  sscanf (MFOC_res, "%s %d", MFOC_res_type, &MFOC_tdir_measd);
345 
346  LOGF_DEBUG("RES <%s>", MFOC_res);
347 
348  //IDSetNumber(&BacklashNP, nullptr);
349 
350  return true;
351 }
352 
353 bool lacerta_mfoc::SetTempComp(double values[], char *names[], int n)
354 {
355  char MFOC_cmd[32] = ": D ";
356  char MFOC_res[32] = {0};
357  int nbytes_read = 0;
358  int nbytes_written = 0;
359  int MFOC_tc_measd = 0;
360  int tc_int = 0;
361  char tc_char[32] = {0};
362  char MFOC_res_type[32] = "0";
363  TempCompNP.s = IPS_OK;
364  IUUpdateNumber(&TempCompNP, values, names, n);
365  tc_int = TempCompN[0].value;
366  sprintf(tc_char, "%d", tc_int);
367  strcat(tc_char, " #");
368  strcat(MFOC_cmd, tc_char);
369 
370  tty_write_string(PortFD, MFOC_cmd, &nbytes_written);
371  LOGF_DEBUG("CMD <%s>", MFOC_cmd);
372  tty_write_string(PortFD, ": U #", &nbytes_written);
373 
374  tty_read_section(PortFD, MFOC_res, 0xD, FOCUSMFOC_TIMEOUT, &nbytes_read);
375 
376  sscanf (MFOC_res, "%s %d", MFOC_res_type, &MFOC_tc_measd);
377 
378  LOGF_DEBUG("RES <%s>", MFOC_res);
379 
380  IDSetNumber(&TempCompNP, nullptr);
381 
382  return true;
383 }
384 
386 {
387  char MFOC_cmd[32] = ": G ";
388  char MFOC_res[32] = {0};
389  int nbytes_read = 0;
390  int nbytes_written = 0;
391  int MFOC_pm_measd = 0;
392  char pm_char[32] = {0};
393  char MFOC_res_type[32] = "0";
394 
395  sprintf(pm_char, "%d", ticks);
396  strcat(pm_char, " #");
397  strcat(MFOC_cmd, pm_char);
398 
399  tty_write_string(PortFD, MFOC_cmd, &nbytes_written);
400  LOGF_DEBUG("CMD <%s>", MFOC_cmd);
401  tty_write_string(PortFD, ": O #", &nbytes_written);
402 
403  tty_read_section(PortFD, MFOC_res, 0xD, FOCUSMFOC_TIMEOUT, &nbytes_read);
404 
405  sscanf (MFOC_res, "%s %d", MFOC_res_type, &MFOC_pm_measd);
406 
407  LOGF_DEBUG("RES <%s>", MFOC_res);
408  return true;
409 }
410 
411 /************************************************************************************
412  *
413 ************************************************************************************/
415 {
416  char MFOC_cmd[32] = ": M ";
417  char abs_pos_char[32] = {0};
418  int nbytes_written = 0;
419 
420  //int pos = GetAbsFocuserPosition();
421  sprintf(abs_pos_char, "%d", targetTicks);
422  strcat(abs_pos_char, " #");
423  strcat(MFOC_cmd, abs_pos_char);
424 
425  tty_write_string(PortFD, MFOC_cmd, &nbytes_written);
426  LOGF_DEBUG("CMD <%s>", MFOC_cmd);
427  FocusAbsPosN[0].value = targetTicks;
428 
429  GetAbsFocuserPosition();
430  return IPS_OK;
431 }
432 
433 /************************************************************************************
434  *
435 ************************************************************************************/
437 {
438  // Calculation of the demand absolute position
439  auto targetTicks = std::clamp(FocusAbsPosN[0].value + (ticks * (dir == FOCUS_INWARD ? -1 : 1)), FocusAbsPosN[0].min, FocusAbsPosN[0].max);
440 
442  IDSetNumber(&FocusAbsPosNP, nullptr);
443 
444  return MoveAbsFocuser(targetTicks);
445 }
446  //Waiting makes no sense - will be immediatly interrupted by the ekos system...
447  //int ticks = std::abs((int)(targetTicks - pos) * FOCUS_MOTION_DELAY);
448  //LOGF_INFO("sleep for %d ms", ticks);
449  //usleep(ticks + 5000);
450 
451 
453 {
454  // Save Focuser Config
456 
457  // Save additional MFPC Config
458  //IUSaveConfigNumber(fp, &BacklashNP);
459  IUSaveConfigNumber(fp, &TempCompNP);
460 
461  return true;
462 }
463 
464 uint32_t lacerta_mfoc::GetAbsFocuserPosition()
465 {
466  char MFOC_cmd[32] = ": Q #";
467  char MFOC_res[32] = {0};
468  char MFOC_res_type[32] = "0";
469  int MFOC_pos_measd = 0;
470 
471  int nbytes_written = 0;
472  int nbytes_read = 0;
473  int count = 0;
474 
475  tty_write_string(PortFD, MFOC_cmd, &nbytes_written);
476  LOGF_DEBUG("CMD <%s>", MFOC_cmd);
477 
478  do
479  {
480  tty_read_section(PortFD, MFOC_res, 0xD, FOCUSMFOC_TIMEOUT, &nbytes_read);
481  sscanf(MFOC_res, "%s %d", MFOC_res_type, &MFOC_pos_measd);
482  count++;
483  }
484  while(strcmp(MFOC_res_type, "P") != 0 && count < 100);
485 
486  LOGF_DEBUG("RES <%s>", MFOC_res_type);
487  LOGF_DEBUG("current position: %d", MFOC_pos_measd);
488 
489  return static_cast<uint32_t>(MFOC_pos_measd);
490 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
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)
INumberVectorProperty FocusAbsPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
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 void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: indifocuser.cpp:95
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.
Definition: indifocuser.cpp:42
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool Handshake() override
perform handshake with device to check communication
const char * getDefaultName() override
void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
double max(void)
double min(void)
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:566
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
Implementations for common driver routines.
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:272
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
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:158
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:180
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:235
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define MFOC_POSMAX_HARDWARE
#define FOCUSMFOC_TIMEOUT
#define MFOC_POSMIN_HARDWARE
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371