Data Help with Data GPS/GNSS Data Data Formats BINEX Record structure Synchronization Record ID bytes Record message length Record message Record checksum/CRC Reverse record length Time stamps Proposed records Current records Forward parsing Conventions Record ID 0x00 Record ID 0x01 Record ID 0x05 Record ID 0x7d Record ID 0x7e Record ID 0x7f Log

BINEX Software


Binary Exchange format for GPS/GNSS
Data/Metadata/Ephemerides/Orbits/Solutions


Index:
BINEX homepage
General considerations
BINEX forward record parsing function
General utility functions
Checksum/CRC functions
Interpretation of record ID 0x01 = 1
Interpretation of record ID 0x7f = 127

Contact: GAGE data guru



General Considerations
The software available through links on this page is taken from the BINEX section of the teqc source code, with little or minimal modification. The teqc source code is written so that it can be compiled either with a Kernighan/Ritchie C compiler (compile with "-DKR_C" option), or with an ANSI C/C++ compiler by default. In general, the teqc code has been compiled on almost 20 different compiler/OS combinations, with both little-endian and big-endian processors. The code available here is the first teqc code that is being made publically available, in order to help jump start BINEX usage.

There are some general considerations. First, you must make sure of the sizes of the following standard C/C++ data types for your particular compiler and platform:

  • unsigned char (uint1) = 1 byte
  • signed char (sint1) = 1 byte
  • unsigned short (uint2) = 2 bytes
  • signed short (sint2) = 2 bytes
  • unsigned long (uint4) = 4 bytes
  • signed long (sint4) = 4 bytes
  • float (real4) = 4 bytes
  • double (real8) = 8 bytes
Non-standard C/C++ data types (long long, long double, and so on) are not used directly.

Currently, none of the supplied code can be compiled as is into a standalone executable. Instead, the supplied C functions are meant as a template (not in the C++ sense!) for your own development effort. You are free to make use of the supplied software as you see fit. But like software from the Free Software Foundation, Inc.:

    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.
Errors or significant code enhancements should be submitted to the GAGE BINEX contact. Please make sure that any submitted code changes are consistent with both Kernighan/Ritchie C and ANSI C/C++ styles.

Now, go for it!


Forward BINEX Record Parsing Function:
In binex.c, prototyped in binex.h, is the function next_BINEX_record(), which will parse a BINEX stream pointed to by file->fp, reading it in the forward direction only. It is designed to work with reading files and stdin, depending of the value of file->fp. Before this function is called the first time, it is assumed that the user has determined the endian-ness of the processor being used, and has set teq.tr.little_endian to the appropriate value. At the end of the function, a switch is used to call the correct interpretation function depending on the record ID of the BINEX record.

Basically, this function is an implimentation of the forward record parsing algorithm. The function is designed to be called repeatedly until the end-of-file marker is encountered, and NORMAL_BINEX_EOF is returned. The only BINEX-related functions that are called are:

    read_ubnxi(): for obtaining the next ubnxi from the stream

    binex_crc(): for computing the BINEX checksum/CRC for this record

    decompose_binex_*(): for interpreting the BINEX record once it has been successfully read into memory pointed to by rec




General Utility Functions:
The files general.c and general.h currently contains the C/C++ functions and prototyping needed for reading BINEX:
    read_ubnxi(): reads a stream to extract the 1-4 byte ubnxi

    ubnxi_to_uint4(): converts the raw 1-4 bytes of a ubnxi into a 4-byte uint4

    binex_extract_mGFZI(): converts the raw 1-8 bytes of a mGFZI into an 8-byte real8

    binex_extract_mGFZi(): converts the raw 1, 2, 4, or 8 bytes of a mGFZi into an 8-byte real8

    extract_uint1(): reads a 1-byte uint1 from the byte to an unsigned char pointer location

    extract_uint2(): reads a 2-byte uint2 starting at the byte at an unsigned char pointer location

    extract_sint2(): reads a 2-byte sint2 starting at the byte at an unsigned char pointer location

    extract_uint3(): reads a 3-byte unsigned integer starting at the byte at an unsigned char pointer location and converts this to a 4-byte uint4

    extract_uint4(): reads a 4-byte uint4 starting at the byte at an unsigned char pointer location

    extract_sint4(): reads a 4-byte sint4 starting at the byte at an unsigned char pointer location

    extract_real4(): reads a 4-byte real4 starting at the byte at an unsigned char pointer location

    extract_real8(): reads an 8-byte real8 starting at the byte at an unsigned char pointer location

    binex_extract_SV_id(): reads a 1-byte SVid1 from the byte at an unsigned char pointer location and decodes the satellite system and satellite number

