Instrument Neutral Distributed Interface INDI 2.2.5
indifilterinterface.cpp
Go to the documentation of this file.
1/*
2 Filter Interface
3 Copyright (C) 2011 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 "indifilterinterface.h"
22#include <cstring>
23#include "indilogger.h"
24#include "indipropertytext.h"
25#include "indipropertynumber.h"
26
27namespace INDI
28{
29
30FilterInterface::FilterInterface(DefaultDevice *defaultDevice) : m_defaultDevice(defaultDevice)
31{
32}
33
37
38void FilterInterface::initProperties(const char *groupName)
39{
40 // @INDI_STANDARD_PROPERTY@
41 FilterSlotNP[0].fill("FILTER_SLOT_VALUE", "Filter", "%.f", 1.0, 12, 1.0, 1.0);
42 FilterSlotNP.fill(m_defaultDevice->getDeviceName(), "FILTER_SLOT", "Filter Slot", groupName, IP_RW, 60, IPS_IDLE);
43
44 loadFilterNames();
45}
46
48{
50 {
51 // Reconcile filter name count with hardware slot count.
52 // Handles both wheel upgrades (5→7) and downgrades (7→5).
53 int maxSlots = static_cast<int>(FilterSlotNP[0].getMax());
54 int nameCount = static_cast<int>(FilterNameTP.size());
55 if (nameCount > 0 && nameCount < maxSlots)
56 {
57 // Wheel got larger — extend with default names
58 char filterName[MAXINDINAME];
59 char filterLabel[MAXINDILABEL];
60 for (int i = nameCount; i < maxSlots; i++)
61 {
62 snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", i + 1);
63 snprintf(filterLabel, MAXINDILABEL, "Filter#%d", i + 1);
64
65 INDI::WidgetText oneWidget;
66 oneWidget.fill(filterName, filterLabel, filterLabel);
67 FilterNameTP.push(std::move(oneWidget));
68 }
70
72 "Filter wheel has %d slots but only %d names were saved. "
73 "Added default names for slots %d-%d.",
74 maxSlots, nameCount, nameCount + 1, maxSlots);
75
77 }
78 else if (nameCount > maxSlots)
79 {
80 // Wheel got smaller — trim excess names
81 FilterNameTP.resize(maxSlots);
83
85 "Filter wheel has %d slots but %d names were saved. "
86 "Trimmed to %d.",
87 maxSlots, nameCount, maxSlots);
88
90 }
91
92 // Define the Filter Slot and name properties
94 if (FilterNameTP.size() == 0)
95 {
96 if (GetFilterNames() == true)
98 }
99 else
101 }
102 else
103 {
106 }
107
108 return true;
109}
110
111bool FilterInterface::processNumber(const char *dev, const char *name, double values[], char *names[], int n)
112{
113 INDI_UNUSED(n);
114
115 if (dev && !strcmp(dev, m_defaultDevice->getDeviceName()) && FilterSlotNP.isNameMatch(name))
116 {
117 TargetFilter = values[0];
118
119 auto np = FilterSlotNP.findWidgetByName(names[0]);
120
121 if (!np)
122 {
124 DEBUGFDEVICE(m_defaultDevice->getDeviceName(), Logger::DBG_ERROR, "Unknown error. %s is not a member of %s property.",
125 names[0], FilterSlotNP.getName());
127 return false;
128 }
129
130 if (TargetFilter < FilterSlotNP[0].getMin() || TargetFilter > FilterSlotNP[0].getMax())
131 {
134 "Error: requested slot %d is invalid (Range from %.f to %.f",
135 static_cast<int>(TargetFilter), FilterSlotNP[0].getMin(), FilterSlotNP[0].getMax());
137 return false;
138 }
139
141 DEBUGFDEVICE(m_defaultDevice->getDeviceName(), Logger::DBG_SESSION, "Setting current filter to slot %d", TargetFilter);
142
143 if (SelectFilter(TargetFilter) == false)
144 {
146 }
147
149 return true;
150 }
151
152 return false;
153}
154
155bool FilterInterface::processText(const char *dev, const char *name, char *texts[], char *names[], int n)
156{
157 if (dev && !strcmp(dev, m_defaultDevice->getDeviceName()) && !strcmp(name, "FILTER_NAME"))
158 {
159 FilterNameTP.update(texts, names, n);
161
163 {
165 return true;
166 }
167 else
168 {
170 DEBUGDEVICE(m_defaultDevice->getDeviceName(), Logger::DBG_ERROR, "Error updating names of filters.");
172 return false;
173 }
174 }
175
176 return false;
177}
178
180{
181 FilterSlotNP.save(fp);
182 if (FilterNameTP.size() > 0)
183 FilterNameTP.save(fp);
184
185 return true;
186}
187
189{
190 // The hardware has finished changing filters
191 FilterSlotNP[0].setValue(f);
194}
195
197{
198 char filterName[MAXINDINAME];
199 char filterLabel[MAXINDILABEL];
200 int MaxFilter = FilterSlotNP[0].getMax();
201
202 const char *filterDesignation[8] = { "Red", "Green", "Blue", "H_Alpha", "SII", "OIII", "LPR", "Luminance" };
203
205
206 for (int i = 0; i < MaxFilter; i++)
207 {
208 snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", i + 1);
209 snprintf(filterLabel, MAXINDILABEL, "Filter#%d", i + 1);
210
211 INDI::WidgetText oneText;
212 oneText.fill(filterName, filterLabel, i < 8 ? filterDesignation[i] : filterLabel);
213 FilterNameTP.push(std::move(oneText));
214 }
215
216 FilterNameTP.fill(m_defaultDevice->getDeviceName(), "FILTER_NAME", "Filter",
219}
220
222{
223 // Generate sample filters if nothing available.
224 if (FilterNameTP.isEmpty())
226
227 return true;
228}
229
234
235bool FilterInterface::loadFilterNames()
236{
237 if (FilterNameTP.size() > 0)
238 return true;
239
240 char *rname, *rdev;
241 XMLEle *root = nullptr, *fproot = nullptr;
242 char filterName[MAXINDINAME] = {0};
243 char errmsg[MAXRBUF];
244 LilXML *lp = newLilXML();
245
246 FILE *fp = IUGetConfigFP(nullptr, m_defaultDevice->getDefaultName(), "r", errmsg);
247
248 if (fp == nullptr)
249 {
250 delLilXML(lp);
251 return false;
252 }
253
254 fproot = readXMLFile(fp, lp, errmsg);
255
256 if (fproot == nullptr)
257 {
258 delLilXML(lp);
259 fclose(fp);
260 return false;
261 }
262
263 for (root = nextXMLEle(fproot, 1); root != nullptr; root = nextXMLEle(fproot, 0))
264 {
265 /* pull out device and name */
266 if (crackDN(root, &rdev, &rname, errmsg) < 0)
267 {
268 fclose(fp);
269 delXMLEle(fproot);
270 delLilXML(lp);
271 return false;
272 }
273
274 // It doesn't belong to our device??
275 if (strcmp(m_defaultDevice->getDeviceName(), rdev))
276 continue;
277
278 if (!strcmp("FILTER_NAME", rname))
279 {
281
282 XMLEle *oneText = nullptr;
283 uint8_t counter = 0;
284
285 for (oneText = nextXMLEle(root, 1); oneText != nullptr; oneText = nextXMLEle(root, 0))
286 {
287 const char *filter = pcdataXMLEle(oneText);
288 snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", counter + 1);
289
290 INDI::WidgetText oneWidget;
291 oneWidget.fill(filterName, filter, filter);
292 FilterNameTP.push(std::move(oneWidget));
293 counter++;
294 }
295
296 break;
297 }
298 }
299
300 FilterNameTP.fill(m_defaultDevice->getDeviceName(), "FILTER_NAME", "Filter",
303
304 // Filter Slot must match and agree with filter name if it was loaded successfully.
305 if (FilterNameTP.count() > 0)
306 FilterSlotNP[0].setMax(FilterNameTP.count());
307
308 fclose(fp);
309 delXMLEle(fproot);
310 delLilXML(lp);
311
312 return true;
313}
314}
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.
bool isConfigLoading() const
isConfigLoading Check if driver configuration is currently in the process of getting loaded.
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 const char * getDefaultName()=0
FilterInterface(DefaultDevice *defaultDevice)
FilterInterface Initiailize Filter Interface.
virtual bool SelectFilter(int position)=0
Select a new filter position.
bool processText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process text properties.
INDI::PropertyNumber FilterSlotNP
DefaultDevice * m_defaultDevice
INDI::PropertyText FilterNameTP
virtual bool SetFilterNames()
Set filter names as defined by the client for each filter position. The desired filter names are stor...
bool updateProperties()
updateProperties Defines or Delete properties based on default device connection status
void generateSampleFilters()
generateSampleFilters Generate sample 8-filter wheel and fill it sample filters
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process number properties.
void SelectFilterDone(int newpos)
The child class calls this function when the hardware successfully finished selecting a new filter wh...
virtual bool GetFilterNames()
Obtains a list of filter names from the hardware and initializes the FilterNameTP property....
void initProperties(const char *groupName)
Initialize filter wheel properties. It is recommended to call this function within initProperties() o...
bool saveConfigItems(FILE *fp)
saveConfigItems save Filter Names in config file
void push(WidgetView< T > &&item)
void setState(IPState state)
WidgetView< T > * findWidgetByName(const char *name) const
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
void resize(size_t size)
const char * getName() const
bool isNameMatch(const char *otherName) const
const char * getGroupName() const
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, 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)
@ 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
#define MAXINDILABEL
Definition indiapi.h:190
#define MAXINDINAME
Definition indiapi.h:189
int crackDN(XMLEle *root, char **dev, char **name, char msg[])
Extract dev and name attributes from an XML element.
Definition indidevapi.c:770
#define INDI_UNUSED(x)
Definition indidevapi.h:132
FILE * IUGetConfigFP(const char *filename, const char *dev, const char *mode, char errmsg[])
Open a configuration file for writing and return a configuration file FILE pointer.
#define MAXRBUF
Definition indidriver.c:52
#define DEBUGDEVICE(device, priority, msg)
Definition indilogger.h:60
#define DEBUGFDEVICE(device, priority, msg,...)
Definition indilogger.h:61
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition lilxml.cpp:555
LilXML * newLilXML()
Create a new lilxml parser.
Definition lilxml.cpp:150
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
Definition lilxml.cpp:167
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition lilxml.cpp:606
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition lilxml.cpp:159
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition lilxml.cpp:653
Namespace to encapsulate INDI client, drivers, and mediator classes.
void fill(const char *name, const char *label, const char *initialText)