Instrument Neutral Distributed Interface INDI  2.0.2
InMemoryDatabase.cpp
Go to the documentation of this file.
1 
9 #include "InMemoryDatabase.h"
10 
11 #include "basedevice.h"
12 #include "indicom.h"
13 
14 #include <cerrno>
15 #include <cstdlib>
16 #include <cstring>
17 #include <sys/stat.h>
18 
19 namespace INDI
20 {
21 namespace AlignmentSubsystem
22 {
23 InMemoryDatabase::InMemoryDatabase() : DatabaseReferencePositionIsValid(false),
24  LoadDatabaseCallback(nullptr), LoadDatabaseCallbackThisPointer(nullptr)
25 {
26 }
27 
29  double Tolerance) const
30 {
31  return std::any_of(MySyncPoints.begin(), MySyncPoints.end(), [CandidateEntry, Tolerance](const auto & point)
32  {
33  return (((std::abs(point.RightAscension - CandidateEntry.RightAscension) < 24.0 * Tolerance / 100.0) &&
34  (std::abs(point.Declination - CandidateEntry.Declination) < 180.0 * Tolerance / 100.0)) ||
35  ((std::abs(point.TelescopeDirection.x - CandidateEntry.TelescopeDirection.x) < Tolerance / 100.0) &&
36  (std::abs(point.TelescopeDirection.y - CandidateEntry.TelescopeDirection.y) < Tolerance / 100.0) &&
37  (std::abs(point.TelescopeDirection.z - CandidateEntry.TelescopeDirection.z) < Tolerance / 100.0)));
38  });
39 }
40 
42  double Tolerance)
43 {
44  MySyncPoints.erase(std::remove_if(MySyncPoints.begin(), MySyncPoints.end(),
45  [CandidateEntry, Tolerance](const auto & point)
46  {
47  return (((std::abs(point.RightAscension - CandidateEntry.RightAscension) < 24.0 * Tolerance / 100.0) &&
48  (std::abs(point.Declination - CandidateEntry.Declination) < 180.0 * Tolerance / 100.0)) ||
49  ((std::abs(point.TelescopeDirection.x - CandidateEntry.TelescopeDirection.x) < Tolerance / 100.0) &&
50  (std::abs(point.TelescopeDirection.y - CandidateEntry.TelescopeDirection.y) < Tolerance / 100.0) &&
51  (std::abs(point.TelescopeDirection.z - CandidateEntry.TelescopeDirection.z) < Tolerance / 100.0)));
52  }),
53  MySyncPoints.end());
54 }
55 
56 
58 {
59  if (DatabaseReferencePositionIsValid)
60  {
61  Position = DatabaseReferencePosition;
62  return true;
63  }
64  else
65  return false;
66 }
67 
68 bool InMemoryDatabase::LoadDatabase(const char *DeviceName)
69 {
70  char DatabaseFileName[MAXRBUF];
71  char Errmsg[MAXRBUF];
72  XMLEle *FileRoot = nullptr;
73  XMLEle *EntriesRoot = nullptr;
74  XMLEle *EntryRoot = nullptr;
75  XMLEle *Element = nullptr;
76  XMLAtt *Attribute = nullptr;
77  LilXML *Parser = newLilXML();
78 
79  FILE *fp = nullptr;
80 
81  snprintf(DatabaseFileName, MAXRBUF, "%s/.indi/%s_alignment_database.xml", getenv("HOME"), DeviceName);
82 
83  fp = fopen(DatabaseFileName, "r");
84  if (fp == nullptr)
85  {
86  snprintf(Errmsg, MAXRBUF, "Unable to read alignment database file. Error loading file %s: %s\n",
87  DatabaseFileName, strerror(errno));
88  return false;
89  }
90 
91  char whynot[MAXRBUF];
92  if (nullptr == (FileRoot = readXMLFile(fp, Parser, whynot)))
93  {
94  snprintf(Errmsg, MAXRBUF, "Unable to parse database XML: %s", whynot);
95  return false;
96  }
97 
98  if (strcmp(tagXMLEle(FileRoot), "INDIAlignmentDatabase") != 0)
99  {
100  return false;
101  }
102 
103  if (nullptr == (EntriesRoot = findXMLEle(FileRoot, "DatabaseEntries")))
104  {
105  snprintf(Errmsg, MAXRBUF, "Cannot find DatabaseEntries element");
106  return false;
107  }
108 
109  if (nullptr != (Element = findXMLEle(FileRoot, "DatabaseReferenceLocation")))
110  {
111  if (nullptr == (Attribute = findXMLAtt(Element, "latitude")))
112  {
113  snprintf(Errmsg, MAXRBUF, "Cannot find latitude attribute");
114  return false;
115  }
116  sscanf(valuXMLAtt(Attribute), "%lf", &DatabaseReferencePosition.latitude);
117  if (nullptr == (Attribute = findXMLAtt(Element, "longitude")))
118  {
119  snprintf(Errmsg, MAXRBUF, "Cannot find longitude attribute");
120  return false;
121  }
122  sscanf(valuXMLAtt(Attribute), "%lf", &DatabaseReferencePosition.longitude);
123  DatabaseReferencePositionIsValid = true;
124  }
125 
126  MySyncPoints.clear();
127 
128  for (EntryRoot = nextXMLEle(EntriesRoot, 1); EntryRoot != nullptr; EntryRoot = nextXMLEle(EntriesRoot, 0))
129  {
130  AlignmentDatabaseEntry CurrentValues;
131  if (strcmp(tagXMLEle(EntryRoot), "DatabaseEntry") != 0)
132  {
133  return false;
134  }
135  for (Element = nextXMLEle(EntryRoot, 1); Element != nullptr; Element = nextXMLEle(EntryRoot, 0))
136  {
137  if (strcmp(tagXMLEle(Element), "ObservationJulianDate") == 0)
138  {
139  sscanf(pcdataXMLEle(Element), "%lf", &CurrentValues.ObservationJulianDate);
140  }
141  else if (strcmp(tagXMLEle(Element), "RightAscension") == 0)
142  {
143  f_scansexa(pcdataXMLEle(Element), &CurrentValues.RightAscension);
144  }
145  else if (strcmp(tagXMLEle(Element), "Declination") == 0)
146  {
147  f_scansexa(pcdataXMLEle(Element), &CurrentValues.Declination);
148  }
149  else if (strcmp(tagXMLEle(Element), "TelescopeDirectionVectorX") == 0)
150  {
151  sscanf(pcdataXMLEle(Element), "%lf", &CurrentValues.TelescopeDirection.x);
152  }
153  else if (strcmp(tagXMLEle(Element), "TelescopeDirectionVectorY") == 0)
154  {
155  sscanf(pcdataXMLEle(Element), "%lf", &CurrentValues.TelescopeDirection.y);
156  }
157  else if (strcmp(tagXMLEle(Element), "TelescopeDirectionVectorZ") == 0)
158  {
159  sscanf(pcdataXMLEle(Element), "%lf", &CurrentValues.TelescopeDirection.z);
160  }
161  else
162  return false;
163  }
164  MySyncPoints.push_back(CurrentValues);
165  }
166 
167  fclose(fp);
168  delXMLEle(FileRoot);
169  delLilXML(Parser);
170 
171  if (nullptr != LoadDatabaseCallback)
172  (*LoadDatabaseCallback)(LoadDatabaseCallbackThisPointer);
173 
174  return true;
175 }
176 
177 bool InMemoryDatabase::SaveDatabase(const char *DeviceName)
178 {
179  char ConfigDir[MAXRBUF];
180  char DatabaseFileName[MAXRBUF];
181  char Errmsg[MAXRBUF];
182  struct stat Status;
183  FILE *fp;
184 
185  snprintf(ConfigDir, MAXRBUF, "%s/.indi/", getenv("HOME"));
186  snprintf(DatabaseFileName, MAXRBUF, "%s%s_alignment_database.xml", ConfigDir, DeviceName);
187 
188  if (stat(ConfigDir, &Status) != 0)
189  {
190  if (mkdir(ConfigDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0)
191  {
192  snprintf(Errmsg, MAXRBUF, "Unable to create config directory. Error %s: %s\n", ConfigDir, strerror(errno));
193  return false;
194  }
195  }
196 
197  fp = fopen(DatabaseFileName, "w");
198  if (fp == nullptr)
199  {
200  snprintf(Errmsg, MAXRBUF, "Unable to open database file. Error opening file %s: %s\n", DatabaseFileName,
201  strerror(errno));
202  return false;
203  }
204 
205  fprintf(fp, "<INDIAlignmentDatabase>\n");
206 
207  if (DatabaseReferencePositionIsValid)
208  fprintf(fp, " <DatabaseReferenceLocation latitude='%lf' longitude='%lf'/>\n", DatabaseReferencePosition.latitude,
209  DatabaseReferencePosition.longitude);
210 
211  fprintf(fp, " <DatabaseEntries>\n");
212  for (AlignmentDatabaseType::const_iterator Itr = MySyncPoints.begin(); Itr != MySyncPoints.end(); Itr++)
213  {
214  char SexaString[12]; // Long enough to hold xx:xx:xx.xx
215  fprintf(fp, " <DatabaseEntry>\n");
216 
217  fprintf(fp, " <ObservationJulianDate>%lf</ObservationJulianDate>\n", (*Itr).ObservationJulianDate);
218  fs_sexa(SexaString, (*Itr).RightAscension, 2, 3600);
219  fprintf(fp, " <RightAscension>%s</RightAscension>\n", SexaString);
220  fs_sexa(SexaString, (*Itr).Declination, 2, 3600);
221  fprintf(fp, " <Declination>%s</Declination>\n", SexaString);
222  fprintf(fp, " <TelescopeDirectionVectorX>%lf</TelescopeDirectionVectorX>\n",
223  (*Itr).TelescopeDirection.x);
224  fprintf(fp, " <TelescopeDirectionVectorY>%lf</TelescopeDirectionVectorY>\n",
225  (*Itr).TelescopeDirection.y);
226  fprintf(fp, " <TelescopeDirectionVectorZ>%lf</TelescopeDirectionVectorZ>\n",
227  (*Itr).TelescopeDirection.z);
228 
229  fprintf(fp, " </DatabaseEntry>\n");
230  }
231  fprintf(fp, " </DatabaseEntries>\n");
232 
233  fprintf(fp, "</INDIAlignmentDatabase>\n");
234 
235  fclose(fp);
236 
237  return true;
238 }
239 
240 void InMemoryDatabase::SetDatabaseReferencePosition(double Latitude, double Longitude)
241 {
242  DatabaseReferencePosition.latitude = Latitude;
243  DatabaseReferencePosition.longitude = Longitude;
244  DatabaseReferencePositionIsValid = true;
245 }
246 
247 void InMemoryDatabase::SetLoadDatabaseCallback(LoadDatabaseCallbackPointer_t CallbackPointer, void *ThisPointer)
248 {
249  LoadDatabaseCallback = CallbackPointer;
250  LoadDatabaseCallbackThisPointer = ThisPointer;
251 }
252 
253 } // namespace AlignmentSubsystem
254 } // namespace INDI
bool SaveDatabase(const char *DeviceName)
Save the database to persistent storage.
void SetDatabaseReferencePosition(double Latitude, double Longitude)
Set the database reference position.
void SetLoadDatabaseCallback(LoadDatabaseCallbackPointer_t CallbackPointer, void *ThisPointer)
Set the function to be called when the database is loaded or reloaded.
bool CheckForDuplicateSyncPoint(const AlignmentDatabaseEntry &CandidateEntry, double Tolerance=0.1) const
Check if a entry already exists in the database.
void RemoveSyncPoint(const AlignmentDatabaseEntry &CandidateEntry, double Tolerance=0.1)
Remove a sync point that falls within the tolerance of a candidate point.
bool GetDatabaseReferencePosition(IGeographicCoordinates &Position)
Get the database reference position.
bool LoadDatabase(const char *DeviceName)
Load the database from persistent storage.
int errno
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double. x can be anything non-numeric. Any missing A,...
Definition: indicom.c:205
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string. sprint the variable a in sexagesimal format into out[].
Definition: indicom.c:141
Implementations for common driver routines.
#define MAXRBUF
Definition: indiserver.cpp:102
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
Definition: lilxml.cpp:524
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
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition: lilxml.cpp:600
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
XMLEle * findXMLEle(XMLEle *ep, const char *tag)
Find an XML element within an XML element.
Definition: lilxml.cpp:537
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition: lilxml.cpp:624
Namespace to encapsulate INDI client, drivers, and mediator classes.
int mkdir(const char *path, mode_t mode)
Definition: indiutility.cpp:41
Entry in the in memory alignment database.
Definition: Common.h:152
double RightAscension
Right ascension in decimal hours. N.B. libnova works in decimal degrees so conversion is always neede...
Definition: Common.h:190
TelescopeDirectionVector TelescopeDirection
Normalised vector giving telescope pointing direction. This is referred to elsewhere as the "apparent...
Definition: Common.h:197
double Declination
Declination in decimal degrees.
Definition: Common.h:193