/* Copyright 1997, 1998, 1999 University Corporation for Atmospheric Research This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Author: Louis H. Estey Date: July 1999 part of the BINEX source code release, see also: http://www.unavco.ucar.edu/software/binex */ #include "binex.h" static unsigned short ashtech_snr[2][3]= { 1, 90, 210, 1, 150, 250 }; unsigned long next_BINEX_record #if KR_C (file, rec) FILE_INFO *file; unsigned char *rec; #else (FILE_INFO *file, unsigned char *rec) #endif { char synchronization[5]; unsigned char j, n, n_length, crc[16]; unsigned long i, id, length, len_offset, mess_offset, crc_offset; static bool first_pass= (bool)TRUE; switch (first_pass) { case TRUE: if (sizeof(char) != 1 || sizeof(unsigned char) != 1 || sizeof(short) != 2 || sizeof(unsigned short) != 2 || sizeof(long) != 4 || sizeof(unsigned long) != 4 || sizeof(float) != 4 || sizeof(double) != 8) { fprintf(stderr, "next_BINEX_record(): compiler/system configuration results in non-compatible data type sizes\n"); exit(-1); } teq.tr.offset= 0; first_pass= (bool)FALSE; break; case FALSE: if (file->fp != stdin) /* re-position pointer in file (in case of bad read on previous attempt) */ fseek(file->fp, teq.tr.offset, SEEK_SET); } /* read stream pointed to by file->fp until potential synchronization/endian byte is found (but might be data) */ do { if ((size_t)fread((void *)&rec[0], (size_t)1, (size_t)1, file->fp) < 1) { if (feof(file->fp)) return(NORMAL_BINEX_EOF); else return(BAD_BINEX_READ); } } while (!feof(file->fp) && rec[0] != BINEX_F_stx_LE && rec[0] != BINEX_F_stx_BE && rec[0] != BINEX_FBstx_LE && rec[0] != BINEX_FBstx_BE); if (file->fp != stdin) /* record position in file */ teq.tr.offset= ftell(file->fp); if (teq.trans.opt_X & DIAGNOSTICS) { sprintf(synchronization, "0x%02x", (int)rec[0]); file_position(file, -1L, synchronization); } /* byte reversal needed for this record? */ switch (teq.tr.little_endian) { case TRUE: /* processor is little-endian */ switch (rec[0]) { case BINEX_F_stx_BE: case BINEX_FBstx_BE: teq.tr.binex.bytes_reversed= (bool)TRUE; teq.tr.binex.little_endian_record= (bool)FALSE; break; default: teq.tr.binex.bytes_reversed= (bool)FALSE; teq.tr.binex.little_endian_record= (bool)TRUE; } break; case FALSE: /* processor is big-endian */ switch (rec[0]) { case BINEX_F_stx_LE: case BINEX_FBstx_LE: teq.tr.binex.bytes_reversed= (bool)TRUE; teq.tr.binex.little_endian_record= (bool)TRUE; break; default: teq.tr.binex.bytes_reversed= (bool)FALSE; teq.tr.binex.little_endian_record= (bool)FALSE; } break; } /* get the record ID */ id= read_ubnxi(file, &rec[i= 1], &n); switch (n) { case 0x00: return(BAD_BINEX_READ); } len_offset= i+= (unsigned long)n; if (teq.trans.opt_X & DIAGNOSTICS) record_type((int)id); /* get the record length */ length= read_ubnxi(file, &rec[i], &n); switch (n) { case 0x00: return(BAD_BINEX_READ); } n_length= n; mess_offset= i+= (unsigned long)n; /* get the record message */ if ((size_t)fread((void *)&rec[i], (size_t)1, (size_t)length, file->fp) < (size_t)length) return(BAD_BINEX_READ); i+= length; if (length < 128) n= 0x01; else if (length < 4096) n= 0x02; else if (length < 1048576) n= 0x04; else n= 0x10; /* read checksum/CRC; then verify checksum/CRC: record ID bytes through to end of record message bytes */ if ((size_t)fread((void *)&rec[i], (size_t)1, (size_t)n, file->fp) < (size_t)n) return(BAD_BINEX_READ); crc_offset= 0; binex_crc(crc, rec + 1, (unsigned char *)NULL, &crc_offset, i-1, 0, teq.tr.binex.bytes_reversed); if (memcmp((void *)crc, (void *)&rec[i], (size_t)n)) /* checksum/CRC mismatch */ return(BAD_BINEX_CHECKSUM); switch (rec[0]) { case BINEX_FBstx_LE: case BINEX_FBstx_BE: /* reversible record: need to read and check reversed length bytes and terminating synchronization byte */ i+= (unsigned long)n; if ((size_t)fread((void *)&rec[i], (size_t)1, (size_t)n_length, file->fp) < (size_t)n_length) return(BAD_BINEX_READ); for (j= 0; j < n_length; j++) if (rec[len_offset + j] != rec[i + n_length - 1 - j]) return(BAD_BINEX_READ); i+= (unsigned long)n_length; if ((size_t)fread((void *)&rec[i], (size_t)1, (size_t)1, file->fp) < (size_t)1) return(BAD_BINEX_READ); switch (rec[0]) { case BINEX_FBstx_LE: if (rec[i] != BINEX_FBetx_LE) return(BAD_BINEX_READ); break; case BINEX_FBstx_BE: if (rec[i] != BINEX_FBetx_BE) return(BAD_BINEX_READ); break; } } /* at this point, rec points to a complete BINEX record, from the initial synchronization/endian byte to the last byte (which is either the last CRC byte for a forward-readable record, or the terminating synchronization/endian byte for a reversible record) */ if (file->fp != stdin) /* record position in file: */ teq.tr.offset= ftell(file->fp); switch (id) { case BINEX_SITE: break; case BINEX_GNSS_NAV: return(decompose_binex_01(file, rec + mess_offset)); case BINEX_GNSS_DATA: return(decompose_binex_02(file, rec + mess_offset)); case BINEX_GNSS_DATA_PROTO: return(decompose_binex_7f(file, rec + mess_offset)); case BINEX_SITE_DATA: break; } return (NO_KNOWN_BINEX); } /********************************************************************/ unsigned long decompose_binex_01 #if KR_C (file, rec) FILE_INFO *file; unsigned char *rec; #else (FILE_INFO *file, unsigned char *rec) #endif { /* function to decompose a BINEX record 0x01 to components of RINEX_NAV struct */ unsigned char ret; unsigned long type; switch (rec[0]) { case 0x01: if (!binex_extract_SV_id(rec[1], &nav.satellite.system)) { fprintf(stderr, "decompose_binex_01(): unknown satellite constellation (= 0x%02x)\n", (int)(rec[1] >> 5 & 0x03)); return(NO_KNOWN_BINEX); } break; default: return(NO_KNOWN_BINEX); } if (ret= binary_NAV((int)nav.satellite.system.sys)) return(ret); switch (rec[0]) { case 0x01: type= (unsigned long)NAV_IS_BINEX_01_01; break; } if (ret= binary_ephemeris(rec+2, type)) return(ret); return (BINEX_GNSS_NAV); } /********************************************************************/ unsigned long decompose_binex_7f #if KR_C (file, rec) FILE_INFO *file; unsigned char *rec; #else (FILE_INFO *file, unsigned char *rec) #endif { /* function to decompose a BINEX record 0x7f to components of RINEX_OBS struct */ static unsigned char ret; static double receive_time; static unsigned long minutes, offset; static unsigned short msec; switch (rec[0]) { case 0x00: /* subrecord 0x00: prototype for JPL LEO mission support */ offset= 1L; extract_uint4(rec, &offset, &minutes); if (!(teq.trans.set_X & SET_GPS_WEEK)) teq.tr.GPS_week= (int)floor((double)minutes/10080.); extract_uint2(rec, &offset, &msec); receive_time= 60.*fmod((double)minutes, 10080.) + (double)msec/1000.; switch (obs_epoch_clock_adjustment(file, &receive_time, 0., &obs.observation.epoch)) { case VALID_EPOCH: break; case CORRUPTED_EPOCH: return(NO_KNOWN_BINEX); default: binary_read_failure(INVALID_EPOCH, (unsigned char)BINEX_GNSS_DATA_PROTO, file); } if (ret= binary_GPS_only_OBS(file, rec, OBS_IS_BINEX_7f_00)) return(NO_KNOWN_BINEX); if (!constellation_total(file, (rec[7] & 0x1f) + 0x01, 0x20)) return(NO_KNOWN_BINEX); if (!constellation_array(file)) return(NO_KNOWN_BINEX); (void)constellation_processing(file, (unsigned char *)NULL, rec, OBS_IS_BINEX_7f_00); break; default: return(NO_KNOWN_BINEX); } return (BINEX_GNSS_DATA_PROTO); } /********************************************************************/ void binex_01_01_ephemeris #if KR_C (rec) unsigned char *rec; #else (unsigned char *rec) #endif { short s; unsigned short us, word; long l, ToC, ToE, ToW; unsigned long offset, day, ul; float f; double d; offset= 0; switch (nav.satellite.system.sys) { case NAVSTAR_GPS: extract_uint2(rec, &offset, &us); nav.satellite.ephemeris.type.GPS.gps_week= (double)adjust_week("Ashtech SNV record", (int)us, 1024); extract_sint4(rec, &offset, &ToW); nav.satellite.ephemeris.type.GPS.ToW= (double)ToW; GPS_to_epoch(&nav.satellite.ephemeris.ToW, (unsigned int)nav.satellite.ephemeris.type.GPS.gps_week, (double)ToW); extract_sint4(rec, &offset, &ToE); ToC= ToE; nav.satellite.ephemeris.type.GPS.ToE= (double)ToE; GPS_to_epoch(&nav.satellite.ephemeris.ToE, (unsigned int)nav.satellite.ephemeris.type.GPS.gps_week, (double)ToE); GPS_to_epoch(&nav.satellite.ephemeris.ToC, (unsigned int)nav.satellite.ephemeris.type.GPS.gps_week, (double)ToC); correct_nav_times(ToC, ToE, ToW); extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.TGD= (double)f; extract_sint4(rec, &offset, &l); nav.satellite.ephemeris.type.GPS.IODC= (double)l; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.af2= (double)f; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.af1= (double)f; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.af0= (double)f; extract_sint4(rec, &offset, &l); nav.satellite.ephemeris.type.GPS.IODE= (double)l; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.dn= (double)f * GPS_PI; extract_real8(rec, &offset, &nav.satellite.ephemeris.type.GPS.M); extract_real8(rec, &offset, &nav.satellite.ephemeris.type.GPS.e); extract_real8(rec, &offset, &nav.satellite.ephemeris.type.GPS.sqrt_a); extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.Cic= (double)f; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.Crc= (double)f; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.Cis= (double)f; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.Crs= (double)f; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.Cuc= (double)f; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.Cus= (double)f; extract_real8(rec, &offset, &nav.satellite.ephemeris.type.GPS.OMEGA); extract_real8(rec, &offset, &nav.satellite.ephemeris.type.GPS.omega); extract_real8(rec, &offset, &nav.satellite.ephemeris.type.GPS.i); extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.OMEGA_dot= (double)f * GPS_PI; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.i_dot= (double)f * GPS_PI; extract_real4(rec, &offset, &f); nav.satellite.ephemeris.type.GPS.URA= (double)f/10.; extract_sint2(rec, &offset, &s); switch (teq.edit.opt_X & BINEX_OUT) { case BINEX_OUT: nav.satellite.ephemeris.type.GPS.health= (double)s; /* store everything */ break; default: nav.satellite.ephemeris.type.GPS.health= (double)(s >> 5 & 0x0001); /* to obtain the MSB of the 6-bit word */ } extract_sint2(rec, &offset, &s); switch (teq.edit.opt_X & BINEX_OUT) { case BINEX_OUT: nav.satellite.ephemeris.type.GPS.fit_interval= (double)s; /* store everything */ break; default: nav.satellite.ephemeris.type.GPS.fit_interval= (double)(s & 0x0001); } break; case GLONASS: fprintf(stderr, "binex_01_01_ephemeris(): GLONASS navigation message code not complete\n"); exit(-1); } } /********************************************************************/ unsigned char binex_7f_00_constellation #if KR_C (rec, data_array) unsigned char *rec; bool data_array; #else (unsigned char *rec, bool data_array) #endif { unsigned char i, n, total; /* function to determine the current list of (GPS) SVs (the constellation): */ /* loop through the SVs */ total= (rec[7] & 0x1f) + 0x01; for (i= n= 0; i < total; i++) switch (binex_extract_SV_id(rec[8 + i], &obs.observation.constellation.satellite[n].system)) { case TRUE: n++; break; case FALSE: fprintf(stderr, "binex_7f_00_constellation(): unknown satellite constellation (= 0x%02x)\n", (int)(rec[8 + i] >> 5 & 0x03)); break; } return (n); } /********************************************************************/ void binex_7f_00_obs #if KR_C (rec) unsigned char *rec; #else (unsigned char *rec) #endif { static unsigned long offset; static unsigned char index, i, n, chn_as_lli, snr_l1, snr_l2, perr, mperr; static double d, delta; static double L1_to_L2= m_L2/m_L1; /* converts L1-cycles to L2-cycles */ bool valid; /* function to determine get the observables from BINEX record 02 01 */ /* loop through the SVs */ for (i= n= 0, offset= (unsigned long)obs.observation.constellation.total + 8L; i < obs.observation.constellation.total; i++) if (binex_extract_SV_id(rec[8 + i], &obs.observation.constellation.satellite[n].system)) { /* handling of "possible error" byte: */ switch (n) { case 0x00: extract_uint1(rec, &offset, &perr); mperr= perr; break; default: switch (mperr & 0x01) { case 0x00: perr= mperr; break; case 0x01: extract_uint1(rec, &offset, &perr); break; } } /* receiver channel ID, A/S, LLI: */ extract_uint1(rec, &offset, &chn_as_lli); obs.observation.constellation.satellite[n].rx_channel= (chn_as_lli & 0x1f) + 0x01; /* extract the observables: */ d= binex_extract_mGFZI(rec, &offset, &valid)/1000.; if ((index= obs.observation.observable.index[C1]) != 0xff) { obs.observation.constellation.satellite[n].data[index].u.pseudorange= d; obs.observation.constellation.satellite[n].data[index].lli= chn_as_lli >> 3 & BIT_2; obs.observation.constellation.satellite[n].data[index].err= perr >> 3 & BIT_0; } delta= binex_extract_mGFZI(rec, &offset, &valid)/1000.; if ((index= obs.observation.observable.index[P1]) != 0xff) { switch (valid) { case TRUE: obs.observation.constellation.satellite[n].data[index].u.pseudorange= d - delta; obs.observation.constellation.satellite[n].data[index].lli= chn_as_lli >> 3 & BIT_2; break; case FALSE: obs.observation.constellation.satellite[n].data[index].u.pseudorange= D_NO_DATA; } obs.observation.constellation.satellite[n].data[index].err= perr >> 5 & BIT_0; } delta= binex_extract_mGFZI(rec, &offset, &valid)/1000.; if ((index= obs.observation.observable.index[P2]) != 0xff) { switch (valid) { case TRUE: obs.observation.constellation.satellite[n].data[index].u.pseudorange= d - delta; obs.observation.constellation.satellite[n].data[index].lli= chn_as_lli >> 3 & BIT_2; break; case FALSE: obs.observation.constellation.satellite[n].data[index].u.pseudorange= D_NO_DATA; } obs.observation.constellation.satellite[n].data[index].err= perr >> 7 & BIT_0; } extract_uint1(rec, &offset, &snr_l1); if ((index= obs.observation.observable.index[S1]) != 0xff) obs.observation.constellation.satellite[n].data[index].u.snr= (double)snr_l1; extract_uint1(rec, &offset, &snr_l2); if ((index= obs.observation.observable.index[S2]) != 0xff) obs.observation.constellation.satellite[n].data[index].u.snr= (double)snr_l2; /* currently storing: L1(P1), L1(P1) - L1(CA), L1(P1) - L2(P2) */ d= binex_extract_mGFZI(rec, &offset, &valid)/10000.; delta= binex_extract_mGFZI(rec, &offset, &valid)/10000.; if ((index= obs.observation.observable.index[LA]) != 0xff) { switch (valid) { case TRUE: obs.observation.constellation.satellite[n].data[index].u.phase= d - delta; break; case FALSE: obs.observation.constellation.satellite[n].data[index].u.phase= D_NO_DATA; } obs.observation.constellation.satellite[n].data[index].lli= chn_as_lli >> 3 & BIT_2; obs.observation.constellation.satellite[n].data[index].lli|= chn_as_lli >> 6 & BIT_0; obs.observation.constellation.satellite[n].data[index].sn= bernese_snr(ashtech_snr[0], (double)snr_l1); obs.observation.constellation.satellite[n].data[index].err= perr >> 2 & BIT_0; } if ((index= obs.observation.observable.index[L1]) != 0xff) { switch (teq.trans.opt_X & USE_CA_L1) { case USE_CA_L1: /* store L1(CA) as RINEX L1 */ switch (valid) { case TRUE: obs.observation.constellation.satellite[n].data[index].u.phase= d - delta; break; case FALSE: obs.observation.constellation.satellite[n].data[index].u.phase= D_NO_DATA; } obs.observation.constellation.satellite[n].data[index].err= perr >> 2 & BIT_0; break; default: /* store L1(P1) as RINEX L1 */ obs.observation.constellation.satellite[n].data[index].u.phase= d; obs.observation.constellation.satellite[n].data[index].err= perr >> 4 & BIT_0; } obs.observation.constellation.satellite[n].data[index].lli= chn_as_lli >> 3 & BIT_2; obs.observation.constellation.satellite[n].data[index].lli|= chn_as_lli >> 6 & BIT_0; obs.observation.constellation.satellite[n].data[index].sn= bernese_snr(ashtech_snr[0], (double)snr_l1); } delta= binex_extract_mGFZI(rec, &offset, &valid)/10000.; if ((index= obs.observation.observable.index[L2]) != 0xff) { switch (valid) { case TRUE: obs.observation.constellation.satellite[n].data[index].u.phase= (d - delta)*L1_to_L2; obs.observation.constellation.satellite[n].data[index].lli= chn_as_lli >> 3 & BIT_2; obs.observation.constellation.satellite[n].data[index].lli|= chn_as_lli >> 7 & BIT_0; obs.observation.constellation.satellite[n].data[index].sn= bernese_snr(ashtech_snr[1], (double)snr_l2); break; case FALSE: obs.observation.constellation.satellite[n].data[index].u.phase= D_NO_DATA; } obs.observation.constellation.satellite[n].data[index].err= perr >> 6 & BIT_0; } n++; } } /********************************************************************/ void binex_observables_7f_00 #if KR_C (message, offset) unsigned char *message; unsigned long *offset; #else (unsigned char *message, unsigned long *offset) #endif { unsigned char n, chn_as_lli, CA_index, P1_index, P2_index, LA_index, L1_index, L2_index, S1_index, S2_index, snr, perr, mperr; double delta, d, error; static double L2_to_L1= m_L1/m_L2; /* converts L2-cycles to L1-cycles */ bool valid; unsigned long perr_offset; /* index values for the observables (for code readability only) */ CA_index= obs.observation.observable.index[C1]; P1_index= obs.observation.observable.index[P1]; P2_index= obs.observation.observable.index[P2]; LA_index= obs.observation.observable.index[LA]; L1_index= obs.observation.observable.index[L1]; L2_index= obs.observation.observable.index[L2]; S1_index= obs.observation.observable.index[S1]; S2_index= obs.observation.observable.index[S2]; /* initial byte for SV total: */ append_uint1(message, offset, obs.observation.constellation.total - 0x01); /* the constellation: */ for (n= 0, mperr= 0x00; n < obs.observation.constellation.total; n++) { append_uint1(message, offset, binex_build_SV_id(&obs.observation.constellation.satellite[n].system)); switch (mperr & 0x01) { case 0x00: perr= mperr & 0x03; switch (LA_index) { case 0xff: break; default: perr|= obs.observation.constellation.satellite[n].data[LA_index].err << 2; } switch (CA_index) { case 0xff: break; default: perr|= obs.observation.constellation.satellite[n].data[CA_index].err << 3; } switch (L1_index) { case 0xff: break; default: perr|= obs.observation.constellation.satellite[n].data[L1_index].err << 4; } switch (P1_index) { case 0xff: break; default: perr|= obs.observation.constellation.satellite[n].data[P1_index].err << 5; } switch (L2_index) { case 0xff: break; default: perr|= obs.observation.constellation.satellite[n].data[L2_index].err << 6; } switch (P2_index) { case 0xff: break; default: perr|= obs.observation.constellation.satellite[n].data[P2_index].err << 7; } switch (n) { case 0x00: mperr= perr; break; default: if (mperr != perr) mperr|= 0x01; } break; } } /* the data for each SV: */ for (n= 0; n < obs.observation.constellation.total; n++) { switch (mperr & 0x01) { case 0x00: /* all "possible error" bytes for all SVs are the same; store the master */ switch (n) { case 0x00: append_uint1(message, offset, mperr); break; } break; case 0x01: /* all "possible error" bytes for all SVs are different; save the position and advance the message offset by one */ perr_offset= *offset; (*offset)++; break; } /* receiver channel ID, A/S, LLI: */ chn_as_lli= (obs.observation.constellation.satellite[n].rx_channel - 0x01) & 0x1f; if (LA_index != 0xff) { /* A/S in bit 5; L1 loss-of-lock in bit 6 */ chn_as_lli|= obs.observation.constellation.satellite[n].data[LA_index].lli << 3 & BIT_5; chn_as_lli|= obs.observation.constellation.satellite[n].data[LA_index].lli << 6 & BIT_6; } if (L1_index != 0xff) { /* A/S in bit 5; L1 loss-of-lock in bit 6 */ chn_as_lli|= obs.observation.constellation.satellite[n].data[L1_index].lli << 3 & BIT_5; chn_as_lli|= obs.observation.constellation.satellite[n].data[L1_index].lli << 6 & BIT_6; } if (L2_index != 0xff) { /* A/S in bit 5; L2 loss-of-lock in bit 7 */ chn_as_lli|= obs.observation.constellation.satellite[n].data[L2_index].lli << 3 & BIT_5; chn_as_lli|= obs.observation.constellation.satellite[n].data[L2_index].lli << 7 & BIT_7; } append_uint1(message, offset, chn_as_lli); switch (CA_index) { case 0xff: d= D_NO_DATA; perr= 0x00; break; default: d= round(obs.observation.constellation.satellite[n].data[CA_index].u.pseudorange, 1e-3); perr= obs.observation.constellation.satellite[n].data[CA_index].err << 3; break; } binex_append_mGFZI(message, offset, d*1000.); switch (P1_index) { case 0xff: delta= MAXFLOAT; break; default: if (obs.observation.constellation.satellite[n].data[P1_index].u.pseudorange != D_NO_DATA) delta= 1000.*(d - round(obs.observation.constellation.satellite[n].data[P1_index].u.pseudorange, 1e-3)); else delta= MAXFLOAT; perr|= obs.observation.constellation.satellite[n].data[P1_index].err << 5; } binex_append_mGFZI(message, offset, delta); switch (P2_index) { case 0xff: delta= MAXFLOAT; break; default: if (obs.observation.constellation.satellite[n].data[P2_index].u.pseudorange != D_NO_DATA) delta= 1000.*(d - round(obs.observation.constellation.satellite[n].data[P2_index].u.pseudorange, 1e-3)); else delta= MAXFLOAT; perr|= obs.observation.constellation.satellite[n].data[P2_index].err << 7; } binex_append_mGFZI(message, offset, delta); switch (S1_index) { case 0xff: snr= 0x00; break; default: snr= (unsigned char)obs.observation.constellation.satellite[n].data[S1_index].u.snr; } append_uint1(message, offset, snr); switch (S2_index) { case 0xff: snr= 0x00; break; default: snr= (unsigned char)obs.observation.constellation.satellite[n].data[S2_index].u.snr; } append_uint1(message, offset, snr); /* currently storing: L1(P1), L1(P1) - L1(CA), L1(P1) - L2(P2) */ switch (L1_index) { case 0xff: d= D_NO_DATA; break; default: d= round(obs.observation.constellation.satellite[n].data[L1_index].u.phase, 1e-4); perr|= obs.observation.constellation.satellite[n].data[L1_index].err << 4; break; } binex_append_mGFZI(message, offset, d*10000.); switch (LA_index) { case 0xff: delta= MAXFLOAT; break; default: if (obs.observation.constellation.satellite[n].data[LA_index].u.phase != D_NO_DATA) delta= 10000.*(d - round(obs.observation.constellation.satellite[n].data[LA_index].u.phase, 1e-4)); else delta= MAXFLOAT; perr|= obs.observation.constellation.satellite[n].data[LA_index].err << 2; } binex_append_mGFZI(message, offset, delta); switch (L2_index) { case 0xff: delta= MAXFLOAT; break; default: if (obs.observation.constellation.satellite[n].data[L2_index].u.phase != D_NO_DATA) delta= 10000.*((d - round(obs.observation.constellation.satellite[n].data[L2_index].u.phase, 1e-4)*L2_to_L1)); else delta= MAXFLOAT; perr|= obs.observation.constellation.satellite[n].data[L2_index].err << 6; } binex_append_mGFZI(message, offset, delta); /* "possible error" byte */ switch (mperr & 0x01) { case 0x00: /* all "possible error" bytes for all SVs are the same; first already saved */ break; case 0x01: /* store each "possible error" byte for each SV, flagging that they differ */ append_uint1(message, &perr_offset, perr | 0x01); break; } } } /********************************************************************/ void binex_nav_message_01_01 #if KR_C (message, offset) unsigned char *message; unsigned long *offset; #else (unsigned char *message, unsigned long *offset) #endif { append_uint1(message, offset, binex_build_SV_id(&nav.satellite.system)); switch (nav.satellite.system.sys) { case NAVSTAR_GPS: append_uint2(message, offset, (unsigned short)nav.satellite.ephemeris.type.GPS.gps_week); append_sint4(message, offset, (long)nav.satellite.ephemeris.type.GPS.ToW); /* ToC assumed equal to ToE: */ append_sint4(message, offset, (long)nav.satellite.ephemeris.type.GPS.ToE); append_real4(message, offset, (float)nav.satellite.ephemeris.type.GPS.TGD); append_sint4(message, offset, (long)nav.satellite.ephemeris.type.GPS.IODC); append_real4(message, offset, (float)nav.satellite.ephemeris.type.GPS.af2); append_real4(message, offset, (float)nav.satellite.ephemeris.type.GPS.af1); append_real4(message, offset, (float)nav.satellite.ephemeris.type.GPS.af0); append_sint4(message, offset, (long)nav.satellite.ephemeris.type.GPS.IODE); append_real4(message, offset, (float)(nav.satellite.ephemeris.type.GPS.dn/GPS_PI)); append_real8(message, offset, (double)nav.satellite.ephemeris.type.GPS.M); append_real8(message, offset, (double)nav.satellite.ephemeris.type.GPS.e); append_real8(message, offset, (double)nav.satellite.ephemeris.type.GPS.sqrt_a); append_real4(message, offset, (float)nav.satellite.ephemeris.type.GPS.Cic); append_real4(message, offset, (float)nav.satellite.ephemeris.type.GPS.Crc); append_real4(message, offset, (float)nav.satellite.ephemeris.type.GPS.Cis); append_real4(message, offset, (float)nav.satellite.ephemeris.type.GPS.Crs); append_real4(message, offset, (float)nav.satellite.ephemeris.type.GPS.Cuc); append_real4(message, offset, (float)nav.satellite.ephemeris.type.GPS.Cus); append_real8(message, offset, (double)nav.satellite.ephemeris.type.GPS.OMEGA); append_real8(message, offset, (double)nav.satellite.ephemeris.type.GPS.omega); append_real8(message, offset, (double)nav.satellite.ephemeris.type.GPS.i); append_real4(message, offset, (float)(nav.satellite.ephemeris.type.GPS.OMEGA_dot/GPS_PI)); append_real4(message, offset, (float)(nav.satellite.ephemeris.type.GPS.i_dot/GPS_PI)); append_real4(message, offset, (float)(nav.satellite.ephemeris.type.GPS.URA*10.)); append_uint2(message, offset, (unsigned short)nav.satellite.ephemeris.type.GPS.health); append_uint2(message, offset, (unsigned short)nav.satellite.ephemeris.type.GPS.fit_interval); break; case GLONASS: fprintf(stderr, "binex_nav_message_01_01(): GLONASS navigation message code not complete\n"); exit(-1); } } /********************************************************************/