//not available on ThunderBolt-E
        /// <summary>
        /// This broadcast packet provides individual satellite solutions as well as the combined
        /// timing solutions. Two formats of this packet are supported: a floating-point form and an
        /// integer form. This packet is broadcast once per second if enabled with the 0x8E-A5 packet
        /// mask command. Packet 0x8E-A5 allows the user to select which format will be broadcast.
        /// 
        /// notes:
        /// If both formats are selected the ThunderBolt will send format 0 (floating point) only.
        /// 
        /// For clock bias numbers, a positive sign indicates that the ThunderBolt PPS occurs after the
        /// GPS PPS. 
        /// 
        /// For clock bias rate numbers, a positive sign indicates that the ThunderBolt
        /// 10MHz frequency output is running slow relative to GPS.
        /// 
        /// 8 sets of satellite ID and data are sent with n=1, 2, . . . 8
        /// </summary>
        private void sat_solutions(TsipPacket tp)
        {
            Debug.Print(":0x8F.A7 (Satellite Solutions)");

            byte format = tp.GetNextByte();
            UInt32 time_of_week = tp.GetNextDWord();

            Single clock_bias;
            Single clock_bias_rate;

            if (format == 0)
            {   // floating point
                clock_bias = tp.GetNextSingle();
                clock_bias_rate = tp.GetNextSingle();
            }
            else if (format == 1)
            {   // integer values
                clock_bias = (float)(int)tp.GetNextWord();
                clock_bias *= 100.0e-12F;
                clock_bias_rate = (float)(int)tp.GetNextWord();
                clock_bias_rate *= 1.0e-12F;
            }
            else
            {
                unknown_msg(tp);
                return;
            }

            for (int i = 0; i < 32; i++)    // reset current bias flags
                Satellites[i].HasBiasInfo = false;

            for (int i = 0; i < 8; i++)     // get bias info from all visible satellites
            {
                byte prn = tp.GetNextByte();
                prn--;
                if (prn > 31)               // ignore bogus data
                    continue;

                if (format == 0)
                    Satellites[prn].SatBias = tp.GetNextSingle();
                else
                {
                    Satellites[prn].SatBias = (float)(int)tp.GetNextWord();
                    Satellites[prn].SatBias *= 100.0e-12F;
                }

                Satellites[prn].TimeOfFix = (float)time_of_week;
                Satellites[prn].HasBiasInfo = true;
            }
        }
        private void m_port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            _activityLed.Write(true);  // turn on the LED
            while (m_port.BytesToRead > 0)
            {

                current_packet.AddByte((ushort)m_port.ReadByte());
                if (current_packet.IsComplete)                  // received complete packet?
                {
                    loopsSinceDataReceived = 0; // reset the no data being received loop counter

                    lock (((ICollection)PacketQueue).SyncRoot)  // use lock for thread sync
                    {
                        PacketQueue.Enqueue(current_packet);    // queue up the packet for the worker thread
                    }
                    current_packet = new TsipPacket();          // allocate a new packet
                }
            }
            _activityLed.Write(false);  // turn off the LED
        }
        private void packet_58(TsipPacket tp)
        {
            Debug.Print("Packet 58 (GPS system data):");

            byte op = tp.GetNextByte();
            byte type = tp.GetNextByte();
            byte prn = tp.GetNextByte();
            byte len = tp.GetNextByte();
        }
        private void io_options(TsipPacket tp)
        {
            Debug.Print("Packet 55 (I/O options):");

            byte posn = tp.GetNextByte();
            byte vel = tp.GetNextByte();
            byte timing = tp.GetNextByte();
            byte aux = tp.GetNextByte();
            level_type = ((aux & 0x08) == 0x08) ? "dB" : "AMU";
        }
        private void lla_fix(TsipPacket tp)
        {
            Debug.Print("Packet 84 (LLA fix):");

            position.Latitude = tp.GetNextDouble();
            position.Longitude = tp.GetNextDouble();
            position.Altitude = tp.GetNextDouble();

            Double clock_bias = tp.GetNextDouble();
            Single time_of_fix = tp.GetNextSingle();

            raise_position_change();
        }
        private void eph_status(TsipPacket tp)
        {
            Debug.Print("Packet 5B (Sat ephemeris status):");

            byte prn = tp.GetNextByte();
            prn--;
            if (prn > 31)
            {
                unknown_msg(tp);
                return;
            }

            Satellites[prn].CollectionTime = tp.GetNextSingle();
            Satellites[prn].EphemerisHealth = tp.GetNextByte();
            Satellites[prn].IODE = tp.GetNextByte();
            Satellites[prn].Toe = tp.GetNextSingle();
            Satellites[prn].FitIntervalFlag = tp.GetNextByte();
            Satellites[prn].UserRangeAccuracy = tp.GetNextSingle();
        }
 private void get_alm_health(TsipPacket tp)
 {
     Debug.Print(":0x49   (Almanac Health Page Report)");
     for (int i = 0; i < 32; i++)
         Satellites[i].IsHealthy = (tp.GetNextByte() == 0);
 }
 private void unknown_msg(TsipPacket tp)
 {
     Debug.Print("Unknown TSIP msg: " + tp.ToString());
     unparseable_packet_count++;
 }
        private void version_info(TsipPacket tp)
        {
            Debug.Print(":0x45 (Software Version Info Received)");

            byte ap_major = tp.GetNextByte();  // Application firmware
            byte ap_minor = tp.GetNextByte();
            byte ap_month = tp.GetNextByte();
            byte ap_day = tp.GetNextByte();
            UInt16 ap_year = (ushort)(tp.GetNextByte() + 2000); // docs say 1900 based!

            byte core_major = tp.GetNextByte(); // GPS firmware
            byte core_minor = tp.GetNextByte();
            byte core_month = tp.GetNextByte();
            byte core_day = tp.GetNextByte();
            UInt16 core_year = (ushort)(tp.GetNextByte() + 2000); // docs say 1900 based!

            try
            {
                unit_firmware.Major = ap_month;
                unit_firmware.Minor = ap_minor;
                unit_firmware.Date = new DateTime(ap_year, ap_month, ap_day);

                unit_hardware.Major = core_major;
                unit_hardware.Minor = core_minor;
                unit_hardware.Date = new DateTime(core_year, core_month, core_day);

                if (SoftwareVersionInfoReceived != null)
                    SoftwareVersionInfoReceived(this, new VersionInfoEventArgs(unit_firmware));

                if (HardwareVersionInfoReceived != null)
                    HardwareVersionInfoReceived(this, new VersionInfoEventArgs(unit_hardware));
            }
            catch (Exception e)
            {
                Debug.Print("Exception:" + e.Message);
            }
        }
 private void survey_params(TsipPacket tp)
 {
     Debug.Print("Packet 8F.A9 (Survey params):");
     byte survey_flag = tp.GetNextByte();
     unit_survey_save = tp.GetNextByte();
     unit_survey_length = tp.GetNextDWord();
     UInt32 rsvd = tp.GetNextDWord();
 }
        private void timing_msg(TsipPacket tp)
        {
            byte subcode = tp.GetNextByte();

            if (subcode == 0x15)
                datums(tp);
            else if (subcode == 0x41)
                manuf_params(tp);
            else if (subcode == 0x42)
                prodn_params(tp);
            else if (subcode == 0x4A)
                pps_settings(tp);
            else if (subcode == 0xA0)
                dac_values(tp);
            else if (subcode == 0xA1)
                osc_sense(tp);
            else if (subcode == 0xA2)
                pps_timing_mode(tp);
            else if (subcode == 0xA5)
                packet_mask(tp);
            else if (subcode == 0xA7)
                sat_solutions(tp);   // not on ThunderBolt-E
            else if (subcode == 0xA8)
                discipline_params(tp);
            else if (subcode == 0xA9)
                survey_params(tp);
            else if (subcode == 0xAB)
                primary_timing(tp);
            else if (subcode == 0xAC)
                secondary_timing(tp);
            else
                unknown_msg(tp);
        }
        private void single_ecef_fix(TsipPacket tp)
        {
            Debug.Print("Packet 42 (XYZ ECEF):");

            Single x = tp.GetNextSingle();
            Single y = tp.GetNextSingle();
            Single z = tp.GetNextSingle();
            Single time_of_fix = tp.GetNextSingle();
        }
        private void secondary_timing(TsipPacket tp)
        {
            Debug.Print(":0x8F.AC (Secondary Timing)");

            byte spare;
            try
            {
                receiver_mode = (ReceiverMode)tp.GetNextByte();
            }
            catch
            {
                receiver_mode = ReceiverMode.Unknown;
            }
            try
            {
                discipline_mode = (DiscipliningMode)tp.GetNextByte();
            }
            catch
            {
                discipline_mode = DiscipliningMode.Unknown;
            }
            survey_progress = tp.GetNextByte(); // 0-100%

            holdover = tp.GetNextDWord(); // seconds

            critical_alarms = tp.GetNextWord();
            minor_alarms = tp.GetNextWord();
            try
            {
                gps_status = (ReceiverStatus)tp.GetNextByte();
            }
            catch
            {
                gps_status = ReceiverStatus.Unknown;
            }

            try
            {
                discipline = (DiscipliningActivity)tp.GetNextByte();
            }
            catch
            {
                discipline = DiscipliningActivity.Unknown;
            }

            spare = tp.GetNextByte();
            spare = tp.GetNextByte();

            pps_offset = tp.GetNextSingle();  // in nano seconds (ns)

            osc_offset = tp.GetNextSingle();  // in parts per billion (ppb)

            dac_value = tp.GetNextDWord();
            dac_voltage = tp.GetNextSingle(); // in V
            temperature = tp.GetNextSingle(); // in C

            position.Latitude = tp.GetNextDouble();
            position.Longitude = tp.GetNextDouble();
            position.Altitude = tp.GetNextDouble();

            if (SecondaryTimingChanged != null)
                SecondaryTimingChanged(this, null);

            raise_position_change();

            clear_sat_tracking(); //??
        }
        private void sat_tracking(TsipPacket tp)
        {
            Debug.Print(":0x5C    (Satellite Tracking)");

            byte prn = tp.GetNextByte();
            prn--;
            if (prn > 31)
            {
                unknown_msg(tp);
                return;
            }

            Satellites[prn].Slot = Satellites[prn].Channel = tp.GetNextByte();
            Satellites[prn].Slot &= 0x07;
            Satellites[prn].Channel >>= 3;
            Satellites[prn].AcquisitionFlag = tp.GetNextByte();
            Satellites[prn].EphemerisFlag = tp.GetNextByte();
            Satellites[prn].SignalLevel = tp.GetNextSingle();
            Satellites[prn].TimeOfWeek = tp.GetNextSingle();
            Satellites[prn].Elevation = tp.GetNextSingle();
            Satellites[prn].Azimuth = tp.GetNextSingle();
            Satellites[prn].Age = tp.GetNextByte();
            Satellites[prn].MsecStatus = tp.GetNextByte();
            Satellites[prn].BadDataFlag = tp.GetNextByte();
            Satellites[prn].CollectingData = tp.GetNextByte();
        }
        private void eeprom_status(TsipPacket tp)
        {
            Debug.Print("Packet 5F (EEPROM status):");

            byte flag = tp.GetNextByte();
            if (flag == 0x11)
            {
                UInt16 ee_status = tp.GetNextWord();
            }
        }
        private void dac_values(TsipPacket tp)
        {
            Debug.Print("Packet 8F.A0 (DAC values):");

            UInt32 dac_value = tp.GetNextDWord();
            Single dac_voltage = tp.GetNextSingle();
            Byte dac_res = tp.GetNextByte();
            Byte dac_format = tp.GetNextByte();
            Single dac_min = tp.GetNextSingle();
            Single dac_max = tp.GetNextSingle();
        }
        private void enu_velocity_fix(TsipPacket tp)
        {
            Debug.Print("Packet 56 (ENU velocity):");

            Single x_vel = tp.GetNextSingle();
            Single y_vel = tp.GetNextSingle();
            Single z_vel = tp.GetNextSingle();
            Single bias_rate = tp.GetNextSingle();
            Single time_of_fix = tp.GetNextSingle();
        }
 private void datums(TsipPacket tp)
 {
     Debug.Print("Packet 8F.15 (Datums)");
     int index = tp.GetNextWord();
     double dx = tp.GetNextDouble();
     double dy = tp.GetNextDouble();
     double dz = tp.GetNextDouble();
     double a_axis = tp.GetNextDouble();
     double ecc = tp.GetNextDouble();
 }
        private void filter_config(TsipPacket tp)
        {
            Debug.Print("Packet 70 (Filter config):");

            pv_filter = tp.GetNextByte();
            static_filter = tp.GetNextByte();
            altitude_filter = tp.GetNextByte();
            kalman_filter = tp.GetNextByte();
        }
        private void discipline_params(TsipPacket tp)
        {
            Debug.Print("Packet 8F.A8 (Discipline params):");

            byte type = tp.GetNextByte();

            if (type == 0)
            {
                unit_time_constant = tp.GetNextSingle();
                unit_damping_factor = tp.GetNextSingle();
            }
            else if (type == 1)
            {
                unit_osc_gain = tp.GetNextSingle();
                unit_min_volts = tp.GetNextSingle();
                unit_max_volts = tp.GetNextSingle();
            }
            else if (type == 2)
            {
                unit_jam_sync = tp.GetNextSingle();
                unit_max_freq_offset = tp.GetNextSingle();
            }
            else if (type == 3)
            {
                unit_initial_voltage = tp.GetNextSingle();
            }
        }
 private void gps_time_received(TsipPacket tp)
 {
     Debug.Print(":0x41 GPS Time Received");
     Single s_time = tp.GetNextSingle();
     Int16 s_week = (short)tp.GetNextWord();
     Single s_offset = tp.GetNextSingle();
     if (GPSTimeReceived != null)
         GPSTimeReceived(this, new GPSTimeInfoEventArgs(s_time, s_week, s_offset));
 }
 private void ebolt_health1(TsipPacket tp)
 {
     Debug.Print(":0x46 (E Receiver Health 1st Packet):");
     receiver_status = (ReceiverStatus)tp.GetNextByte();
     //byte sv_fix = tsip_byte();
     byte antenna_fault = tp.GetNextByte();
 }
        private void last_fix_info(TsipPacket tp)
        {
            Debug.Print("Packet 57 (last fix info):");

            byte source_of_fix = tp.GetNextByte();
            byte tracking_mode = tp.GetNextByte();
            Single time_of_fix = tp.GetNextSingle();
            UInt16 week_of_fix = tp.GetNextWord();
        }
 private void ebolt_health2(TsipPacket tp)
 {
     Debug.Print(":0x4B (E Receiver Health 2nd Packet):");
     byte id = tp.GetNextByte();
     byte rtc = tp.GetNextByte();
     byte superpackets = tp.GetNextByte();
 }
        private void manuf_params(TsipPacket tp)
        {
            Debug.Print("Packet 8F.41 (Manufacturing Params):");

            UInt16 sn_prefix = tp.GetNextWord();
            UInt32 serial_num = tp.GetNextDWord();
            byte build_year = tp.GetNextByte();
            byte build_month = tp.GetNextByte();
            byte build_day = tp.GetNextByte();
            byte build_hour = tp.GetNextByte();
            Single osc_offset = tp.GetNextSingle();
            UInt16 test_code = tp.GetNextWord();

            unit_build.Date = new DateTime(build_year + 2000, build_month, build_day, build_hour, 0, 0);
            unit_build.SerialNumber = sn_prefix.ToString() + "-" + serial_num.ToString();
        }
        // Thunderbolt E Version Information
        private void ebolt_version(TsipPacket tp)
        {
            byte rev_month;
            byte rev_day;
            UInt16 rev_year;

            byte subcode = tp.GetNextByte();
            if (subcode == 0x81) // firmware version
            {
                Debug.Print(":0x1C.0x81 (Firmware Version)");
                byte reserved8 = tp.GetNextByte();
                byte major = tp.GetNextByte(); // major version number
                byte minor = tp.GetNextByte(); // minor version number
                byte build = tp.GetNextByte(); // build number
                rev_month = tp.GetNextByte();  // build month
                rev_day = tp.GetNextByte();    // build day
                rev_year = tp.GetNextWord();   // build year
                unit_firmware.VersionString = tp.GetNextString(); // product name string
                try
                {
                    unit_firmware.Date = new DateTime(rev_year, rev_month, rev_day, 0, 0, 0);
                }
                catch (Exception e)
                {
                    unit_firmware.Date = new DateTime(0L);   // bad date
                    Debug.Print("Date Conversion Exception: " + e.Message);
                }
                unit_firmware.Code = 0;
                if (FirmwareVersionInfoReceived != null)
                    FirmwareVersionInfoReceived(this, new VersionInfoEventArgs(unit_firmware));
            }
            else if (subcode == 0x83) // hardware version
            {
                Debug.Print(":0x1C.0x83 (Hardware Version)");
                UInt32 serno = tp.GetNextDWord();    // board serial number
                rev_day = tp.GetNextByte();          // board build day
                rev_month = tp.GetNextByte();        // board build month
                rev_year = tp.GetNextWord();         // board build year
                byte rev_hour = tp.GetNextByte();    // board build hour

                unit_hardware.Code = tp.GetNextWord(); // hardware code associated with hardware ID
                unit_hardware.VersionString = tp.GetNextString(); // Hardware ID
                unit_hardware.SerialNumber = "SN:" + serno.ToString();

                try
                {
                    unit_hardware.Date = new DateTime(rev_year, rev_month, rev_day, rev_hour, 0, 0);
                }
                catch (Exception e)
                {
                    unit_hardware.Date = new DateTime(0L);  // bad date
                    Debug.Print("Date Conversion Exception: " + e.Message);
                }
                if (HardwareVersionInfoReceived != null)
                    HardwareVersionInfoReceived(this, new VersionInfoEventArgs(unit_hardware));
            }
            else
                unknown_msg(tp);
        }
 // not avilable on ThunderBolt-E or early ThunderBolts
 private void osc_sense(TsipPacket tp)
 {
     Debug.Print("Packet 8F.A1 (10 MHz sense):");
     unit_osc_polarity = (tp.GetNextByte() != 0);
 }
        private void ecef_fix(TsipPacket tp)
        {
            Debug.Print("Packet 83 (XYZ ECEF):");

            Double x = tp.GetNextDouble();
            Double y = tp.GetNextDouble();
            Double z = tp.GetNextDouble();
            Double clock_bias = tp.GetNextDouble();
            Single time_of_fix = tp.GetNextSingle();
        }
 private void packet_mask(TsipPacket tp)
 {
     Debug.Print("Packet 8F.A5 (Packet mask):");
     UInt16 mask1 = tp.GetNextWord();
     UInt16 mask2 = tp.GetNextWord();
 }
        /// <summary>
        /// This packet provides a list of satellites used for position or time-only fixes by the GPS
        /// receiver. The packet also provides the dilution of precision values PDOP, HDOP, VDOP and TDOP 
        /// of that set and provides the current mode (automatic or manual, 3-D or 2-D, Over-Determined Clock
        /// mode, etc.). This packet has variable length equal to (17 + nsvs) where "nsvs" is the
        /// number of satellites used in the solution. If an SV is rejected for use by the T-RAIM
        /// algorithm then the SV PRN value will be negative.
        /// 
        /// PDOP = positional DOP
        /// HDOP = horizontal DOP
        /// VDOP = vertical DOP
        /// TDOP = temporal DOP
        /// 
        /// Note: The GPS receiver sends this packet in response to packet 0x24 or automatically. 
        /// </summary>
        private void sat_list(TsipPacket tp)
        {
            byte mode, count, dimension;

            dimension = mode = count = tp.GetNextByte();
            dimension &= 0x07;  // fix dimension is in first 3 bits
            mode &= 0x08;       // mode is in bit 3
            mode >>= 3;
            count >>= 4;        // tracked sat count in upper 4 bits

            //Debug.Print(":0x6D    (Satellite List count = {0})", count);

            positional_dop = Helpers.FloatToFixPrecision(tp.GetNextSingle());
            horizontal_dop = Helpers.FloatToFixPrecision(tp.GetNextSingle());
            vertical_dop = Helpers.FloatToFixPrecision(tp.GetNextSingle());
            temporal_dop = Helpers.FloatToFixPrecision(tp.GetNextSingle());
            fix_dimension = Helpers.ByteToFixDimension(dimension);
            fix_mode = Helpers.ByteToFixMode(mode);

            for (int i = 0; i < 32; i++)    // clear current tracking flags
                Satellites[i].UsedInFix = false;

            for (int i = 0; i < count; i++)
            {
                bool used = true;
                byte prn = tp.GetNextByte();
                if ((prn & 0x80) == 0x80)   // satellite is tracked but is not used in fix
                {
                    used = false;
                    prn &= 0x7F;
                }
                prn--;
                if (prn > 31)
                    continue;               // disregard bogus data

                Satellites[prn].Tracked = true;
                Satellites[prn].UsedInFix = used;
            }
        }