Instrument Neutral Distributed Interface INDI  2.0.2
alto.cpp
Go to the documentation of this file.
1 /*
2  ALTO driver
3  Copyright (C) 2023 Jasem Mutlaq
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
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  Lesser General Public License for more details.
12  You should have received a copy of the GNU Lesser General Public
13  License along with this library; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15 */
16 
17 #include "alto.h"
18 
19 #include <memory>
20 #include <unistd.h>
22 
23 static std::unique_ptr<ALTO> sesto(new ALTO());
24 
26 {
27  setVersion(1, 0);
28 }
29 
34 {
35 
37 
39 
41 
43 
44  // Calibrate Toggle
45  CalibrateToggleSP[INDI_ENABLED].fill("INDI_ENABLED", "Start", ISS_OFF);
46  CalibrateToggleSP[INDI_DISABLED].fill("INDI_DISABLED", "Stop", ISS_OFF);
47  CalibrateToggleSP.fill(getDeviceName(), "CALIBRATE_TOGGLE", "Calibrate", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60,
48  IPS_IDLE);
49 
50  // Calibrate Speed
51  MotionSpeedSP[Slow].fill("SLOW", "Slow", ISS_OFF);
52  MotionSpeedSP[Fast].fill("FAST", "Fast", ISS_ON);
53  MotionSpeedSP.fill(getDeviceName(), "MOTION_SPEED", "Speed", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
54 
55  // Calibrate Command
56  MotionCommandSP[Open].fill("OPEN", "Open", ISS_OFF);
57  MotionCommandSP[Close].fill("CLOSE", "Close", ISS_OFF);
58  MotionCommandSP[Stop].fill("STOP", "Stop", ISS_OFF);
59  MotionCommandSP.fill(getDeviceName(), "MOTION_COMMAND", "Command", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
60 
61  serialConnection = new Connection::Serial(this);
63  serialConnection->registerHandshake([&]()
64  {
65  return Handshake();
66  });
67  registerConnection(serialConnection);
68 
69  return true;
70 }
71 
76 {
78 
79  if (isConnected())
80  {
82  defineProperty(MotionSpeedSP);
83  defineProperty(MotionCommandSP);
84  defineProperty(CalibrateToggleSP);
85  }
86  else
87  {
89  deleteProperty(MotionSpeedSP);
90  deleteProperty(MotionCommandSP);
91  deleteProperty(CalibrateToggleSP);
92  }
93 
94  return true;
95 }
96 
101 {
102  PortFD = serialConnection->getPortFD();
103  m_ALTO.reset(new PrimalucaLabs::ALTO(getDeviceName(), PortFD));
104  std::string model;
105  if (m_ALTO->getModel(model))
106  {
107  LOGF_INFO("%s is online. Detected model %s", getDeviceName(), model.c_str());
108  return true;
109  }
110 
111  LOG_INFO("Error retrieving data from device, please ensure ALTO is powered and the port is correct.");
112  return false;
113 }
114 
115 
119 const char *ALTO::getDefaultName()
120 {
121  return "ALTO";
122 }
123 
127 bool ALTO::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
128 {
129  return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
130 }
131 
135 bool ALTO::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
136 {
137  if (processDustCapSwitch(dev, name, states, names, n))
138  return true;
139 
140  // Motion Speed
141  if (MotionSpeedSP.isNameMatch(name))
142  {
143  MotionSpeedSP.update(states, names, n);
144  MotionSpeedSP.setState(IPS_OK);
145  MotionSpeedSP.apply();
146  saveConfig(true, MotionSpeedSP.getName());
147  return true;
148  }
149 
150  // Motion Command
151  if (MotionCommandSP.isNameMatch(name))
152  {
153  MotionCommandSP.update(states, names, n);
154  auto command = MotionCommandSP.findOnSwitchIndex();
155  auto rc = false;
156  switch (command)
157  {
158  case Open:
159  rc = m_ALTO->open(MotionSpeedSP[Fast].getState() == ISS_ON);
160  break;
161  case Close:
162  rc = m_ALTO->close(MotionSpeedSP[Fast].getState() == ISS_ON);
163  break;
164  case Stop:
165  rc = m_ALTO->stop();
166  if (m_CalibrationStatus == findClosePosition)
167  {
168  m_ALTO->storeClosedPosition();
169  LOG_INFO("Close position recorded. Open cover to maximum position then click stop.");
170  m_CalibrationStatus = findOpenPosition;
171  }
172  else if (m_CalibrationStatus == findOpenPosition)
173  {
174  m_ALTO->storeOpenPosition();
175  LOG_INFO("Open position recorded. Calibration completed.");
176  m_CalibrationStatus = Idle;
177  CalibrateToggleSP.reset();
178  CalibrateToggleSP.setState(IPS_IDLE);
179  CalibrateToggleSP.apply();
180  }
181  break;
182  }
183 
184 
185  MotionCommandSP.reset();
186  MotionCommandSP.setState(rc ? (command == Stop ? IPS_IDLE : IPS_BUSY) : IPS_ALERT);
187  MotionCommandSP.apply();
188  return true;
189  }
190 
191  // Calibrate
192  if (CalibrateToggleSP.isNameMatch(name))
193  {
194  CalibrateToggleSP.update(states, names, n);
195  auto isToggled = CalibrateToggleSP[INDI_ENABLED].getState() == ISS_ON;
196  CalibrateToggleSP.setState(isToggled ? IPS_BUSY : IPS_IDLE);
197 
198  if (isToggled)
199  {
200  m_ALTO->initCalibration();
201  m_CalibrationStatus = findClosePosition;
202  LOG_INFO("Calibration started. Close cover to minimum position then click stop.");
203  }
204  else
205  {
206  m_CalibrationStatus = Idle;
207  LOG_INFO("Calibration complete.");
208  }
209 
210  CalibrateToggleSP.apply();
211  return true;
212  }
213 
214  return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n);
215 }
216 
221 {
222  return m_ALTO->Park() ? IPS_BUSY : IPS_ALERT;
223 }
224 
229 {
230  return m_ALTO->UnPark() ? IPS_BUSY : IPS_ALERT;
231 }
232 
236 bool ALTO::saveConfigItems(FILE * fp)
237 {
238  MotionSpeedSP.save(fp);
240 }
241 
246 {
247  if (ParkCapSP.s == IPS_BUSY)
248  {
249  json status;
250  try
251  {
252  m_ALTO->getStatus(status);
253  std::string mst = status["MST"];
254  if (mst == "stop")
255  {
256  ParkCapSP.s = IPS_OK;
257  IDSetSwitch(&ParkCapSP, nullptr);
258  }
259  }
260  catch (json::exception &e)
261  {
262  LOGF_ERROR("%s %d", e.what(), e.id);
263  }
264  }
265 
267 }
Definition: alto.h:24
bool Handshake()
Definition: alto.cpp:100
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: alto.cpp:75
ALTO()
Definition: alto.cpp:25
virtual IPState ParkCap() override
Park dust cap (close cover). Must be implemented by child.
Definition: alto.cpp:220
const char * getDefaultName() override
Definition: alto.cpp:119
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: alto.cpp:245
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: alto.cpp:127
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: alto.cpp:135
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: alto.cpp:236
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: alto.cpp:33
virtual IPState UnParkCap() override
unPark dust cap (open cover). Must be implemented by child.
Definition: alto.cpp:228
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the intial connection to the device...
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...
Provides interface to implement remotely controlled dust cover.
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
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.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
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()
Initilize properties initial state and value. The child class must implement this function.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void initDustCapProperties(const char *deviceName, const char *groupName)
Initilize dust cap properties. It is recommended to call this function within initProperties() of you...
bool processDustCapSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process dust cap switch properties.
ISwitchVectorProperty ParkCapSP
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
IPState getState() const
const char * getName() const
bool isNameMatch(const char *otherName) const
bool update(const ISState states[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
a class to store JSON values
Definition: json.h:18647
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
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
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
@ ISR_ATMOST1
Definition: indiapi.h:174
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
char name[MAXINDINAME]
Definition: indiapi.h:371