-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOSPtoRINEX.cpp
278 lines (272 loc) · 14 KB
/
OSPtoRINEX.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/** @file OSPtoRINEX.cpp
* Contains the command line program to generate RINEX files from an OSP data file containing SiRF IV receiver messages.
*<p>Usage:
*<p>OSPtoRINEX.exe {options} [OSPfilename]
*<p>Options are:
* - -a or --aend : Append end-of-file comment lines to Rinex file. Default value FALSE
* - -b or --bias : Apply receiver clock bias to measurements and time. Default value TRUE
* - -c or --glo50bps : Use MID8 GLONASS 50bps data to generate GLONASS navigation file, instead of MID70. Default value FALSE
* - -d or --gps50bps : Use MID8 GPS 50bps data to generate nav file, instead of MID15. Default value FALSE
* - -h or --help : Show usage data and stops. Default value HELP=FALSE
* - -i MINSV or --minsv=MINSV : Minimun satellites in a fix to acquire observations. Default value MINSV = 4
* - -j ANTN or --antnum=ANTN : Receiver antenna number. Default value ANTN = Antenna#
* - -k ANTT or --antype=ANTT : Receiver antenna type. Default value ANTT = AntennaType
* - -l LOGLEVEL or --llevel=LOGLEVEL : Maximum level to log (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST). Default value LOGLEVEL = INFO
* - -m MRKNAM or --mrkname=MRKNAM : Marker name. Default value MRKNAM = MRKNAM
* - -n or --nav : Generate RINEX navigation file. Default value FALSE
* - -o OBSERVER or --observer=OBSERVER : Observer name. Default value OBSERVER = OBSERVER
* - -p PGM or --program=PGM : Program used to generate RINEX file. Default value OSPtoRINEX
* - -q RUNBY or --runby=RUNBY : Who runs the RINEX file generator. Default value RUNBY = RUNBY
* - -r RINEX or --rinex=RINEX : RINEX file name prefix. Default value RINEX = PNT1
* - -s SYSLST or --selsys=SYSLST : List of additional systems to GPS (R or S or R,S) to be included in the RINEX files. Default value an empty list
* - -u MRKNUM or --mrknum=MRKNUM : Marker number. Default value MRKNUM = MRKNUM
* - -v VER or --ver=VER : RINEX version to generate (V210, V304). Default value VER = V210
* - -y AGENCY or --agency=AGENCY : Agency name. Default value AGENCY = AGENCY
*Default value for operator is: DATA.OSP
*<p>
*Copyright 2015, 2021 by Francisco Cancillo & Luis Cancillo
*<p>
*This file is part of the OSPtoRINEX tools.
*<p>
*RXtoRINEX is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
*as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*<p>RXtoRINEX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
*<p>warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*See the GNU General Public License for more details.
*<p>A copy of the GNU General Public License can be found at <http://www.gnu.org/licenses/>.
*
*<p>Ver. |Date |Reason for change
*<p>------+-------+------------------
*<p>V1.0 |2/2015 |First release
*<p>V2.0 |3/2016 |Removed option to allow selection for GPS and SBAS of observables to include.
*<p> |Removed option to generate or not observation file.
*<p> |Added capability to generate GLONASS navigation files
*<p> |Added capability to generate multiple navigation files in V2.10
*<p>V2.1 |2/2018 |Reviewed to run on Linux
*/
//from CommonClasses
#include "ArgParser.h"
#include "Logger.h"
#include "Utilities.h"
#include "GNSSdataFromOSP.h"
#include "RinexData.h"
using namespace std;
//@cond DUMMY
///Compilation date to identify program full version
const string COMPDATE = __DATE__;
///Program name
const string THISPRG = "OSPtoRINEX";
///The command line format
const string CMDLINE = THISPRG + ".exe {options} [OSPfilename]";
///Current program version
const string MYVER = " V2.1 ";
///A common message
const string FILENOK = "Cannot open or create file ";
///The receiver name
const string RECEIVER_NAME = "SiRF";
//The parser object to store options and operators passed in the comman line
ArgParser parser;
//Metavariables for options
int AGENCY, APPEND, ANTN, ANTT, APBIAS, MID8G, MID8R, HELP, LOGLEVEL, NAVI, MINSV, MRKNAM, MRKNUM, OBSERVER, PGM, RINEX, RUNBY, SELSYS, TOFO, VER;
//Metavariables for operators
int OSPF;
//functions in this file
int generateRINEX(FILE*, Logger*);
void prinfNavFile(RinexData &, RinexData::RINEXversion, char, Logger*);
//@endcond
/**main
* gets the command line arguments, sets parameters accordingly and triggers the data acquisition to generate RINEX files.
* Input data are contained in a OSP binary file containing receiver messages (see SiRF IV ICD for details).
* The output is a RINEX observation data file, and optionally a RINEX navigation data file.
* A detailed definition of the RINEX format can be found in the document "RINEX: The Receiver Independent Exchange
* Format Version 2.10" from Werner Gurtner; Astronomical Institute; University of Berne. An updated document exists
* also for Version 3.00.
*
*@param argc the number of arguments passed from the command line
*@param argv the array of arguments passed from the command line
*@return the exit status according to the following values and meaning::
* - (0) no errors have been detected
* - (1) an error has been detected in arguments
* - (2) error when opening the input file
* - (3) error when creating output files or no epoch data exist
*/
int main(int argc, char* argv[]) {
/**The main process sequence follows:*/
/// 1- Defines and sets the error logger object
Logger log("LogFile.txt", string(), string(argv[0]) + MYVER + COMPDATE + string(" START"));
/// 2- Setups the valid options in the command line. They will be used by the argument/option parser
AGENCY = parser.addOption("-y", "--agency", "AGENCY", "Agency name", "AGENCY");
VER = parser.addOption("-v", "--ver", "VER", "RINEX version to generate (V210, V304)", "V210");
MRKNUM = parser.addOption("-u", "--mrknum", "MRKNUM", "Marker number", "MRKNUM");
SELSYS = parser.addOption("-s", "--selsys", "SELSYS", "Systems from input in addition to GPS (R,S or R or S)", "");
RINEX = parser.addOption("-r", "--rinex", "RINEX", "RINEX file name prefix", "PNT1");
RUNBY = parser.addOption("-q", "--runby", "RUNBY", "Who runs the RINEX file generation", "RUNBY");
PGM = parser.addOption("-p", "--program", "PGM", "Program used to generate RINEX file", (char *) (THISPRG+MYVER).c_str());
OBSERVER = parser.addOption("-o", "--observer", "OBSERVER", "Observer name", "OBSERVER");
NAVI = parser.addOption("-n", "--nRINEX", "NAVI", "Generate RINEX navigation file", false);
MRKNAM = parser.addOption("-m", "--mrkname", "MRKNAM", "Marker name", "MRKNAM");
LOGLEVEL = parser.addOption("-l", "--llevel", "LOGLEVEL", "Maximum level to log (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)", "INFO");
ANTT = parser.addOption("-k", "--antype", "ANTT", "Receiver antenna type", "AntennaType");
ANTN = parser.addOption("-j", "--antnum", "ANTN", "Receiver antenna number", "Antenna#");
MINSV = parser.addOption("-i", "--minsv", "MINSV", "Minimun satellites in a fix to acquire observations", "4");
HELP = parser.addOption("-h", "--help", "HELP", "Show usage data and stops", false);
MID8G = parser.addOption("-d", "--gps50bps", "MID8G", "Use MID8 GPS 50bps data to generate nav file", false);
MID8R = parser.addOption("-c", "--glo50bps", "MID8R", "Use MID8 GLONASS 50bps data to generate nav file", false);
APBIAS = parser.addOption("-b", "--bias", "APBIAS", "Apply receiver clock bias to measurements (and time)", true);
APPEND = parser.addOption("-a", "--aend", "APPEND", "Append end-of-file comment lines to Rinex file", false);
/// 3- Setups the default values for operators in the command line
OSPF = parser.addOperator("DATA.OSP");
/// 4- Parses arguments in the command line extracting options and operators
try {
parser.parseArgs(argc, argv);
} catch (string error) {
parser.usage("Argument error: " + error, CMDLINE);
log.severe(error);
return 1;
}
log.info(parser.showOptValues());
log.info(parser.showOpeValues());
if (parser.getBoolOpt(HELP)) {
//help info has been requested
parser.usage("Generates RINEX files from an OSP data file containing SiRF IV receiver messages", CMDLINE);
return 0;
}
/// 5- Sets logging level stated in option
log.setLevel(parser.getStrOpt(LOGLEVEL));
/// 6- Opens the OSP binary file
FILE* inFile;
string fileName = parser.getOperator (OSPF);
if ((inFile = fopen(fileName.c_str(), "rb")) == NULL) {
log.severe(FILENOK + fileName);
return 2;
}
/// 7- Calls generateRINEX to generate RINEX files extracting data from messages in the binary OSP file
int n = generateRINEX(inFile, &log);
log.info("End of RINEX generation. Epochs read: " + to_string((long long) n));
fclose(inFile);
return n>0? 0:3;
}
/**generateRINEX iterates over the input OSP file processing GNSS receiver messages to extract RINEX data and print them.
*
*@param inFile is the FILE containing the binary OSP messages
*@param plog point to the Logger
*@return the number of epochs read in the inFile
*/
int generateRINEX(FILE* inFile, Logger* plog) {
/**The generateRINEX process sequence follows:*/
int epochCount; //to count the number of epochs processed
string outFileName; //the output file name for RINEX files
FILE* obsFile; //the file where RINEX observation data will be printed
vector<string> selSys; //the selected systems
vector<string> selObs; //the empty selected observations
vector<string> observables = getTokens("C1C,L1C,D1C,S1C", ','); //the defined observables in OSP
bool glonassSel = false; //if GLONASS data (observation or navigation) are requested or not
bool prtNav = parser.getBoolOpt(NAVI); //if navigation file will be printed or not
/// 1- Setups the RinexData object members with data given in command line options
string aStr = parser.getStrOpt(SELSYS); //the selected systems
if (aStr.empty()) aStr = "G";
else aStr = "G," + aStr;
selSys = getTokens(aStr, ',');
aStr = parser.getStrOpt(VER);
RinexData::RINEXversion rinexVer = RinexData::V210; //default version is 2.10
if (aStr.compare("V304") == 0) rinexVer = RinexData::V304;
RinexData rinex(rinexVer, plog);
try {
rinex.setHdLnData(RinexData::RUNBY, parser.getStrOpt(PGM), parser.getStrOpt(RUNBY));
rinex.setHdLnData(RinexData::MRKNAME, parser.getStrOpt(MRKNAM));
rinex.setHdLnData(RinexData::MRKNUMBER, parser.getStrOpt(MRKNUM));
rinex.setHdLnData(RinexData::ANTTYPE, parser.getStrOpt(ANTN), parser.getStrOpt(ANTT));
rinex.setHdLnData(RinexData::ANTHEN, (double) 0.0, (double) 0.0, (double) 0.0);
rinex.setHdLnData(RinexData::AGENCY, parser.getStrOpt(OBSERVER), parser.getStrOpt(AGENCY));
//rinex.setHdLnData(RinexData::TOFO, string("GPS"));
rinex.setHdLnData(RinexData::TOFO, 'G');
rinex.setHdLnData(RinexData::WVLEN, (int) 1, (int) 0);
for (vector<string>::iterator it = selSys.begin(); it != selSys.end(); it++) {
rinex.setHdLnData(RinexData::TOBS, it->at(0), observables);
if (it->at(0) == 'R') glonassSel = true;
}
if (!rinex.setFilter(selSys, selObs)) plog->warning("Error in selected systems. Erroneous data ignored");
} catch (string error) {
plog->severe(error);
}
/// 2- Setups the GNSSdataFromOSP object used to extract message data from the OSP file
GNSSdataFromOSP gnssAcq(RECEIVER_NAME, stoi(parser.getStrOpt(MINSV)), parser.getBoolOpt(APBIAS), inFile, plog);
/// 3- Starts data acquisition extracting RINEX header data located in the binary file
if(!gnssAcq.acqHeaderData(rinex)) {
plog->warning("All, or some header data not acquired");
};
if (glonassSel) gnssAcq.acqGLOparams();
/// 4- For the observation RINEX file, generate the filename in standard format, create it, print header,
outFileName = rinex.getObsFileName(parser.getStrOpt(RINEX));
if ((obsFile = fopen(outFileName.c_str(), "w")) == NULL) {
plog->severe(FILENOK + outFileName);
return 0;
}
try {
rinex.printObsHeader(obsFile);
/// and iterate over the binary OSP file extracting epoch by epoch data and printing them
epochCount = 0;
rewind(inFile);
while (gnssAcq.acqEpochData(rinex, parser.getBoolOpt(MID8G), parser.getBoolOpt(MID8R))) {
rinex.printObsEpoch(obsFile);
epochCount++;
}
if (parser.getBoolOpt(APPEND)) rinex.printObsEOF(obsFile);
} catch (string error) {
plog->severe(error);
}
fclose(obsFile);
/// 5- If navigation RINEX file requested, generate the filename in standard format, create it, print header,
if (prtNav) {
if (rinexVer == RinexData::V304) {
prinfNavFile(rinex, rinexVer, 'M', plog);
}
else {
for (vector<string>::iterator it = selSys.begin(); it != selSys.end(); it++) {
prinfNavFile(rinex, rinexVer, it->at(0), plog);
}
}
}
return epochCount;
}
/**prinfNavFile prints a RINEX navigation file from the navigation data stored stored in the given RinexData object.
*File format will be according the given version, and for the given satellite system if version to be generated is 2.10.
*
*@param rinex is the RinexData object containing navigation data for the file to be printed
*@param ver is the RINEX version of the file to be generated
*@param sysId is the identification of the satellite system data to be printed. Only relevant for version 2.10 files.
*@param plog a pointer to the Logger object where logging messages will be printed
*/
void prinfNavFile(RinexData &rinex, RinexData::RINEXversion ver, char sysId, Logger* plog) {
FILE* navFile; //the file where RINEX navigation data will be printed
string outFileName; //the output file name for RINEX files
string fnameSfx;
switch (ver) {
case RinexData::V210:
switch (sysId) {
case 'G': fnameSfx = "N"; break;
case 'R': fnameSfx = "G"; break;
case 'S': fnameSfx = "H"; break;
default:
plog->warning("Cannot print RINEX V2.10 navigation file for system " + string(1, sysId));
return;
}
outFileName = rinex.getNavFileName(parser.getStrOpt(RINEX), fnameSfx);
break;
case RinexData::V304:
outFileName = rinex.getNavFileName(parser.getStrOpt(RINEX));
break;
}
if ((navFile = fopen(outFileName.c_str(), "w")) == NULL) {
plog->warning(FILENOK + outFileName);
return;
}
try {
rinex.setFilter(vector<string>(1,string(1,sysId)), vector<string>());
rinex.printNavHeader(navFile);
rinex.printNavEpochs(navFile);
} catch (string error) {
plog->severe(error);
}
fclose(navFile);
}