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