Instrument Neutral Distributed Interface INDI  2.0.2
indifilterinterface.cpp
Go to the documentation of this file.
1 /*
2  Filter Interface
3  Copyright (C) 2011 Jasem Mutlaq (mutlaqja@ikarustech.com)
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 
25 namespace INDI
26 {
27 
28 FilterInterface::FilterInterface(DefaultDevice *defaultDevice) : m_defaultDevice(defaultDevice)
29 {
31  FilterNameT = nullptr;
32 }
33 
35 {
36  delete FilterNameTP;
37 }
38 
39 void FilterInterface::initProperties(const char *groupName)
40 {
41  IUFillNumber(&FilterSlotN[0], "FILTER_SLOT_VALUE", "Filter", "%3.0f", 1.0, 12.0, 1.0, 1.0);
42  IUFillNumberVector(&FilterSlotNP, FilterSlotN, 1, m_defaultDevice->getDeviceName(), "FILTER_SLOT", "Filter Slot", groupName,
43  IP_RW, 60,
44  IPS_IDLE);
45 
46  loadFilterNames();
47 }
48 
50 {
52  {
53  // Define the Filter Slot and name properties
55  if (FilterNameT == nullptr)
56  {
57  if (GetFilterNames() == true)
59  }
60  else
62  }
63  else
64  {
67  }
68 
69  return true;
70 }
71 
72 bool FilterInterface::processNumber(const char *dev, const char *name, double values[], char *names[], int n)
73 {
74  INDI_UNUSED(n);
75 
76  if (dev && !strcmp(dev, m_defaultDevice->getDeviceName()) && !strcmp(name, FilterSlotNP.name))
77  {
78  TargetFilter = values[0];
79 
80  INumber *np = IUFindNumber(&FilterSlotNP, names[0]);
81 
82  if (!np)
83  {
85  DEBUGFDEVICE(m_defaultDevice->getDeviceName(), Logger::DBG_ERROR, "Unknown error. %s is not a member of %s property.",
86  names[0], FilterSlotNP.name);
87  IDSetNumber(&FilterSlotNP, nullptr);
88  return false;
89  }
90 
92  {
94  DEBUGFDEVICE(m_defaultDevice->getDeviceName(), Logger::DBG_ERROR, "Error: valid range of filter is from %g to %g",
95  FilterSlotN[0].min, FilterSlotN[0].max);
96  IDSetNumber(&FilterSlotNP, nullptr);
97  return false;
98  }
99 
101  DEBUGFDEVICE(m_defaultDevice->getDeviceName(), Logger::DBG_SESSION, "Setting current filter to slot %d", TargetFilter);
102 
103  if (SelectFilter(TargetFilter) == false)
104  {
106  }
107 
108  IDSetNumber(&FilterSlotNP, nullptr);
109  return true;
110  }
111 
112  return false;
113 }
114 
115 bool FilterInterface::processText(const char *dev, const char *name, char *texts[], char *names[], int n)
116 {
117  if (dev && !strcmp(dev, m_defaultDevice->getDeviceName()) && !strcmp(name, "FILTER_NAME"))
118  {
119  // If this call due to config loading, let's delete existing dummy property and define the full one
120  if (loadingFromConfig)
121  {
122  loadingFromConfig = false;
123  m_defaultDevice->deleteProperty("FILTER_NAME");
124 
125  char filterName[MAXINDINAME];
126  char filterLabel[MAXINDILABEL];
127 
128  if (FilterNameT != nullptr)
129  {
130  for (int i = 0; i < FilterNameTP->ntp; i++)
131  free(FilterNameT[i].text);
132  delete [] FilterNameT;
133  }
134 
135  FilterNameT = new IText[n];
136  memset(FilterNameT, 0, sizeof(IText) * n);
137 
138  for (int i = 0; i < n; i++)
139  {
140  snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", i + 1);
141  snprintf(filterLabel, MAXINDILABEL, "Filter#%d", i + 1);
142  IUFillText(&FilterNameT[i], filterName, filterLabel, texts[i]);
143  }
144 
145  IUFillTextVector(FilterNameTP, FilterNameT, n, m_defaultDevice->getDeviceName(), "FILTER_NAME", "Filter",
148  return true;
149  }
150 
151  IUUpdateText(FilterNameTP, texts, names, n);
152  FilterNameTP->s = IPS_OK;
153 
154  if (SetFilterNames() == true)
155  {
156  IDSetText(FilterNameTP, nullptr);
157  return true;
158  }
159  else
160  {
162  DEBUGDEVICE(m_defaultDevice->getDeviceName(), Logger::DBG_ERROR, "Error updating names of filters.");
163  IDSetText(FilterNameTP, nullptr);
164  return false;
165  }
166  }
167 
168  return false;
169 }
170 
172 {
174  if (FilterNameTP)
176 
177  return true;
178 }
179 
181 {
182  // The hardware has finished changing
183  // filters
184  FilterSlotN[0].value = f;
186  // Tell the clients we are done, and
187  // filter is now useable
188  IDSetNumber(&FilterSlotNP, nullptr);
189 }
190 
192 {
193  char filterName[MAXINDINAME];
194  char filterLabel[MAXINDILABEL];
195  int MaxFilter = FilterSlotN[0].max;
196 
197  const char *filterDesignation[8] = { "Red", "Green", "Blue", "H_Alpha", "SII", "OIII", "LPR", "Luminance" };
198 
199  if (FilterNameT != nullptr)
200  {
201  for (int i = 0; i < FilterNameTP->ntp; i++)
202  free(FilterNameT[i].text);
203  delete [] FilterNameT;
204  }
205 
206  FilterNameT = new IText[MaxFilter];
207  memset(FilterNameT, 0, sizeof(IText) * MaxFilter);
208 
209  for (int i = 0; i < MaxFilter; i++)
210  {
211  snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", i + 1);
212  snprintf(filterLabel, MAXINDILABEL, "Filter#%d", i + 1);
213  IUFillText(&FilterNameT[i], filterName, filterLabel, i < 8 ? filterDesignation[i] : filterLabel);
214  }
215 
216  IUFillTextVector(FilterNameTP, FilterNameT, MaxFilter, m_defaultDevice->getDeviceName(), "FILTER_NAME", "Filter",
218 }
219 
221 {
222  // Load from config
223  if (FilterNameT == nullptr)
224  {
226 
227  // // JM 2018-07-09: Set loadingFromConfig to true here before calling loadConfig
228  // // since if loadConfig is successful, ISNewText could be executed _before_ we have a chance
229  // // to set loadFromConfig below
230  // loadingFromConfig = true;
231 
232  // // If property is found, let's define it once loaded to the client and delete
233  // // the generate sample filters above
234  // loadingFromConfig = m_defaultDevice->loadConfig(true, "FILTER_NAME");
235  }
236 
237  return true;
238 }
239 
241 {
242  return m_defaultDevice->saveConfig(true, "FILTER_NAME");
243 }
244 
245 bool FilterInterface::loadFilterNames()
246 {
247  if (FilterNameT != nullptr)
248  return true;
249 
250  char *rname, *rdev;
251  XMLEle *root = nullptr, *fproot = nullptr;
252  char filterName[MAXINDINAME] = {0};
253  char errmsg[MAXRBUF];
254  LilXML *lp = newLilXML();
255  int nelem = 0;
256 
257  FILE *fp = IUGetConfigFP(nullptr, m_defaultDevice->getDefaultName(), "r", errmsg);
258 
259  if (fp == nullptr)
260  {
261  delLilXML(lp);
262  return false;
263  }
264 
265  fproot = readXMLFile(fp, lp, errmsg);
266 
267  if (fproot == nullptr)
268  {
269  delLilXML(lp);
270  fclose(fp);
271  return false;
272  }
273 
274  for (root = nextXMLEle(fproot, 1); root != nullptr; root = nextXMLEle(fproot, 0))
275  {
276  /* pull out device and name */
277  if (crackDN(root, &rdev, &rname, errmsg) < 0)
278  {
279  fclose(fp);
280  delXMLEle(fproot);
281  delLilXML(lp);
282  return false;
283  }
284 
285  // It doesn't belong to our device??
286  if (strcmp(m_defaultDevice->getDeviceName(), rdev))
287  continue;
288 
289  if (!strcmp("FILTER_NAME", rname))
290  {
291  nelem = nXMLEle(root);
292  FilterNameT = new IText[nelem];
293  memset(FilterNameT, 0, sizeof(IText) * nelem);
294 
295  XMLEle *oneText = nullptr;
296  uint8_t counter = 0;
297 
298  for (oneText = nextXMLEle(root, 1); oneText != nullptr; oneText = nextXMLEle(root, 0))
299  {
300  const char *filter = pcdataXMLEle(oneText);
301  snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", counter + 1);
302  IUFillText(&FilterNameT[counter], filterName, filter, filter);
303  counter++;
304  }
305 
306  break;
307  }
308  }
309 
310  IUFillTextVector(FilterNameTP, FilterNameT, nelem, m_defaultDevice->getDeviceName(), "FILTER_NAME", "Filter",
312 
313  fclose(fp);
314  delXMLEle(fproot);
315  delLilXML(lp);
316 
317  return true;
318 }
319 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
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 const char * getDefaultName()=0
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
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.
DefaultDevice * m_defaultDevice
virtual bool SetFilterNames()
Set filter names as defined by the client for each filter position. The desired filter names are stor...
ITextVectorProperty * FilterNameTP
INumberVectorProperty FilterSlotNP
bool updateProperties()
updateProperties Defines or Delete proprties 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)
Initilize filter wheel properties. It is recommended to call this function within initProperties() of...
bool saveConfigItems(FILE *fp)
saveConfigItems save Filter Names in config file
double max(void)
double min(void)
@ IP_RW
Definition: indiapi.h:186
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
#define MAXINDILABEL
Definition: indiapi.h:192
#define MAXINDINAME
Definition: indiapi.h:191
struct _ITextVectorProperty ITextVectorProperty
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indidevapi.c:66
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:291
int crackDN(XMLEle *root, char **dev, char **name, char msg[])
Extract dev and name attributes from an XML element.
Definition: indidevapi.c:553
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition: indidevapi.c:198
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidevapi.c:180
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indidevapi.c:20
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:1396
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
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.
Definition: indidriver.c:994
#define DEBUGDEVICE(device, priority, msg)
Definition: indilogger.h:60
#define DEBUGFDEVICE(device, priority, msg,...)
Definition: indilogger.h:61
#define MAXRBUF
Definition: indiserver.cpp:102
int nXMLEle(XMLEle *ep)
Return the number of nested XML elements in a parent XML element.
Definition: lilxml.cpp:630
LilXML * newLilXML()
Create a new lilxml parser.
Definition: lilxml.cpp:150
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.cpp:606
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition: lilxml.cpp:653
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.cpp:555
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
Definition: lilxml.cpp:167
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition: lilxml.cpp:159
Namespace to encapsulate INDI client, drivers, and mediator classes.
One number descriptor.
One text descriptor.
char group[MAXINDIGROUP]
Definition: indiapi.h:327
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:250