for writing BINEX:
    binex_f_stx(): writes out the leading synchronization/endian byte for a forward-readable BINEX record; also sets the endian-ness of the record to be the same as the processor on which this is running

    binex_append_time(): writes a 4-12 byte time stamp at a unsigned char pointer depending on the desired resolution for a specific record, based on the time stamp proposal for BINEX

    uint4_to_ubnxi(): converts a 4-byte uint4 into a 1-4 byte ubnxi

    binex_append_mGFZI(): converts an 8-byte real8 into a 1-, 2-, 3-, 4-, 5-, 6-, 7- or 8-byte mGFZI

    binex_append_mGFZi(): converts an 8-byte real8 into a 1-, 2-, 4-, or 8-byte mGFZi

    append_uint1(): writes a 1-byte uint1 to an unsigned char pointer location

    append_uint2(): writes a 2-byte uint2 starting at an unsigned char pointer location

    append_sint2(): writes a 2-byte sint2 starting at an unsigned char pointer location

    append_uint3(): writes a 3-byte unsigned integer starting at an unsigned char pointer location

    append_uint4(): writes a 4-byte uint4 starting at an unsigned char pointer location

    append_sint4(): writes a 4-byte sint4 starting at an unsigned char pointer location

    append_real4(): writes a 4-byte real4 starting at an unsigned char pointer location

    append_real8(): writes a 8-byte real8 starting at an unsigned char pointer location

    binex_build_SV_id(): returns a 1-byte SVid1 when supplied a satellite system and satellite number

and for both:
    reverse_bytes(): byte swaps for converting a little-endian data type into a big-endian data type, or converting a big-endian data type into a little-endian data type

    swap_uc(): byte swaps two unsigned chars

    binex_crc(): obtains the BINEX checksum/CRC value for the record specified




Checksum/CRC Functions:
The files crc.c and crc.h currently contain the C/C++ functions and prototyping of
    cks08(): 8-bit byte-wise XOR sum

    crc16(): 16-bit CRC

    crc32(): 32-bit CRC

sufficient for creating or verifying the checksum/CRC of any BINEX record of less than 2^20 = 1048576 bytes (which will probably be all BINEX records for the foreseeable future). Yet to be finalized is md5(), for record lengths of 2^20 or greater bytes.

The CRCs (cyclic redundancy checks) are computed using static lookup tables, to minimize computation time. Each function accepts one or two pointers to unsigned char, buff and mess, which point to the bytes for which the checksum or CRC is to be computed. The unsigned long values buff_length and mess_length indicate the number of bytes to sum at each pointer, respectively. If both pointers are not NULL, buff must occur first, immediately followed by mess. The reason for this two-part pointer method is the construction of any BINEX record: The initial record ID bytes are followed by the record length bytes, but the record length is usually not known until the entire record message has been constructed. It is useful, therefore, when creating a BINEX record, to store the record ID and record length bytes in buff, and create the record message in mess.


Interpretation of Record ID 0x01 = 1:
Though not complete (since they access other teqc-specific functions), the following C/C++ functions and prototyping are provided in binex.c and binex.h as help in learning how to interpret (decompose) BINEX record ID 0x01:
    decompose_binex_01(): for record 0x01, determines the subrecord value (currently only subrecord 0x01 is valid), and calls binex_extract_SV_id(), binary_NAV(), and binary_ephemeris(), the latter two of which are teqc functions: binary_NAV() sets initial RINEX NAV file header information, binary_ephemeris() essentially just calls binex_01_01_ephemeris() if subrecord 0x01 and does other teqc specific tasks

    binex_01_01_ephemeris(): decomposition of BINEX record 0x01-01 for GPS satellites (GLONASS will be another case statement defined later); if teq.edit.opt_X & BINEX_OUT is non-zero, BINEX values will be generated and if zero, RINEX values will be generated (only relevant for the SV health and SV fit interval components of the GPS navigation message)




Interpretation of Record ID 0x7f = 127:
Though not complete (since they access other teqc-specific functions), the following C/C++ functions and prototyping are provided in binex.c and binex.h as help in learning how to interpret (decompose) BINEX record ID 0x7f:
    decompose_binex_7f(): for record 0x7f, determines the subrecord value (currently only subrecord 0x00 is valid), and calls teqc functions which establish the observation epoch time based on the GPS week and seconds into the week, and for subrecord 0x00 then establishes the current observable part of the constellation (indirectly calls binex_7f_00_constellation()) and obtains the observables (indirectly call binex_7f_00_obs()).

    binex_7f_00_constellation(): determines the observable part of the constellation (SVs being tracked) in current 0x7f-00

    binex_7f_00_obs(): decomposition of the observables:
    • C1 = C/A pseudorange; nearest 0.001 meter
    • P1 = P1 pseudorange; nearest 0.001 meter
    • P2 = P2 pseudorange; nearest 0.001 meter
    • S1 = raw SNR value for L1 (one byte is currently assumed)
    • S2 = raw SNR value for L2 (one byte is currently assumed)
    • L1 = L1(P1) phase; nearest 0.0001 L1-cycle
    • LA = L1(CA) phase; nearest 0.0001 L1-cycle
    • L2 = L2(P2) phase; nearest 0.0001 L2-cycle
    Also, extraction of the "possible error" byte for C1, P1, P2, LA, L1, L2; receiver channel number; A/S status; and loss-of-lock for L1 and L2. (Full-wavelength tracking of LA, L1, and L2 is assumed. index == 0xff is a teqc-ism that means that that specific observable was not requested.)

 

Last modified: 2023-05-12  13:20:32  America/Denver