/* Programheader * Name: readRTCM.cpp Project: SSR test Version: $Id: readRTCM3.cpp 6208 2014-09-25 14:39:00Z stuerze $ Description: reads, decodes and writes mixed RTCM SSR data sets supported messages: - System: part of 1013, - Ephemeris Data: 1019, 1020, - Orbit and Clock: 1057, 1058, 1061,1063, 1064, 1067 - Code Biases: 1059, 1065, - Phase Biases: 1265, 1266, - VTEC: 1264 */ extern "C" { #include "clock_orbit_rtcm.h" #include "rtcm3torinex.h" } #include #include #include #include #include #include #include #include #include using namespace std; typedef enum { GPS, GLO, GAL, QZSS, SBAS, BDS } SATSYS; int GPSUTCdiff = 16; /* prototype, don't use any of this code in a final application */ void printClock(const char* filename, struct ClockOrbit* clockOrb, SATSYS sys, char satSys, int offsetGnss); void printOrbit(const char* filename, struct ClockOrbit* clockOrb, SATSYS sys, char satSys, int offsetGnss); void printUra(const char* filename, struct ClockOrbit* clockOrb, SATSYS sys, char satSys, int offsetGnss); void printVtec(const char* filename, struct VTEC* vtec); void printCodeBias(const char* filename, struct CodeBias* codeBias, SATSYS sys, char satSys, int offsetGnss); void printPhaseBias(const char* filename, struct PhaseBias* phaseBias, SATSYS sys, char satSys, int offsetGnss); void printSystemParameters(const char* filename, struct RTCM3ParserData* parser); void printTextMessageType(const char* filename, int messageType); void printGpsEph(const char* filename, struct gpsephemeris* ephemerisGPS); void printGlonassEph(const char* filename, struct glonassephemeris* ephemerisGLO); void decodeFileContent(char* inputFile, char* outputFile); int main(void) { char inFilename[124] = "ssr2_svpb_data/svpb224m.rtc"; char outFilename[124] = "ssr2_svpb_data/svpb224m_bkg.txt"; unlink(outFilename); // Decode and save rtcm & ssr messages decodeFileContent(inFilename, outFilename); return 0; } void decodeFileContent(char* inputFile, char* outputFile) { char obuffer[CLOCKORBIT_BUFFERSIZE]; long int offset = 0; FILE * pFile = fopen(inputFile, "rb"); if (pFile == NULL) { fputs("File error", stderr); return; } while (1) { RTCM3ParserData rtcm3Out; memset(&rtcm3Out, 0, sizeof(rtcm3Out)); ClockOrbit coOut; memset(&coOut, 0, sizeof(coOut)); CodeBias cbOut; memset(&cbOut, 0, sizeof(cbOut)); PhaseBias pbOut; memset(&pbOut, 0, sizeof(pbOut)); VTEC vtecOut; memset(&vtecOut, 0, sizeof(vtecOut)); fseek(pFile, offset, SEEK_SET); int l = fread(obuffer, 1, CLOCKORBIT_BUFFERSIZE, pFile); int bytesUsed = 0; GCOB_RETURN nl = GetSSR(&coOut, &cbOut, &vtecOut, &pbOut, obuffer, l, &bytesUsed); offset += bytesUsed; if (nl <= -30) { fprintf(stderr, "Not enough data. Error code: %d .\n", nl); break; } else if (nl < 0) { fprintf(stderr, "GCOB_RETURN %d\nTry now RTCM3TORINEX\n", nl); int z; for (z = 0; z < bytesUsed; ++z) { HandleByte(&rtcm3Out, (unsigned int) obuffer[z]); } fprintf(stderr, "RTCM message type: %d\n",rtcm3Out.blocktype); switch (rtcm3Out.blocktype) { case 1013: printSystemParameters(outputFile, &rtcm3Out); break; case 1019: printGpsEph(outputFile, &rtcm3Out.ephemerisGPS); break; case 1020: printGlonassEph(outputFile, &rtcm3Out.ephemerisGLONASS); break; case 1029:// rtcm3torinex is unable to decode this type of RTCM message printTextMessageType(outputFile, rtcm3Out.blocktype); break; case 1230:// rtcm3torinex is unable to decode this type of RTCM message printTextMessageType(outputFile, rtcm3Out.blocktype); } } else if (nl == GCOBR_OK) {//fprintf(stderr, "GCOBR_OK\n"); switch (coOut.messageType) { case 1057: printOrbit(outputFile, &coOut, GPS, 'G', CLOCKORBIT_OFFSETGPS); break; case 1058: printClock(outputFile, &coOut, GPS, 'G', CLOCKORBIT_OFFSETGPS); break; case 1061: printUra(outputFile, &coOut, GPS, 'G', CLOCKORBIT_OFFSETGPS); break; case 1063: printOrbit(outputFile, &coOut, GLO, 'R', CLOCKORBIT_OFFSETGLONASS); break; case 1064: printClock(outputFile, &coOut, GLO, 'R', CLOCKORBIT_OFFSETGLONASS); break; case 1067: printUra(outputFile, &coOut, GLO, 'R', CLOCKORBIT_OFFSETGLONASS); break; } switch (cbOut.messageType) { case 1059: printCodeBias(outputFile, &cbOut, GPS, 'G', CLOCKORBIT_OFFSETGPS); break; case 1065: printCodeBias(outputFile, &cbOut, GLO, 'R', CLOCKORBIT_OFFSETGLONASS); break; } switch (pbOut.messageType) { case 1265: printPhaseBias(outputFile, &pbOut, GPS, 'G', CLOCKORBIT_OFFSETGPS); break; case 1266: printPhaseBias(outputFile, &pbOut, GLO, 'R', CLOCKORBIT_OFFSETGLONASS); break; } if (vtecOut.EpochTime) { printVtec(outputFile, &vtecOut); } } else if (nl == GCOBR_MESSAGEFOLLOWS) { fprintf(stderr, "GCOBR_MESSAGEFOLLOWS\n"); } } } void printClock(const char* filename, struct ClockOrbit* clockOrb, SATSYS sys, char satSys, int offsetGnss) { int timeOffset = 0; string datum[2] = { "ITRF", "LOCAL" }; FILE *filestream = fopen(filename, "ab+"); if (filestream == NULL) { fprintf(stderr, "ERROR: open file %s\n", filename); return; } switch (sys) { case GPS: fprintf(filestream, "**RTCM 3 - SSR GPS Clock Message <%d>\nSystem:\t\t%10d (GPS)\nTime of week [s]:", clockOrb->messageType, sys); timeOffset = 0; break; case GLO: fprintf(filestream, "**RTCM 3 - SSR GLONASS Clock Message <%d>\nSystem:\t\t%10d (GLONASS)\nTime of day [s]:", clockOrb->messageType, sys); timeOffset = (GPSUTCdiff - 3 * 3600); break; } fprintf(filestream, "\t%10d\nUpdate Interval:\t%10d\nIOD SSR:\t\t%10d\n" "ProviderId:\t\t%10d\nSolutionId:\t\t%10d\nNumber of Satellites:\t%10d\n" "PRN A0[m] A1[mm/s] A2[mm/s^2]\n", clockOrb->EpochTime[sys] + timeOffset, clockOrb->UpdateInterval, clockOrb->SSRIOD, clockOrb->SSRProviderID, clockOrb->SSRSolutionID, clockOrb->NumberOfSat[sys]); unsigned int i = 0; for (i = offsetGnss; i < offsetGnss + clockOrb->NumberOfSat[sys]; ++i) { fprintf(filestream, "%c%02d %10.4f%10.3f%10.5f\n", satSys, clockOrb->Sat[i].ID, clockOrb->Sat[i].Clock.DeltaA0, clockOrb->Sat[i].Clock.DeltaA1 * 1.0E3, clockOrb->Sat[i].Clock.DeltaA2 * 1.0E3); } fclose(filestream); return; } void printOrbit(const char* filename, struct ClockOrbit* clockOrb, SATSYS sys, char satSys, int offsetGnss) { int timeOffset = 0; string datum[2] = { "ITRF", "LOCAL" }; FILE *filestream = fopen(filename, "ab+"); if (filestream == NULL) { fprintf(stderr, "ERROR: open file %s\n", filename); return; } switch (sys) { case GPS: fprintf(filestream, "**RTCM 3 - SSR GPS Orbit Message <%d>\nSystem:\t\t%10d (GPS)\nTime of week [s]:", clockOrb->messageType, sys); timeOffset = 0; break; case GLO: fprintf(filestream, "**RTCM 3 - SSR GLONASS Orbit Message <%d>\nSystem:\t\t%10d (GLONASS)\nTime of day [s]:", clockOrb->messageType, sys); timeOffset = (GPSUTCdiff - 3 * 3600); break; } fprintf(filestream, "\t%10d\nUpdate Interval:\t%10d\nIOD SSR:\t\t%10d\n" "ProviderId:\t\t%10d\nSolutionId:\t\t%10d\nReference Datum:\t\t%s\nNumber of Satellites:\t%10d\n" "PRN IOD Radial AlongTrk CrossTrk[m] DotDelta[mm/s]\n", clockOrb->EpochTime[sys] + timeOffset, clockOrb->UpdateInterval, clockOrb->SSRIOD, clockOrb->SSRProviderID, clockOrb->SSRSolutionID, (datum[clockOrb->SatRefDatum]).c_str(), clockOrb->NumberOfSat[sys]); unsigned int i = 0; for (i = offsetGnss; i < offsetGnss + clockOrb->NumberOfSat[sys]; ++i) { fprintf(filestream, "%c%02d %5d %10.4f%10.4f%10.4f%10.3f%10.3f%10.3f\n", satSys, clockOrb->Sat[i].ID, clockOrb->Sat[i].IOD, clockOrb->Sat[i].Orbit.DeltaRadial, clockOrb->Sat[i].Orbit.DeltaAlongTrack, clockOrb->Sat[i].Orbit.DeltaCrossTrack, clockOrb->Sat[i].Orbit.DotDeltaRadial * 1.0E3, clockOrb->Sat[i].Orbit.DotDeltaAlongTrack * 1.0E3, clockOrb->Sat[i].Orbit.DotDeltaAlongTrack * 1.0E3); } fclose(filestream); return; } void printUra(const char* filename, struct ClockOrbit* clockOrb, SATSYS sys, char satSys, int offsetGnss) { int timeOffset = 0; FILE *filestream = fopen(filename, "ab+"); if (filestream == NULL) { fprintf(stderr, "ERROR: open file %s\n", filename); return; } switch (sys) { case GPS: fprintf(filestream, "**RTCM 3 - SSR GPS URA Message <%d>\nSystem:\t\t%10d (GPS)\nTime of week [s]:", clockOrb->messageType, sys); timeOffset = 0; break; case GLO: fprintf(filestream, "**RTCM 3 - SSR GLONASS URA Message <%d>\nSystem:\t\t%10d (GLONASS)\nTime of day [s]:", clockOrb->messageType, sys); timeOffset = (GPSUTCdiff - 3 * 3600); break; } fprintf(filestream, "\t%10d\nUpdate Interval:\t%10d\nIOD SSR:\t\t%10d\n" "ProviderId:\t\t%10d\nSolutionId:\t\t%10d\nNumber of Satellites:\t%10d\n" "PRN URA[m]\n", clockOrb->EpochTime[sys] + timeOffset, clockOrb->UpdateInterval, clockOrb->SSRIOD, clockOrb->SSRProviderID, clockOrb->SSRSolutionID, clockOrb->NumberOfSat[sys]); unsigned int i = 0; for (i = offsetGnss; i < offsetGnss + clockOrb->NumberOfSat[sys]; ++i) { fprintf(filestream, "%c%02d %10.4f\n", satSys, clockOrb->Sat[i].ID, clockOrb->Sat[i].UserRangeAccuracy); } fclose(filestream); return; } void printCodeBias(const char* filename, struct CodeBias* codeBias, SATSYS sys, char satSys, int offsetGnss) { int timeOffset = 0; FILE *filestream = fopen(filename, "ab+"); if (filestream == NULL) { fprintf(stderr, "ERROR: open file %s\n", filename); return; } switch (sys) { case GPS: fprintf(filestream, "**RTCM 3 - SSR GPS Code Bias Message <%d>\nSystem:\t\t%10d (GPS)\nTime of week [s]:", codeBias->messageType, sys); timeOffset = 0; break; case GLO: fprintf(filestream, "**RTCM 3 - SSR GLONASS Code Bias Message <%d>\nSystem:\t\t%10d (GLONASS)\nTime of day [s]:", codeBias->messageType, sys); timeOffset = (GPSUTCdiff - 3 * 3600); break; } fprintf(filestream, "\t%10d\nUpdate Interval:\t%10d\nIOD SSR:\t\t%10d\n" "ProviderId:\t\t%10d\nSolutionId:\t\t%10d\nNumber of Satellites:\t%10d\n" "PRN Number Type Bias[m] Type Bias[m]\n", codeBias->EpochTime[sys] + timeOffset, codeBias->UpdateInterval, codeBias->SSRIOD, codeBias->SSRProviderID, codeBias->SSRSolutionID, codeBias->NumberOfSat[sys]); unsigned int i = 0; for (i = offsetGnss; i < offsetGnss + codeBias->NumberOfSat[sys]; ++i) { fprintf(filestream, "%c%02d %5d ", satSys, codeBias->Sat[i].ID, codeBias->Sat[i].NumberOfCodeBiases); int j; for (j = 0; j < codeBias->Sat[i].NumberOfCodeBiases; j++) { fprintf(filestream, "%10d %12.2f", codeBias->Sat[i].Biases[j].Type, codeBias->Sat[i].Biases[j].Bias); } fprintf(filestream, "\n"); } fclose(filestream); return; } void printPhaseBias(const char* filename, struct PhaseBias* phaseBias, SATSYS sys, char satSys, int offsetGnss) { int timeOffset = 0; FILE *filestream = fopen(filename, "ab+"); if (filestream == NULL) { fprintf(stderr, "ERROR: open file %s\n", filename); return; } switch (sys) { case GPS: fprintf(filestream, "**RTCM 3 - SSR GPS Phase Bias Message <%d>\nSystem:\t\t%10d (GPS)\nTime of week [s]:", phaseBias->messageType, sys); timeOffset = 0; break; case GLO: fprintf(filestream, "**RTCM 3 - SSR GLONASS Phase Bias Message <%d>\nSystem:\t\t%10d (GLONASS)\nTime of day [s]:", phaseBias->messageType, sys); timeOffset = (GPSUTCdiff - 3 * 3600); break; } fprintf(filestream, "\t%10d\nUpdate Interval:\t\t%10d\nIOD SSR:\t\t\t%10d\n" "ProviderId:\t\t\t%10d\nSolutionId:\t\t\t%10d\n" "DispersiveBiasConsistencyIndicator\t%2d\nMWConsistencyIndicator\t\t%10d\nNumber of Satellites:\t\t%10d\n" "PRN Yaw[deg] YawRate[deg/sec] Number Type INT-ind WL-ind DISC-count Bias[m] Type INT-ind WL-ind DISC-count Bias[m]\n", phaseBias->EpochTime[sys] + timeOffset, phaseBias->UpdateInterval, phaseBias->SSRIOD, phaseBias->SSRProviderID, phaseBias->SSRSolutionID, phaseBias->DispersiveBiasConsistencyIndicator , phaseBias->MWConsistencyIndicator, phaseBias->NumberOfSat[sys]); unsigned int i = 0; for (i = offsetGnss; i < offsetGnss + phaseBias->NumberOfSat[sys]; ++i) { fprintf(filestream, "%c%02d %8.3f %8.4f %12d", satSys,phaseBias->Sat[i].ID, phaseBias->Sat[i].YawAngle, phaseBias->Sat[i].YawRate, phaseBias->Sat[i].NumberOfPhaseBiases); int j; for (j = 0; j < phaseBias->Sat[i].NumberOfPhaseBiases; j++) { fprintf(filestream, "%6d %6d %6d %10d %10.2f", phaseBias->Sat[i].Biases[j].Type, phaseBias->Sat[i].Biases[j].SignalIntegerIndicator, phaseBias->Sat[i].Biases[j].SignalsWideLaneIntegerIndicator, phaseBias->Sat[i].Biases[j].SignalDiscontinuityCounter, phaseBias->Sat[i].Biases[j].Bias); } fprintf(filestream, "\n"); } fclose(filestream); return; } void printVtec(const char* filename, struct VTEC* vtec) { FILE *filestream = fopen(filename, "ab+"); if (filestream == NULL) { fprintf(stderr, "ERROR: open file %s\n", filename); return; } fprintf(filestream, "**RTCM 3 - SSR VTEC Message <1264>\n" "Time of week [s]:\t%10d\nUpdate Interval:\t%10d\nIOD SSR:\t\t%10d\n" "ProviderId:\t\t%10d\nSolutionId:\t\t%10d\nNumber of Layers:\t%10d\n" "Quality:\t\t%13.3f\n", vtec->EpochTime, vtec->UpdateInterval, vtec->SSRIOD, vtec->SSRProviderID, vtec->SSRSolutionID, vtec->NumLayers, vtec->Quality); unsigned int i, j, k; for (i = 0; i < vtec->NumLayers; ++i) { fprintf(filestream, "Layer: %2d Height [m]: %f Degree n:%2d Order m:%2d\n", i, vtec->Layers[i].Height, vtec->Layers[i].Degree, vtec->Layers[i].Order); for (j = 0; j <= vtec->Layers[i].Degree; ++j) { fprintf(filestream, "Cn%d [TECU]: ", j); for (k = 0; k <= vtec->Layers[i].Order; ++k) { fprintf(filestream, " %7.3f", vtec->Layers[i].Cosinus[k][j]); } fprintf(filestream, "\n"); } for (j = 1; j <= vtec->Layers[i].Degree; ++j) { fprintf(filestream, "Sn%d [TECU]: ", j); for (k = 0; k <= vtec->Layers[i].Order; ++k) { fprintf(filestream, " %7.3f", vtec->Layers[i].Sinus[k][j]); } fprintf(filestream, "\n"); } } fclose(filestream); return; } void printSystemParameters(const char* filename, struct RTCM3ParserData* parser) { FILE *filestream = fopen(filename, "ab+"); if (filestream == NULL) { fprintf(stderr, "ERROR: open file %s\n", filename); return; } fprintf(filestream, "**RTCM 3 - System parameters <1013>\n" "Modified Julian Day:\t %d\nSeconds of Day:\t\t%2d\nLeapSeconds:\t\t%2d\n", parser->modjulday, parser->secofday, parser->leapsec); fclose(filestream); return; } void printTextMessageType(const char* filename, int messageType) { FILE *filestream = fopen(filename, "ab+"); if (filestream == NULL) { fprintf(stderr, "ERROR: open file %s\n", filename); return; } fprintf(filestream, "**RTCM 3 - Text Message <%d>\n", messageType); fclose(filestream); return; } void printGpsEph(const char* filename, struct gpsephemeris* ephemerisGPS) { FILE *filestream = fopen(filename, "ab+"); if (filestream == NULL) { fprintf(stderr, "ERROR: open file %s\n", filename); return; } fprintf(filestream, "**RTCM 3 - GPS Ephemeris <1019>\n" "PRN %13d\n" "IODE %13d\n" "URAindex [1..15] %13d\n" "SVhealth %13d\n" "GPSweek %13d\n" "IODC %13d\n" "TOW [s] %13d\n" "TOC [s] %13d\n" "TOE [s] %13d\n" "clock_bias [s] %13e\n" "clock_drift[s/s] %13e\n" "clock_driftrate [s/s^2]%13e\n" "Crs [m] %13e\n" "Delta_n [rad/s] %13e\n" "M0 [rad] %13e\n" "Cuc [rad] %13e\n" "e %13e\n" "Cus [rad] %13e\n" "sqrt_A [m^0.5] %13e\n" "Cic [rad] %13e\n" "OMEGA0 [rad] %13e\n" "Cis [rad] %13e\n" "i0 [rad] %13e\n" "Crc [m] %13e\n" "omega [rad] %13e\n" "OMEGADOT [rad/s] %13e\n" "IDOT [rad/s] %13e\n" "TGD [s] %13e\n", ephemerisGPS->satellite, ephemerisGPS->IODE, ephemerisGPS->URAindex, ephemerisGPS->SVhealth, ephemerisGPS->GPSweek, ephemerisGPS->IODC, ephemerisGPS->TOW, ephemerisGPS->TOC, ephemerisGPS->TOE, ephemerisGPS->clock_bias, ephemerisGPS->clock_drift, ephemerisGPS->clock_driftrate, ephemerisGPS->Crs, ephemerisGPS->Delta_n, ephemerisGPS->M0, ephemerisGPS->Cuc, ephemerisGPS->e, ephemerisGPS->Cus, ephemerisGPS->sqrt_A, ephemerisGPS->Cic, ephemerisGPS->OMEGA0, ephemerisGPS->Cis, ephemerisGPS->i0, ephemerisGPS->Crc, ephemerisGPS->omega, ephemerisGPS->OMEGADOT, ephemerisGPS->IDOT, ephemerisGPS->TGD); fclose(filestream); return; return; } void printGlonassEph(const char* filename, struct glonassephemeris* ephemerisGLO) { FILE *filestream = fopen(filename, "ab+"); if (filestream == NULL) { fprintf(stderr, "ERROR: open file %s\n", filename); return; } fprintf(filestream, "**RTCM 3 - GLONASS Ephemeris <1020>\n" "SV %10d\n" "frequency_number %10d\n" "tb [s] %10d\n" "tk [s] %10d\n" "E [days] %10d\n" "tau [s] %13e\n" "gamma %13e\n" "x_pos [km] %13e\n" "x_velocity [km/s] %13e\n" "x_acceleration [km/s^2] %13e\n" "y_pos [km] %13e\n" "y_velocity [km/s] %13e\n" "y_acceleration [km/s^2] %13e\n" "z_pos [km] %13e\n" "z_velocity [km/s] %13e\n" "z_acceleration [km/s^2] %13e\n", ephemerisGLO->almanac_number, ephemerisGLO->frequency_number, ephemerisGLO->tb, ephemerisGLO->tk, ephemerisGLO->E, ephemerisGLO->tau, ephemerisGLO->gamma, ephemerisGLO->x_pos, ephemerisGLO->x_velocity, ephemerisGLO->x_acceleration, ephemerisGLO->y_pos, ephemerisGLO->y_velocity, ephemerisGLO->y_acceleration, ephemerisGLO->z_pos, ephemerisGLO->z_velocity, ephemerisGLO->z_acceleration); fclose(filestream); return; }