Instrument Neutral Distributed Interface INDI  2.0.2
primalucacommandset.cpp
Go to the documentation of this file.
1 /*
2  Primaluca Labs Essato-Arco-Sesto Command Set
3  For USB Control Specification Document Revision 3.3 published 2020.07.08
4 
5  Copyright (C) 2022 Jasem Mutlaq
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 
21  JM 2022.07.16: Major refactor to using json.h and update to Essato Arco
22  Document protocol revision 3.3 (8th July 2022).
23 */
24 
25 #include <cmath>
26 #include <cstring>
27 #include <memory>
28 #include <algorithm>
29 #include <regex>
30 
31 #include <assert.h>
32 #include <termios.h>
33 #include <unistd.h>
34 #include <sys/ioctl.h>
35 
36 #include "primalucacommandset.h"
37 #include "indicom.h"
38 #include "indilogger.h"
39 
40 namespace PrimalucaLabs
41 {
42 
43 std::vector<std::string> split(const std::string &input, const std::string &regex)
44 {
45  // passing -1 as the submatch index parameter performs splitting
46  std::regex re(regex);
47  std::sregex_token_iterator
48  first{input.begin(), input.end(), re, -1},
49  last;
50  return {first, last};
51 }
52 
53 /******************************************************************************************************
54  * Communication
55 *******************************************************************************************************/
56 bool Communication::sendRequest(const json &command, json *response)
57 {
58  int tty_rc = TTY_OK;
59  int nbytes_written = 0, nbytes_read = 0;
60  tcflush(m_PortFD, TCIOFLUSH);
61 
62  std::string output = command.dump();
63  LOGF_DEBUG("<REQ> %s", output.c_str());
64  if ( (tty_rc = tty_write(m_PortFD, output.c_str(), output.length(), &nbytes_written)) != TTY_OK)
65  {
66  char errorMessage[MAXRBUF] = {0};
67  tty_error_msg(tty_rc, errorMessage, MAXRBUF);
68  LOGF_ERROR("Serial write error: %s", errorMessage);
69  return false;
70  }
71 
72  // Should we ignore response?
73  if (response == nullptr)
74  return true;
75 
76  char read_buf[DRIVER_LEN] = {0};
77  if ( (tty_rc = tty_read_section(m_PortFD, read_buf, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read)) != TTY_OK)
78  {
79  char errorMessage[MAXRBUF] = {0};
80  tty_error_msg(tty_rc, errorMessage, MAXRBUF);
81  LOGF_ERROR("Serial write error: %s", errorMessage);
82  return false;
83  }
84 
85  LOGF_DEBUG("<RES> %s", read_buf);
86 
87  try
88  {
89  if (strstr(read_buf, "Error:"))
90  {
91  LOGF_ERROR("Required %s failed: %s", command.dump().c_str(), read_buf);
92  return false;
93  }
94  *response = json::parse(read_buf)["res"];
95  }
96  catch (json::exception &e)
97  {
98  // output exception information
99  LOGF_ERROR("Error parsing device response %s id: %d", e.what(), e.id);
100  return false;
101  }
102 
103  return true;
104 }
105 
106 bool Communication::getStringAsDouble(NodeType type, const std::string &parameter, double &value)
107 {
108  std::string response;
109  if (get(type, parameter, response))
110  {
111  sscanf(response.c_str(), "%lf", &value);
112  return true;
113  }
114  return false;
115 }
116 
117 template <typename T> bool Communication::get(NodeType type, const std::string &parameter, T &value)
118 {
119  std::string node;
120  switch (type)
121  {
122  case MOT_1:
123  node = "MOT1";
124  break;
125  case MOT_2:
126  node = "MOT2";
127  break;
128  default:
129  break;
130  }
131 
132  json jsonRequest = {{parameter, ""}};
133  return genericRequest(node, "get", jsonRequest, &value);
134 }
135 
137 {
138  std::string node;
139  switch (type)
140  {
141  case MOT_1:
142  node = "MOT1";
143  break;
144  case MOT_2:
145  node = "MOT2";
146  break;
147  default:
148  break;
149  }
150 
151  std::string isDone;
152  if (genericRequest(node, "set", value, &isDone))
153  return isDone == "done";
154  return false;
155 }
156 
157 template <typename T> bool Communication::genericRequest(const std::string &node, const std::string &type,
158  const json &command, T *response)
159 {
160  json jsonRequest;
161  if (node.empty())
162  jsonRequest = {{"req", {{type, command}}}};
163  else
164  jsonRequest = {{"req", {{type, {{node, command}}}}}};
165  if (response == nullptr)
166  return sendRequest(jsonRequest);
167  else
168  {
169  json jsonResponse;
170  if (sendRequest(jsonRequest, &jsonResponse))
171  {
172  // There is no command.items().last() so we have to iterate all
173  std::string key;
174  std::string flat = command.flatten().items().begin().key();
175  std::vector<std::string> keys = split(flat, "/");
176  key = keys.back();
177  // for (auto &oneItem : command.items())
178  // key = oneItem.key();
179  try
180  {
181  if (node.empty())
182  {
183  if (jsonResponse[type].contains(key))
184  jsonResponse[type][key].get_to(*response);
185  else if (jsonResponse[type].contains("ERROR"))
186  {
187  std::string error = jsonResponse[type]["ERROR"];
188  LOGF_ERROR("Error: %s", error.c_str());
189  return false;
190  }
191  }
192  else
193  {
194  if (jsonResponse[type][node].contains(key))
195  jsonResponse[type][node][key].get_to(*response);
196  else if (jsonResponse[type][node].contains("ERROR"))
197  {
198  std::string error = jsonResponse[type][node]["ERROR"];
199  LOGF_ERROR("Error: %s", error.c_str());
200  return false;
201  }
202  }
203 
204 
205  }
206  catch (json::exception &e)
207  {
208  // output exception information
209  LOGF_ERROR("Failed Request: %s\nResponse: %s\nException: %s id: %d", jsonRequest.dump().c_str(),
210  jsonResponse.dump().c_str(),
211  e.what(), e.id);
212  return false;
213  }
214  return true;
215  }
216  }
217 
218  return false;
219 }
220 
221 template <typename T> bool Communication::command(NodeType type, const json &jsonCommand)
222 {
223  std::string node;
224  switch (type)
225  {
226  case MOT_1:
227  node = "MOT1";
228  break;
229  case MOT_2:
230  node = "MOT2";
231  break;
232  default:
233  break;
234  }
235  std::string response;
236  if (genericRequest(node, "cmd", jsonCommand, &response))
237  return response == "done";
238  return false;
239 }
240 
241 /******************************************************************************************************
242  * Common Focuser functions between SestoSenso2 & Esatto
243 *******************************************************************************************************/
244 Focuser::Focuser(const std::string &name, int port)
245 {
246  m_Communication.reset(new Communication(name, port));
247 }
248 
249 /******************************************************************************************************
250  *
251 *******************************************************************************************************/
252 bool Focuser::goAbsolutePosition(uint32_t position)
253 {
254  return m_Communication->command(MOT_1, {{"MOVE_ABS", {{"STEP", position}}}});
255 }
256 
257 /******************************************************************************************************
258  *
259 *******************************************************************************************************/
261 {
262  return m_Communication->command(MOT_1, {{"MOT_STOP", ""}});
263 }
264 
265 /******************************************************************************************************
266  *
267 *******************************************************************************************************/
269 {
270  return m_Communication->command(MOT_1, {{"F_OUTW", ""}});
271 }
272 
273 /******************************************************************************************************
274  *
275 *******************************************************************************************************/
277 {
278  return m_Communication->command(MOT_1, {{"F_INW", ""}});
279 }
280 
281 /******************************************************************************************************
282  *
283 *******************************************************************************************************/
284 bool Focuser::getMaxPosition(uint32_t &position)
285 {
286  return m_Communication->get(MOT_1, "CAL_MAXPOS", position);
287 }
288 
289 /******************************************************************************************************
290  *
291 *******************************************************************************************************/
292 bool Focuser::isHallSensorDetected(bool &isDetected)
293 {
294  int detected = 0;
295  if (m_Communication->get(MOT_1, "HSENDET", detected))
296  {
297  isDetected = detected == 1;
298  return true;
299  }
300  return false;
301 }
302 
303 /******************************************************************************************************
304  *
305 *******************************************************************************************************/
306 bool Focuser::getAbsolutePosition(uint32_t &position)
307 {
308  return m_Communication->get(MOT_1, "ABS_POS", position);
309 }
310 
311 /******************************************************************************************************
312  *
313 *******************************************************************************************************/
314 bool Focuser::getCurrentSpeed(uint32_t &speed)
315 {
316  return m_Communication->get(MOT_1, "SPEED", speed);
317 }
318 
319 /******************************************************************************************************
320  *
321 *******************************************************************************************************/
323 {
324  return m_Communication->get(MOT_1, "STATUS", status);
325 }
326 
327 /******************************************************************************************************
328  *
329 *******************************************************************************************************/
331 {
332  json status;
333  if (m_Communication->get(MOT_1, "STATUS", status))
334  {
335  return status["BUSY"] == 1;
336  }
337  return false;
338 }
339 
340 /******************************************************************************************************
341  *
342 *******************************************************************************************************/
343 bool Focuser::getMotorTemp(double &value)
344 {
345  return m_Communication->getStringAsDouble(MOT_1, "NTC_T", value);
346 }
347 
348 /******************************************************************************************************
349  *
350 *******************************************************************************************************/
351 bool Focuser::getExternalTemp(double &value)
352 {
353  return m_Communication->getStringAsDouble(GENERIC_NODE, "EXT_T", value);
354 }
355 
356 /******************************************************************************************************
357  *
358 *******************************************************************************************************/
359 bool Focuser::getSerialNumber(std::string &response)
360 {
361  return m_Communication->get(GENERIC_NODE, "SN", response);
362 }
363 
364 /******************************************************************************************************
365  *
366 *******************************************************************************************************/
367 bool Focuser::getVoltage12v(double &value)
368 {
369  return m_Communication->getStringAsDouble(GENERIC_NODE, "VIN_12V", value);
370 }
371 
372 /******************************************************************************************************
373  *
374 *******************************************************************************************************/
375 bool Focuser::getFirmwareVersion(std::string &response)
376 {
377  json versions;
378  if (m_Communication->get(GENERIC_NODE, "SWVERS", versions))
379  {
380  versions["SWAPP"].get_to(response);
381  return true;
382  }
383  return false;
384 }
385 
386 /******************************************************************************************************
387  *
388 *******************************************************************************************************/
389 bool Focuser::setBacklash(uint32_t steps)
390 {
391  return m_Communication->set(MOT_1, {{"BKLASH", steps}});
392 }
393 
394 /******************************************************************************************************
395  *
396 *******************************************************************************************************/
397 bool Focuser::getBacklash(uint32_t &steps)
398 {
399  return m_Communication->get(MOT_1, "BKLASH", steps);
400 }
401 
402 
403 /******************************************************************************************************
404  * SestoSenso2 functions
405 *******************************************************************************************************/
406 SestoSenso2::SestoSenso2(const std::string &name, int port) : Focuser(name, port) {}
408 {
409  return m_Communication->command(MOT_1, {{"CAL_FOCUSER", "StoreAsMaxPos"}});
410 }
411 
412 /******************************************************************************************************
413  *
414 *******************************************************************************************************/
416 {
417  return m_Communication->command(MOT_1, {{"CAL_FOCUSER", "StoreAsMinPos"}});
418 }
419 
420 /******************************************************************************************************
421  *
422 *******************************************************************************************************/
424 {
425  return m_Communication->command(MOT_1, {{"CAL_FOCUSER", "GoOutToFindMaxPos"}});
426 }
427 
428 /******************************************************************************************************
429  *
430 *******************************************************************************************************/
432 {
433  return m_Communication->command(MOT_1, {{"CAL_FOCUSER", "Init"}});
434 }
435 
436 /******************************************************************************************************
437  *
438 *******************************************************************************************************/
439 bool SestoSenso2::applyMotorPreset(const std::string &name)
440 {
441  return m_Communication->command(GENERIC_NODE, {{"RUNPRESET", name}});
442 }
443 
444 /******************************************************************************************************
445  *
446 *******************************************************************************************************/
447 bool SestoSenso2::setMotorUserPreset(uint32_t index, const MotorRates &rates, const MotorCurrents &currents)
448 {
449  auto name = std::string("RUNPRESET_") + std::to_string(index);
450  auto user = std::string("user_") + std::to_string(index);
451 
452  json preset = {{"RP_NAME", user},
453  {"M1ACC", rates.accRate},
454  {"M1DEC", rates.decRate},
455  {"M1SPD", rates.runSpeed},
456  {"M1CACC", currents.accCurrent},
457  {"M1CDEC", currents.decCurrent},
458  {"M1CSPD", currents.runCurrent},
459  {"M1CHOLD", currents.holdCurrent}
460  };
461 
462  return m_Communication->set(MOT_1, {{name, preset}});
463 }
464 
465 /******************************************************************************************************
466  *
467 *******************************************************************************************************/
468 bool SestoSenso2::getMotorSettings(MotorRates &rates, MotorCurrents &currents, bool &motorHoldActive)
469 {
470  json jsonRequest = {{"req", {{"get", {{"MOT1", { {"FnRUN_ACC", ""},
471  {"FnRUN_DEC", ""}, {"FnRUN_SPD", ""}, {"FnRUN_CURR_ACC", ""},
472  {"FnRUN_CURR_DEC", ""}, {"FnRUN_CURR_SPD", ""}, {"FnRUN_CURR_HOLD", ""}, {"HOLDCURR_STATUS", ""}
473  }
474  }
475  }
476  }
477  }
478  }
479  };
480  json jsonResponse;
481 
482  if (m_Communication->sendRequest(jsonRequest, &jsonResponse))
483  {
484  jsonResponse["get"]["MOT1"]["FnRUN_ACC"].get_to(rates.accRate);
485  jsonResponse["get"]["MOT1"]["FnRUN_DEC"].get_to(rates.decRate);
486  jsonResponse["get"]["MOT1"]["FnRUN_SPD"].get_to(rates.runSpeed);
487 
488  jsonResponse["get"]["MOT1"]["FnRUN_CURR_ACC"].get_to(currents.accCurrent);
489  jsonResponse["get"]["MOT1"]["FnRUN_CURR_DEC"].get_to(currents.decCurrent);
490  jsonResponse["get"]["MOT1"]["FnRUN_CURR_SPD"].get_to(currents.runCurrent);
491  jsonResponse["get"]["MOT1"]["FnRUN_CURR_HOLD"].get_to(currents.holdCurrent);
492 
493  int status = 0;
494  jsonResponse["get"]["MOT1"]["HOLDCURR_STATUS"].get_to(status);
495  motorHoldActive = ( status == 1 );
496  return true;
497  }
498  return false;
499 }
500 
501 /******************************************************************************************************
502  *
503 *******************************************************************************************************/
505 {
506  json jsonRates =
507  {
508  {"FnRUN_ACC", rates.accRate},
509  {"FnRUN_ACC", rates.accRate},
510  {"FnRUN_ACC", rates.accRate},
511  };
512 
513  return m_Communication->set(MOT_1, jsonRates);
514 }
515 
516 /******************************************************************************************************
517  *
518 *******************************************************************************************************/
520 {
521  json jsonRates =
522  {
523  {"FnRUN_CURR_ACC", currents.accCurrent},
524  {"FnRUN_CURR_DEC", currents.decCurrent},
525  {"FnRUN_CURR_SPD", currents.runCurrent},
526  {"FnRUN_CURR_HOLD", currents.holdCurrent},
527  };
528 
529  return m_Communication->set(MOT_1, jsonRates);
530 }
531 
532 /******************************************************************************************************
533  *
534 *******************************************************************************************************/
536 {
537  return m_Communication->set(MOT_1, {{"HOLDCURR_STATUS", hold ? 1 : 0}});
538 }
539 
540 /******************************************************************************************************
541  * Esatto functions
542 *******************************************************************************************************/
543 Esatto::Esatto(const std::string &name, int port) : Focuser(name, port) {}
544 bool Esatto::setBacklash(uint32_t steps)
545 {
546  return m_Communication->set(MOT_1, {{"BKLASH", steps}});
547 }
548 
549 /******************************************************************************************************
550  *
551 *******************************************************************************************************/
552 bool Esatto::getBacklash(uint32_t &steps)
553 {
554  return m_Communication->get(MOT_1, "BKLASH", steps);
555 }
556 
557 /******************************************************************************************************
558  *
559 *******************************************************************************************************/
560 bool Esatto::getVoltageUSB(double &value)
561 {
562  return m_Communication->getStringAsDouble(GENERIC_NODE, "VIN_USB", value);
563 }
564 
565 /******************************************************************************************************
566  * Arco
567 *******************************************************************************************************/
568 Arco::Arco(const std::string &name, int port)
569 {
570  m_Communication.reset(new Communication(name, port));
571 }
572 
573 /******************************************************************************************************
574  *
575 *******************************************************************************************************/
576 bool Arco::setEnabled(bool enabled)
577 {
578  return m_Communication->set(GENERIC_NODE, {{"ARCO", enabled ? 1 : 0}});
579 }
580 
581 /******************************************************************************************************
582  *
583 *******************************************************************************************************/
585 {
586  int enabled = 0;
587  if (m_Communication->get(GENERIC_NODE, "ARCO", enabled))
588  return enabled == 1;
589  return false;
590 }
591 
592 /******************************************************************************************************
593  *
594 *******************************************************************************************************/
595 bool Arco::getAbsolutePosition(Units unit, double &value)
596 {
597  json command;
598  switch (unit)
599  {
600  case UNIT_DEGREES:
601  command = {{"POSITION_DEG", ""}};
602  break;
603  case UNIT_ARCSECS:
604  command = {{"POSITION_ARCSEC", ""}};
605  break;
606  case UNIT_STEPS:
607  command = {{"POSITION_STEP", ""}};
608  break;
609  }
610 
611  return m_Communication->genericRequest("MOT2", "get", command, &value);
612 }
613 
614 /******************************************************************************************************
615  *
616 *******************************************************************************************************/
617 bool Arco::moveAbsolutePoition(Units unit, double value)
618 {
619  json command;
620  switch (unit)
621  {
622  case UNIT_DEGREES:
623  command = {{"MOVE_ABS", {{"DEG", value}}}};
624  break;
625  case UNIT_ARCSECS:
626  command = {{"MOVE_ABS", {{"ARCSEC", value}}}};
627  break;
628  case UNIT_STEPS:
629  command = {{"MOVE_ABS", {{"STEP", static_cast<int>(value)}}}};
630  break;
631  }
632 
633  return m_Communication->command(MOT_2, command);
634 }
635 
636 /******************************************************************************************************
637  *
638 *******************************************************************************************************/
639 bool Arco::sync(Units unit, double value)
640 {
641  json command;
642  switch (unit)
643  {
644  case UNIT_DEGREES:
645  command = {{"SYNC_POS", {{"DEG", value}}}};
646  break;
647  case UNIT_ARCSECS:
648  command = {{"SYNC_POS", {{"ARCSEC", value}}}};
649  break;
650  case UNIT_STEPS:
651  command = {{"SYNC_POS", {{"STEP", static_cast<int>(value)}}}};
652  break;
653  }
654 
655  return m_Communication->command(MOT_2, command);
656 }
657 
658 /******************************************************************************************************
659  *
660 *******************************************************************************************************/
662 {
663  json status;
664  if (m_Communication->get(MOT_2, "STATUS", status))
665  {
666  return status["BUSY"] == 1;
667  }
668  return false;
669 }
670 
671 /******************************************************************************************************
672  *
673 *******************************************************************************************************/
674 bool Arco::getStatus(json &status)
675 {
676  return m_Communication->get(MOT_2, "STATUS", status);
677 }
678 
679 /******************************************************************************************************
680  *
681 *******************************************************************************************************/
683 {
684  return m_Communication->command(MOT_2, {{"MOT_STOP", ""}});
685 }
686 
687 /******************************************************************************************************
688  *
689 *******************************************************************************************************/
691 {
692  return m_Communication->set(MOT_2, {{"CAL_STATUS", "exec"}});
693 }
694 
695 /******************************************************************************************************
696  *
697 *******************************************************************************************************/
699 {
700  std::string value;
701  if (m_Communication->get(MOT_2, "CAL_STATUS", value))
702  {
703  return value == "exec";
704  }
705  return false;
706 }
707 
708 /******************************************************************************************************
709  *
710 *******************************************************************************************************/
711 bool Arco::reverse(bool enabled)
712 {
713  return m_Communication->set(MOT_2, {{"REVERSE", enabled ? 1 : 0}});
714 }
715 
716 /******************************************************************************************************
717  *
718 *******************************************************************************************************/
720 {
721  int value;
722  if (m_Communication->get(MOT_2, "REVERSE", value))
723  {
724  return value == 1;
725  }
726  return false;
727 }
728 
729 /******************************************************************************************************
730  *
731 *******************************************************************************************************/
732 bool Arco::getSerialNumber(std::string &response)
733 {
734  return m_Communication->get(GENERIC_NODE, "ARCO_SN", response);
735 }
736 
737 /******************************************************************************************************
738  *
739 *******************************************************************************************************/
740 bool Arco::getFirmwareVersion(std::string &response)
741 {
742  // JM 2022.07.22: Apparently not possible now in protocol.
743  response = "NA";
744  return true;
745 }
746 
747 /******************************************************************************************************
748  *
749 *******************************************************************************************************/
751 {
752  json jsonRequest = {{"req", {{"get", {{"MOT2", ""}}}}}};
753  return m_Communication->sendRequest(jsonRequest, &info);
754 }
755 
756 /******************************************************************************************************
757  * GIOTTO
758 *******************************************************************************************************/
759 GIOTTO::GIOTTO(const std::string &name, int port)
760 {
761  m_Communication.reset(new Communication(name, port));
762 }
763 
764 /******************************************************************************************************
765  *
766 *******************************************************************************************************/
767 bool GIOTTO::setLightEnabled(bool enabled)
768 {
769  json jsonRequest = {{"req", {{"set", {{"LIGHT", enabled ? 1 : 0}}}}}};
770  return m_Communication->sendRequest(jsonRequest);
771 }
772 
773 
774 /******************************************************************************************************
775  *
776 *******************************************************************************************************/
778 {
779  int value;
780  if (m_Communication->get(GENERIC_NODE, "LIGHT", value))
781  {
782  return value == 1;
783  }
784  return false;
785 }
786 /******************************************************************************************************
787  *
788 *******************************************************************************************************/
789 bool GIOTTO::getMaxBrightness(uint16_t &value)
790 {
791  return m_Communication->get(GENERIC_NODE, "MAX_BRIGHTNESS", value);
792 }
793 
794 /******************************************************************************************************
795  *
796 *******************************************************************************************************/
797 bool GIOTTO::setBrightness(uint16_t value)
798 {
799  return m_Communication->set(GENERIC_NODE, {{"BRIGHTNESS", value}});
800 }
801 
802 /******************************************************************************************************
803  *
804 *******************************************************************************************************/
805 bool GIOTTO::getBrightness(uint16_t &value)
806 {
807  return m_Communication->get(GENERIC_NODE, "BRIGHTNESS", value);
808 }
809 
810 /******************************************************************************************************
811  *
812 *******************************************************************************************************/
813 ALTO::ALTO(const std::string &name, int port)
814 {
815  m_Communication.reset(new Communication(name, port));
816 }
817 
818 
819 /******************************************************************************************************
820  *
821 *******************************************************************************************************/
822 bool ALTO::getModel(std::string &model)
823 {
824  return m_Communication->get(GENERIC_NODE, "MODNAME", model);
825 }
826 
827 /******************************************************************************************************
828  *
829 *******************************************************************************************************/
830 bool ALTO::getStatus(json &status)
831 {
832  return m_Communication->get(MOT_1, "STATUS", status);
833 }
834 
835 /******************************************************************************************************
836  *
837 *******************************************************************************************************/
839 {
840  return setPosition(0);
841 }
842 
843 /******************************************************************************************************
844  *
845 *******************************************************************************************************/
847 {
848  return setPosition(100);
849 }
850 
851 /******************************************************************************************************
852  *
853 *******************************************************************************************************/
854 bool ALTO::setPosition(uint8_t value)
855 {
856  return m_Communication->set(MOT_1, {{"POSITION", value}});
857 }
858 
859 /******************************************************************************************************
860  *
861 *******************************************************************************************************/
863 {
864  return m_Communication->command(MOT_1, {{"MOT_STOP", ""}});
865 }
866 
867 /******************************************************************************************************
868  *
869 *******************************************************************************************************/
871 {
872  return m_Communication->command(MOT_1, {{"CAL_ALTO", "Init"}});
873 }
874 
875 /******************************************************************************************************
876  *
877 *******************************************************************************************************/
878 bool ALTO::close(bool fast)
879 {
880  return m_Communication->command(MOT_1, {{"CAL_ALTO", fast ? "Open_Fast" : "Open_Slow"}});
881 }
882 
883 /******************************************************************************************************
884  *
885 *******************************************************************************************************/
886 bool ALTO::open(bool fast)
887 {
888  return m_Communication->command(MOT_1, {{"CAL_ALTO", fast ? "Close_Fast" : "Close_Slow"}});
889 }
890 
891 /******************************************************************************************************
892  *
893 *******************************************************************************************************/
895 {
896  return m_Communication->command(MOT_1, {{"CAL_ALTO", "StoreAsClosedPos"}});
897 }
898 
899 /******************************************************************************************************
900  *
901 *******************************************************************************************************/
903 {
904  return m_Communication->command(MOT_1, {{"CAL_ALTO", "StoreAsMaxOpenPos"}});
905 }
906 
907 }
bool close(bool fast=false)
bool getModel(std::string &model)
ALTO(const std::string &name, int port)
bool setPosition(uint8_t value)
bool open(bool fast=false)
bool getStatus(json &status)
bool setEnabled(bool enabled)
bool getStatus(json &status)
bool getMotorInfo(json &info)
bool moveAbsolutePoition(Units unit, double value)
Arco(const std::string &name, int port)
bool sync(Units unit, double value)
bool getSerialNumber(std::string &response)
bool getAbsolutePosition(Units unit, double &value)
bool reverse(bool enabled)
bool getFirmwareVersion(std::string &response)
bool command(NodeType type, const json &jsonCommand)
bool genericRequest(const std::string &node, const std::string &type, const json &command, T *response=nullptr)
bool sendRequest(const json &command, json *response=nullptr)
bool getStringAsDouble(NodeType type, const std::string &parameter, double &value)
getStringAsDouble Same as get, but it receives a string and scan it for double.
bool get(NodeType type, const std::string &parameter, T &value)
bool set(NodeType type, const json &value)
bool setBacklash(uint32_t steps)
Esatto(const std::string &name, int port)
bool getBacklash(uint32_t &steps)
bool getVoltageUSB(double &value)
bool getVoltage12v(double &value)
std::unique_ptr< Communication > m_Communication
bool getAbsolutePosition(uint32_t &position)
bool getExternalTemp(double &value)
bool isHallSensorDetected(bool &isDetected)
bool getSerialNumber(std::string &response)
Focuser(const std::string &name, int port)
bool getFirmwareVersion(std::string &response)
bool setBacklash(uint32_t steps)
bool getCurrentSpeed(uint32_t &speed)
bool getMotorTemp(double &value)
bool getMaxPosition(uint32_t &position)
bool getStatus(json &status)
bool getBacklash(uint32_t &steps)
bool goAbsolutePosition(uint32_t position)
GIOTTO(const std::string &name, int port)
bool getMaxBrightness(uint16_t &value)
bool setLightEnabled(bool enabled)
bool getBrightness(uint16_t &value)
bool setBrightness(uint16_t value)
bool getMotorSettings(struct MotorRates &rates, struct MotorCurrents &currents, bool &motorHoldActive)
bool setMotorCurrents(const MotorCurrents &currents)
bool applyMotorPreset(const std::string &name)
SestoSenso2(const std::string &name, int port)
bool setMotorUserPreset(uint32_t index, const MotorRates &rates, const MotorCurrents &currents)
bool setMotorRates(const MotorRates &rates)
a class to store JSON values
Definition: json.h:18647
string_t dump(const int indent=-1, const char indent_char=' ', const bool ensure_ascii=false, const error_handler_t error_handler=error_handler_t::strict) const
serialization
Definition: json.h:19810
ValueType & get_to(ValueType &v) const noexcept(noexcept(JSONSerializer< ValueType >::from_json(std::declval< const basic_json_t & >(), v)))
get a value (explicit)
Definition: json.h:20336
general exception of the basic_json class
Definition: json.h:4032
const char * what() const noexcept override
returns the explanatory string
Definition: json.h:4035
const int id
the id of the exception
Definition: json.h:4041
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(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define MAXRBUF
Definition: indiserver.cpp:102
std::vector< std::string > split(const std::string &input, const std::string &regex)
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.h:23613
__le16 type
Definition: pwc-ioctl.h:0