Instrument Neutral Distributed Interface INDI 2.2.5
indioutputinterface.cpp
Go to the documentation of this file.
1/*
2 Output Interface
3 Copyright (C) 2024 Jasem Mutlaq ([email protected])
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21#include "indioutputinterface.h"
22#include <cstring>
23#include "indilogger.h"
24
25namespace INDI
26{
27
31OutputInterface::OutputInterface(DefaultDevice *defaultDevice) : m_defaultDevice(defaultDevice)
32{
33}
34
41
45void OutputInterface::initProperties(const char *groupName, uint8_t Outputs, const std::string &prefix)
46{
49
50 // Initialize pulse duration properties
51 PulseDurationNP.clear();
52 PulseDurationNP.reserve(Outputs);
53 for (size_t i = 0; i < Outputs; i++)
54 {
55 auto label = prefix + " #" + std::to_string(i + 1);
56 INDI::PropertyNumber oneDuration {1};
57 oneDuration[0].fill("DURATION", "Duration (ms)", "%.0f", 0, 60000, 100, 0);
58 oneDuration.fill(m_defaultDevice->getDeviceName(), ("PULSE_" + std::to_string(i)).c_str(),
59 label.c_str(), "Pulse Mode", IP_RW, 60, IPS_IDLE);
60 oneDuration.load();
61 PulseDurationNP.push_back(std::move(oneDuration));
62 }
63 PulseDurationNP.shrink_to_fit();
64
65 // Initialize labels
66 for (auto i = 0; i < Outputs; i++)
67 {
68 auto name = "DIGITAL_OUTPUT_" + std::to_string(i + 1);
69 auto label = prefix + " #" + std::to_string(i + 1);
70
71 INDI::WidgetText oneLabel;
72 oneLabel.fill(name, label, label);
73 DigitalOutputLabelsTP.push(std::move(oneLabel));
74 }
75
76 DigitalOutputLabelsTP.fill(m_defaultDevice->getDeviceName(), "DIGITAL_OUTPUT_LABELS", "Labels", groupName, IP_RW, 60,
77 IPS_IDLE);
79 if (Outputs > 0)
81
82 DigitalOutputsSP.reserve(Outputs);
83 // Initialize switches, use labels if loaded.
84 for (size_t i = 0; i < Outputs; i++)
85 {
86 auto name = "DIGITAL_OUTPUT_" + std::to_string(i + 1);
87 auto label = prefix + " #" + std::to_string(i + 1);
88
89 INDI::PropertySwitch oneOutput {2};
90 oneOutput[Off].fill("OFF", "Off", ISS_OFF);
91 oneOutput[On].fill("ON", "On", ISS_OFF);
92
94 label = DigitalOutputLabelsTP[i].getText();
95 oneOutput.fill(m_defaultDevice->getDeviceName(), name.c_str(), label.c_str(), groupName, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
96 DigitalOutputsSP.push_back(std::move(oneOutput));
97 }
98}
99
104{
106 {
107 for (auto &oneOutput : DigitalOutputsSP)
109 if (DigitalOutputsSP.size() > 0)
111 for (auto &oneDuration : PulseDurationNP)
112 m_defaultDevice->defineProperty(oneDuration);
113 }
114 else
115 {
116 for (auto &oneOutput : DigitalOutputsSP)
118 if (DigitalOutputsSP.size() > 0)
120 for (auto &oneDuration : PulseDurationNP)
121 m_defaultDevice->deleteProperty(oneDuration);
122 }
123
124 return true;
125}
126
130bool OutputInterface::processSwitch(const char *dev, const char *name, ISState states[], char *names[], int n)
131{
132 if (dev && !strcmp(dev, m_defaultDevice->getDeviceName()))
133 {
134 for (size_t i = 0; i < DigitalOutputsSP.size(); i++)
135 {
136 if (DigitalOutputsSP[i].isNameMatch(name))
137 {
138 auto oldState = DigitalOutputsSP[i].findOnSwitchIndex();
139 DigitalOutputsSP[i].update(states, names, n);
140 auto newState = DigitalOutputsSP[i].findOnSwitchIndex();
141 if (oldState != newState)
142 {
143 // Cast to Command and send
144 if (CommandOutput(i, static_cast<OutputState>(newState)))
145 {
146 DigitalOutputsSP[i].setState(IPS_OK);
147
148 // If turning on and pulse duration is set, start the pulse
149 if (newState == On && i < PulseDurationNP.size() && PulseDurationNP[i][0].getValue() > 0)
150 {
151 INDI::Timer::singleShot(static_cast<uint32_t>(PulseDurationNP[i][0].getValue()),
152 [this, i]()
153 {
154 CommandOutput(i, Off);
155 DigitalOutputsSP[i].reset();
156 DigitalOutputsSP[i][Off].setState(ISS_ON);
157 DigitalOutputsSP[i].setState(IPS_OK);
158 DigitalOutputsSP[i].apply();
159 PulseDurationNP[i].setState(IPS_OK);
160 PulseDurationNP[i].apply();
161 });
162 PulseDurationNP[i].setState(IPS_BUSY);
163 PulseDurationNP[i].apply();
164 }
165 }
166 else
167 {
168 DigitalOutputsSP[i].setState(IPS_ALERT);
169 DigitalOutputsSP[i].reset();
170 DigitalOutputsSP[i][oldState].setState(ISS_ON);
171 }
172
173 // Apply and return
174 DigitalOutputsSP[i].apply();
175 return true;
176 }
177 // No state change
178 else
179 {
180 DigitalOutputsSP[i].setState(IPS_OK);
181 DigitalOutputsSP[i].apply();
182 return true;
183 }
184 }
185 }
186 }
187
188 return false;
189}
190
191bool OutputInterface::processNumber(const char *dev, const char *name, double values[], char *names[], int n)
192{
193 if (dev && !strcmp(dev, m_defaultDevice->getDeviceName()))
194 {
195 for (size_t i = 0; i < PulseDurationNP.size(); i++)
196 {
197 if (PulseDurationNP[i].isNameMatch(name))
198 {
199 PulseDurationNP[i].update(values, names, n);
200 PulseDurationNP[i].setState(IPS_OK);
201 PulseDurationNP[i].apply();
203 return true;
204 }
205 }
206 }
207
208 return false;
209}
210
214bool OutputInterface::processText(const char *dev, const char *name, char *texts[], char *names[], int n)
215{
216 if (dev && !strcmp(dev, m_defaultDevice->getDeviceName()))
217 {
218 // If this call due to config loading, let's delete existing dummy property and define the full one
220 {
221 DigitalOutputLabelsTP.update(texts, names, n);
225 return true;
226 }
227 }
228
229 return false;
230}
231
236{
238 for (auto &oneDuration : PulseDurationNP)
239 oneDuration.save(fp);
240 return true;
241}
242
243}
bool isConnected() const
const char * getDeviceName() const
Class to provide extended functionality for devices in addition to the functionality provided by INDI...
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a 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)
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process number properties.
void initProperties(const char *groupName, uint8_t outputs, const std::string &prefix="Output")
Initialize filter wheel properties. It is recommended to call this function within initProperties() o...
bool processSwitch(const char *dev, const char *name, ISState states[], char *names[], int n)
Process switch properties.
OutputInterface(DefaultDevice *defaultDevice)
OutputInterface Initiailize Output Interface.
bool saveConfigItems(FILE *fp)
saveConfigItems save Filter Names in config file
std::vector< INDI::PropertySwitch > DigitalOutputsSP
bool processText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process text properties.
virtual bool CommandOutput(uint32_t index, OutputState command)=0
Send command to output.
INDI::PropertyText DigitalOutputLabelsTP
std::vector< INDI::PropertyNumber > PulseDurationNP
bool updateProperties()
updateProperties Defines or Delete properties based on default device connection status
DefaultDevice * m_defaultDevice
void push(WidgetView< T > &&item)
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool load()
load Attempt to load property values from configuration file.
void save(FILE *f) const
save Save property to configuration file.
void resize(size_t size)
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)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
bool update(const char *const texts[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
INDI::PropertyViewText * getText() const
static void singleShot(int msec, const std::function< void()> &callback)
This static function calls a the given function after a given time interval.
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
@ 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_ATMOST1
Definition indiapi.h:172
Namespace to encapsulate INDI client, drivers, and mediator classes.
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
void fill(const char *name, const char *label, const char *initialText)