Instrument Neutral Distributed Interface INDI 2.2.5
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
23static 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 // Position
62 PositionNP[0].fill("POSITION", "Steps", "%.f", 0, 100, 10, 0);
63 PositionNP.fill(getDeviceName(), "POSITION_STEPS", "Position", MAIN_CONTROL_TAB, IP_RW, 60, IPS_IDLE);
64
65 serialConnection = new Connection::Serial(this);
67 serialConnection->registerHandshake([&]()
68 {
69 return Handshake();
70 });
71 registerConnection(serialConnection);
72
73 return true;
74}
75
80{
82
83 if (isConnected())
84 {
85 // Check parking status
86 uint8_t value = 0;
87 try
88 {
89 if (m_ALTO->getPosition(value))
90 {
91 ParkCapSP[CAP_PARK].setState(value == 0 ? ISS_ON : ISS_OFF);
93 PositionNP[0].value = value;
94 }
95 }
96 catch (json::exception &e)
97 {
98 LOGF_ERROR("%s %d", e.what(), e.id);
99 }
100
101 defineProperty(PositionNP);
102 defineProperty(MotionSpeedSP);
103 defineProperty(MotionCommandSP);
104 defineProperty(CalibrateToggleSP);
105 }
106 else
107 {
108 deleteProperty(PositionNP);
109 deleteProperty(MotionSpeedSP);
110 deleteProperty(MotionCommandSP);
111 deleteProperty(CalibrateToggleSP);
112 }
113
115
116 return true;
117}
118
123{
124 PortFD = serialConnection->getPortFD();
125 m_ALTO.reset(new PrimalucaLabs::ALTO(getDeviceName(), PortFD));
126 std::string model;
127 if (m_ALTO->getModel(model))
128 {
129 LOGF_INFO("%s is online. Detected model %s", getDeviceName(), model.c_str());
130 return true;
131 }
132
133 LOG_INFO("Error retrieving data from device, please ensure ALTO is powered and the port is correct.");
134 return false;
135}
136
137
142{
143 return "ALTO";
144}
145
149bool ALTO::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
150{
151 // Position
152 if (PositionNP.isNameMatch(name))
153 {
154 m_TargetPosition = values[0];
155
156 try
157 {
158 auto rc = m_ALTO->setPosition(m_TargetPosition);
159 PositionNP.setState(rc ? IPS_BUSY : IPS_ALERT);
160 PositionNP.apply();
161 }
162 catch (json::exception &e)
163 {
164 LOGF_ERROR("%s %d", e.what(), e.id);
165 }
166
167 return true;
168 }
169
170 return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
171}
172
176bool ALTO::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
177{
178 if (DI::processSwitch(dev, name, states, names, n))
179 return true;
180
181 // Motion Speed
182 if (MotionSpeedSP.isNameMatch(name))
183 {
184 MotionSpeedSP.update(states, names, n);
185 MotionSpeedSP.setState(IPS_OK);
186 MotionSpeedSP.apply();
187 saveConfig(true, MotionSpeedSP.getName());
188 return true;
189 }
190
191 // Motion Command
192 if (MotionCommandSP.isNameMatch(name))
193 {
194 MotionCommandSP.update(states, names, n);
195 auto command = MotionCommandSP.findOnSwitchIndex();
196 auto rc = false;
197 switch (command)
198 {
199 case Open:
200 rc = m_ALTO->open(MotionSpeedSP[Fast].getState() == ISS_ON);
201 break;
202 case Close:
203 rc = m_ALTO->close(MotionSpeedSP[Fast].getState() == ISS_ON);
204 break;
205 case Stop:
206 rc = m_ALTO->stop();
207 if (m_CalibrationStatus == findClosePosition)
208 {
209 m_ALTO->storeClosedPosition();
210 LOG_INFO("Close position recorded. Open cover to maximum position then click stop.");
211 m_CalibrationStatus = findOpenPosition;
212 }
213 else if (m_CalibrationStatus == findOpenPosition)
214 {
215 m_ALTO->storeOpenPosition();
216 LOG_INFO("Open position recorded. Calibration completed.");
217 m_CalibrationStatus = Idle;
218 CalibrateToggleSP.reset();
219 CalibrateToggleSP.setState(IPS_IDLE);
220 CalibrateToggleSP.apply();
221 }
222 break;
223 }
224
225 MotionCommandSP.reset();
226 MotionCommandSP.setState(rc ? (command == Stop ? IPS_IDLE : IPS_BUSY) : IPS_ALERT);
227 MotionCommandSP.apply();
228 return true;
229 }
230
231 // Calibrate
232 if (CalibrateToggleSP.isNameMatch(name))
233 {
234 CalibrateToggleSP.update(states, names, n);
235 auto isToggled = CalibrateToggleSP[INDI_ENABLED].getState() == ISS_ON;
236 CalibrateToggleSP.setState(isToggled ? IPS_BUSY : IPS_IDLE);
237
238 if (isToggled)
239 {
240 m_ALTO->initCalibration();
241 m_CalibrationStatus = findClosePosition;
242 LOG_INFO("Calibration started. Close cover to minimum position then click stop.");
243 }
244 else
245 {
246 m_CalibrationStatus = Idle;
247 LOG_INFO("Calibration complete.");
248 }
249
250 CalibrateToggleSP.apply();
251 return true;
252 }
253
254 return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n);
255}
256
261{
262 if (m_ALTO->Park())
263 {
264 m_TargetPosition = 0;
265 PositionNP.setState(IPS_BUSY);
266 PositionNP.apply();
267 return IPS_BUSY;
268 }
269
270 return IPS_ALERT;
271}
272
277{
278 if (m_ALTO->UnPark())
279 {
280 m_TargetPosition = 100;
281 PositionNP.setState(IPS_BUSY);
282 PositionNP.apply();
283 return IPS_BUSY;
284 }
285
286 return IPS_ALERT;
287}
288
293{
294 return m_ALTO->stop() ? IPS_OK : IPS_ALERT;
295}
296
301{
302 MotionSpeedSP.save(fp);
304}
305
310{
311 // Check Park Cap status
312 if (ParkCapSP.getState() == IPS_BUSY)
313 {
314 json status;
315 try
316 {
317 m_ALTO->getStatus(status);
318 std::string mst = status["MST"];
319 if (mst == "stop")
320 {
323 }
324 }
325 catch (json::exception &e)
326 {
327 LOGF_ERROR("%s %d", e.what(), e.id);
328 }
329 }
330
331 // Check position updates
332 if (PositionNP.getState() == IPS_BUSY)
333 {
334 uint8_t newPosition = PositionNP[0].value;
335 try
336 {
337 m_ALTO->getPosition(newPosition);
338 }
339 catch (json::exception &e)
340 {
341 LOGF_ERROR("%s %d", e.what(), e.id);
342 }
343
344 if (newPosition == m_TargetPosition)
345 {
346 PositionNP[0].setValue(m_TargetPosition);
347 PositionNP.setState(IPS_OK);
348 PositionNP.apply();
349 }
350 else if (newPosition != PositionNP[0].getValue())
351 {
352 PositionNP[0].setValue(newPosition);
353 PositionNP.apply();
354 }
355 }
356
358}
Definition alto.h:24
bool Handshake()
Definition alto.cpp:122
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition alto.cpp:79
ALTO()
Definition alto.cpp:25
virtual IPState ParkCap() override
Park dust cap (close cover). Must be implemented by child.
Definition alto.cpp:260
const char * getDefaultName() override
Definition alto.cpp:141
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition alto.cpp:309
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition alto.cpp:149
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition alto.cpp:176
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition alto.cpp:300
virtual IPState AbortCap() override
Abort motion. Must be implemented by child.
Definition alto.cpp:292
virtual bool initProperties() override
Initialize 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:276
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...
Provides interface to implement remotely controlled dust cover.
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.
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 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.
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.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
INDI::PropertySwitch ParkCapSP
bool updateProperties()
updateProperties Defines or Delete properties based on default device connection status
void initProperties(const char *group, uint32_t capabilities=0)
Initialize dust cap properties. It is recommended to call this function within initProperties() of yo...
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process dust cap switch properties.
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
const char * getName() const
bool isNameMatch(const char *otherName) const
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
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
general exception of the basic_json class
const int id
the id of the exception
const char * what() const noexcept override
returns the explanatory string
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
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
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
@ ISR_1OFMANY
Definition indiapi.h:171
@ ISR_ATMOST1
Definition indiapi.h:172
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOG_INFO(txt)
Definition indilogger.h:74