/* packet-ubx-gps_l1_lnav.c * Dissection of Global Positioning System (GPS) L1 C/A LNAV navigation messages * (as provided by UBX-RXM-SFRBX). * * By Timo Warns * Copyright 2023 Timo Warns * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include "packet-ubx.h" /* * Dissects GPS L1 C/A LNAV navigation messages as encoded by UBX (in * UBX-RXM-SFRBX messages). * * UBX encodes the 30 bit words of GPS subframes as 32 bit words in little-endian. * * The two most significant bits of the 32 bit word can be ignored. * * UBX takes care of the word parity checks. So, parity checks do not have to be * repeated for dissection. UBX inverts the bits of a word if the least * significant parity bit (D30) of the previous word is 1 (i.e. UBX undoes the * bit inverting of GPS removing the need to do so for dissection). */ /* * mapping from L2 channel code ID to description * see IS-GPS-200N, Section 20.3.3.3.1.2 */ static const value_string L2_CHANNEL_CODE[] = { {0x0, "invalid"}, {0x1, "P-code ON"}, {0x2, "C/A-code ON"}, {0x3, "invalid"}, {0, NULL}, }; /* * mapping from URA index to URA * see IS-GPS-200N, Section 20.3.3.3.1.3 */ static const value_string URA_INDEX[] = { { 0, "0.00 < URA <= 2.40"}, { 1, "2.40 < URA <= 3.40"}, { 2, "3.40 < URA <= 4.85"}, { 3, "4.85 < URA <= 6.85"}, { 4, "6.85 < URA <= 9.65"}, { 5, "9.65 < URA <= 13.65"}, { 6, "13.65 < URA <= 24.00"}, { 7, "24.00 < URA <= 48.00"}, { 8, "48.00 < URA <= 96.00"}, { 9, "96.00 < URA <= 192.00"}, {10, "192.00 < URA <= 384.00"}, {11, "384.00 < URA <= 768.00"}, {12, "768.00 < URA <= 1536.00"}, {13, "1536.00 < URA <= 3072.00"}, {14, "3072.00 < URA <= 6144.00"}, {15, "6144.00 < URA"}, {0, NULL}, }; /* * mapping for SV health summary * see IS-GPS-200N, Section 20.3.3.3.1.4 */ static const value_string SV_HEALTH_SUMMARY[] = { {0, "all LNAV data are OK"}, {1, "some or all LNAV data are bad"}, {0, NULL}, }; /* * mapping for codes for health of SV signal components * see IS-GPS-200N, Section 20.3.3.5.1.3 */ static const value_string SV_HEALTH_CODE[] = { {0, "All Signals OK"}, {1, "All Signals Weak"}, {2, "All Signals Dead"}, {3, "All Signals Have No Data Modulation"}, {4, "L1 P Signal Weak"}, {5, "L1 P Signal Dead"}, {6, "L1 P Signal Has No Data Modulation"}, {7, "L2 P Signal Weak"}, {8, "L2 P Signal Dead"}, {9, "L2 P Signal Has No Data Modulation"}, {10, "L1C Signal Weak"}, {11, "L1C Signal Dead"}, {12, "L1C Signal Has No Data Modulation"}, {13, "L2C Signal Weak"}, {14, "L2C Signal Dead"}, {15, "L2C Signal Has No Data Modulation"}, {16, "L1 & L2 P Signal Weak"}, {17, "L1 & L2 P Signal Dead"}, {18, "L1 & L2 P Signal Has No Data Modulation"}, {19, "L1 & L2C Signal Weak"}, {20, "L1 & L2C Signal Dead"}, {21, "L1 & L2C Signal Has No Data Modulation"}, {22, "L1 Signal Weak"}, {23, "L1 Signal Dead"}, {24, "L1 Signal Has No Data Modulation"}, {25, "L2 Signal Weak"}, {26, "L2 Signal Dead"}, {27, "L2 Signal Has No Data Modulation"}, {28, "SV Is Temporarily Out (Do not use this SV during current pass)"}, {29, "SV Will Be Temporarily Out (Use with caution)"}, {30, "One Or More Signals Are Deformed, However The Relevant URA Parameters Are Valid"}, {31, "More Than One Combination Would Be Required To Describe Anomalies"}, {0, NULL}, }; // Initialize the protocol and registered fields static int proto_ubx_gps_l1 = -1; // Telemetry Word (see IS-GPS-200N, Section 20.3.3.1) static int hf_ubx_gps_l1_tlm_preamble = -1; static int hf_ubx_gps_l1_tlm_message = -1; static int hf_ubx_gps_l1_tlm_integrity = -1; static int hf_ubx_gps_l1_tlm_reserved = -1; static int hf_ubx_gps_l1_tlm_parity = -1; // Handover Word (see IS-GPS-200N, Section 20.3.3.2) static int hf_ubx_gps_l1_how_tow_count = -1; static int hf_ubx_gps_l1_how_alert = -1; static int hf_ubx_gps_l1_how_anti_spoof = -1; static int hf_ubx_gps_l1_how_subframe_id = -1; static int hf_ubx_gps_l1_how_parity_sol = -1; static int hf_ubx_gps_l1_how_parity = -1; // Subframe 1 (see IS-GPS-200N, Section 20.3.3.3) static int hf_ubx_gps_l1_sf1 = -1; static int hf_ubx_gps_l1_sf1_week_no = -1; static int hf_ubx_gps_l1_sf1_l2_channel_code = -1; static int hf_ubx_gps_l1_sf1_ura_index = -1; static int hf_ubx_gps_l1_sf1_sv_health_summary = -1; static int hf_ubx_gps_l1_sf1_sv_health = -1; static int hf_ubx_gps_l1_sf1_iodc_msbs = -1; static int hf_ubx_gps_l1_sf1_w3_parity = -1; static int hf_ubx_gps_l1_sf1_w4_l2_p_data_flag = -1; static int hf_ubx_gps_l1_sf1_w4_reserved = -1; static int hf_ubx_gps_l1_sf1_w4_parity = -1; static int hf_ubx_gps_l1_sf1_w5_reserved = -1; static int hf_ubx_gps_l1_sf1_w5_parity = -1; static int hf_ubx_gps_l1_sf1_w6_reserved = -1; static int hf_ubx_gps_l1_sf1_w6_parity = -1; static int hf_ubx_gps_l1_sf1_w7_reserved = -1; static int hf_ubx_gps_l1_sf1_w7_tgd = -1; static int hf_ubx_gps_l1_sf1_w7_parity = -1; static int hf_ubx_gps_l1_sf1_w8_iodc_lsbs = -1; static int hf_ubx_gps_l1_sf1_w8_toc = -1; static int hf_ubx_gps_l1_sf1_w8_parity = -1; static int hf_ubx_gps_l1_sf1_w9_af2 = -1; static int hf_ubx_gps_l1_sf1_w9_af1 = -1; static int hf_ubx_gps_l1_sf1_w9_parity = -1; static int hf_ubx_gps_l1_sf1_w10_af0 = -1; static int hf_ubx_gps_l1_sf1_w10_parity = -1; static dissector_table_t ubx_gps_l1_sf_dissector_table; static expert_field ei_ubx_gps_l1_tlm_preamble = EI_INIT; static expert_field ei_ubx_gps_l1_how_tow_count = EI_INIT; static expert_field ei_ubx_gps_l1_how_subframe_id = EI_INIT; static int ett_ubx_gps_l1 = -1; static int ett_ubx_gps_l1_tlm = -1; static int ett_ubx_gps_l1_how = -1; static int ett_ubx_gps_l1_sf1_w3 = -1; static int ett_ubx_gps_l1_sf1_w4 = -1; static int ett_ubx_gps_l1_sf1_w5 = -1; static int ett_ubx_gps_l1_sf1_w6 = -1; static int ett_ubx_gps_l1_sf1_w7 = -1; static int ett_ubx_gps_l1_sf1_w8 = -1; static int ett_ubx_gps_l1_sf1_w9 = -1; static int ett_ubx_gps_l1_sf1_w10 = -1; /* Format TOW count */ static void fmt_tow_count(gchar *label, gint32 c) { guint tow = c << 2; snprintf(label, ITEM_LABEL_LENGTH, "%d (TOW: %.1fs)", c, tow * 1.5); } /* Format Clock Data Reference Time t_OC */ static void fmt_t_oc(gchar *label, gint32 i) { guint t_oc = i << 4; snprintf(label, ITEM_LABEL_LENGTH, "%ds", t_oc); } /* Dissect GPS L1 C/A LNAV navigation message */ static int dissect_ubx_gps_l1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { guint32 subframe_id = (tvb_get_guint32(tvb, 4, ENC_LITTLE_ENDIAN) & 0x00000700) >> 8; col_set_str(pinfo->cinfo, COL_PROTOCOL, "GPS L1 LNAV"); col_clear(pinfo->cinfo, COL_INFO); col_append_fstr(pinfo->cinfo, COL_INFO, "Subframe %i", subframe_id); proto_tree *gps_l1_tree = proto_tree_add_subtree_format(tree, tvb, 0, 40, ett_ubx_gps_l1, NULL, "GPS L1 LNAV (Subframe %i)", subframe_id); // send the subframe to the next dissector if (!dissector_try_uint(ubx_gps_l1_sf_dissector_table, subframe_id, tvb, pinfo, gps_l1_tree)) { call_data_dissector(tvb, pinfo, tree); } return tvb_captured_length(tvb); } // Dissect the telemetry (TLM) word static void dissect_ubx_gps_l1_tlm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) { proto_tree *tlm_tree = proto_tree_add_subtree_format(tree, tvb, 0, 4, ett_ubx_gps_l1_tlm, NULL, "Word 1: Telemetry"); guint32 tlm_preamble; proto_item* pi_tlm_preamble = proto_tree_add_item_ret_uint(tlm_tree, hf_ubx_gps_l1_tlm_preamble, tvb, 0, 4, ENC_LITTLE_ENDIAN, &tlm_preamble); if (tlm_preamble != 0x8b) { expert_add_info_format(pinfo, pi_tlm_preamble, &ei_ubx_gps_l1_tlm_preamble, "Invalid preamble"); } proto_tree_add_item(tlm_tree, hf_ubx_gps_l1_tlm_message, tvb, 0, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(tlm_tree, hf_ubx_gps_l1_tlm_integrity, tvb, 0, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(tlm_tree, hf_ubx_gps_l1_tlm_reserved, tvb, 0, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(tlm_tree, hf_ubx_gps_l1_tlm_parity, tvb, 0, 4, ENC_LITTLE_ENDIAN); } // Dissect the handover word (HOW) static void dissect_ubx_gps_l1_how(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) { guint32 subframe_id; proto_tree *how_tree = proto_tree_add_subtree_format(tree, tvb, 4, 4, ett_ubx_gps_l1_how, NULL, "Word 2: Handover"); guint32 tow_count; proto_item* pi_how_tow_count = proto_tree_add_item_ret_uint(how_tree, hf_ubx_gps_l1_how_tow_count, tvb, 4, 4, ENC_LITTLE_ENDIAN, &tow_count); if (tow_count > 100799) { expert_add_info_format(pinfo, pi_how_tow_count, &ei_ubx_gps_l1_how_tow_count, "Invalid TOW count"); } proto_tree_add_item(how_tree, hf_ubx_gps_l1_how_alert, tvb, 4, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(how_tree, hf_ubx_gps_l1_how_anti_spoof, tvb, 4, 4, ENC_LITTLE_ENDIAN); proto_item* pi_how_sf_id = proto_tree_add_item_ret_uint(how_tree, hf_ubx_gps_l1_how_subframe_id, tvb, 4, 4, ENC_LITTLE_ENDIAN, &subframe_id); if (subframe_id > 5) { expert_add_info_format(pinfo, pi_how_sf_id, &ei_ubx_gps_l1_how_subframe_id, "Invalid subframe ID"); } proto_tree_add_item(how_tree, hf_ubx_gps_l1_how_parity_sol, tvb, 4, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(how_tree, hf_ubx_gps_l1_how_parity, tvb, 4, 4, ENC_LITTLE_ENDIAN); } /* Dissect subframe 1 */ static int dissect_ubx_gps_l1_sf1(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) { dissect_ubx_gps_l1_tlm(tvb, pinfo, tree, data); dissect_ubx_gps_l1_how(tvb, pinfo, tree, data); // subframe 1, word 3 proto_tree *w3_tree = proto_tree_add_subtree_format(tree, tvb, 8, 4, ett_ubx_gps_l1_sf1_w3, NULL, "Word 3"); proto_tree_add_item(w3_tree, hf_ubx_gps_l1_sf1_week_no, tvb, 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w3_tree, hf_ubx_gps_l1_sf1_l2_channel_code, tvb, 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w3_tree, hf_ubx_gps_l1_sf1_ura_index, tvb, 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w3_tree, hf_ubx_gps_l1_sf1_sv_health_summary, tvb, 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w3_tree, hf_ubx_gps_l1_sf1_sv_health, tvb, 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w3_tree, hf_ubx_gps_l1_sf1_iodc_msbs, tvb, 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w3_tree, hf_ubx_gps_l1_sf1_w3_parity, tvb, 8, 4, ENC_LITTLE_ENDIAN); // subframe 1, word 4 proto_tree *w4_tree = proto_tree_add_subtree_format(tree, tvb, 12, 4, ett_ubx_gps_l1_sf1_w4, NULL, "Word 4"); proto_tree_add_item(w4_tree, hf_ubx_gps_l1_sf1_w4_l2_p_data_flag, tvb, 12, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w4_tree, hf_ubx_gps_l1_sf1_w4_reserved, tvb, 12, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w4_tree, hf_ubx_gps_l1_sf1_w4_parity, tvb, 12, 4, ENC_LITTLE_ENDIAN); // subframe 1, word 5 proto_tree *w5_tree = proto_tree_add_subtree_format(tree, tvb, 16, 4, ett_ubx_gps_l1_sf1_w5, NULL, "Word 5"); proto_tree_add_item(w5_tree, hf_ubx_gps_l1_sf1_w5_reserved, tvb, 16, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w5_tree, hf_ubx_gps_l1_sf1_w5_parity, tvb, 16, 4, ENC_LITTLE_ENDIAN); // subframe 1, word 6 proto_tree *w6_tree = proto_tree_add_subtree_format(tree, tvb, 20, 4, ett_ubx_gps_l1_sf1_w6, NULL, "Word 6"); proto_tree_add_item(w6_tree, hf_ubx_gps_l1_sf1_w6_reserved, tvb, 20, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w6_tree, hf_ubx_gps_l1_sf1_w6_parity, tvb, 20, 4, ENC_LITTLE_ENDIAN); // subframe 1, word 7 proto_tree *w7_tree = proto_tree_add_subtree_format(tree, tvb, 24, 4, ett_ubx_gps_l1_sf1_w7, NULL, "Word 7"); proto_tree_add_item(w7_tree, hf_ubx_gps_l1_sf1_w7_reserved, tvb, 24, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w7_tree, hf_ubx_gps_l1_sf1_w7_tgd, tvb, 24, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w7_tree, hf_ubx_gps_l1_sf1_w7_parity, tvb, 24, 4, ENC_LITTLE_ENDIAN); // subframe 1, word 8 proto_tree *w8_tree = proto_tree_add_subtree_format(tree, tvb, 28, 4, ett_ubx_gps_l1_sf1_w8, NULL, "Word 8"); proto_tree_add_item(w8_tree, hf_ubx_gps_l1_sf1_w8_iodc_lsbs, tvb, 28, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w8_tree, hf_ubx_gps_l1_sf1_w8_toc, tvb, 28, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w8_tree, hf_ubx_gps_l1_sf1_w8_parity, tvb, 28, 4, ENC_LITTLE_ENDIAN); // subframe 1, word 9 proto_tree *w9_tree = proto_tree_add_subtree_format(tree, tvb, 32, 4, ett_ubx_gps_l1_sf1_w9, NULL, "Word 9"); proto_tree_add_item(w9_tree, hf_ubx_gps_l1_sf1_w9_af2, tvb, 32, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w9_tree, hf_ubx_gps_l1_sf1_w9_af1, tvb, 32, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w9_tree, hf_ubx_gps_l1_sf1_w9_parity, tvb, 32, 4, ENC_LITTLE_ENDIAN); // subframe 1, word 10 proto_tree *w10_tree = proto_tree_add_subtree_format(tree, tvb, 36, 4, ett_ubx_gps_l1_sf1_w10, NULL, "Word 10"); proto_tree_add_item(w10_tree, hf_ubx_gps_l1_sf1_w10_af0, tvb, 36, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(w10_tree, hf_ubx_gps_l1_sf1_w10_parity, tvb, 36, 4, ENC_LITTLE_ENDIAN); return tvb_captured_length(tvb); } void proto_register_ubx_gps_l1(void) { static hf_register_info hf[] = { // TLM {&hf_ubx_gps_l1_tlm_preamble, {"Preamble", "gps_l1.tlm.preamble", FT_UINT32, BASE_HEX, NULL, 0x3fc00000, NULL, HFILL}}, {&hf_ubx_gps_l1_tlm_message, {"Message", "gps_l1.tlm.message", FT_UINT32, BASE_HEX, NULL, 0x003fff00, NULL, HFILL}}, {&hf_ubx_gps_l1_tlm_integrity, {"Integrity Status Flag (ISF)", "gps_l1.tlm.integrity", FT_BOOLEAN, 32, NULL, 0x00000080, NULL, HFILL}}, {&hf_ubx_gps_l1_tlm_reserved, {"Reserved", "gps_l1.tlm.reserved", FT_UINT32, BASE_HEX, NULL, 0x00000040, NULL, HFILL}}, {&hf_ubx_gps_l1_tlm_parity, {"Parity", "gps_l1.tlm.parity", FT_UINT32, BASE_HEX, NULL, 0x0000003f, NULL, HFILL}}, // HOW {&hf_ubx_gps_l1_how_tow_count, {"Time-of-Week (TOW) Count", "gps_l1.how.tow_count", FT_UINT32, BASE_CUSTOM, CF_FUNC(&fmt_tow_count), 0x3fffe000, NULL, HFILL}}, {&hf_ubx_gps_l1_how_alert, {"Alert", "gps_l1.how.alert", FT_BOOLEAN, 32, NULL, 0x00001000, NULL, HFILL}}, {&hf_ubx_gps_l1_how_anti_spoof, {"Anti-Spoof (A-S)", "gps_l1.how.anti_spoof", FT_BOOLEAN, 32, NULL, 0x00000800, NULL, HFILL}}, {&hf_ubx_gps_l1_how_subframe_id, {"Subframe ID", "gps_l1.how.subframe_id", FT_UINT32, BASE_DEC, NULL, 0x00000700, NULL, HFILL}}, {&hf_ubx_gps_l1_how_parity_sol, {"Solved for parity zero bits", "gps_l1.how.parity_sol", FT_UINT32, BASE_HEX, NULL, 0x000000c0, NULL, HFILL}}, {&hf_ubx_gps_l1_how_parity, {"Parity", "gps_l1.how.parity", FT_UINT32, BASE_DEC, NULL, 0x0000003f, NULL, HFILL}}, // SF1 {&hf_ubx_gps_l1_sf1, {"Subframe 1", "gps_l1.sf1", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_week_no, {"Week Number", "gps_l1.sf1.week_number", FT_UINT32, BASE_DEC, NULL, 0x3ff00000, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_l2_channel_code, {"L2 Channel Code", "gps_l1.sf1.l2_channel_code", FT_UINT32, BASE_HEX, VALS(L2_CHANNEL_CODE), 0x000c0000, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_ura_index, {"URA Index", "gps_l1.sf1.ura_index", FT_UINT32, BASE_HEX, VALS(URA_INDEX), 0x0003c000, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_sv_health_summary, {"SV Health Summary", "gps_l1.sf1.sv_health_summary", FT_UINT32, BASE_HEX, VALS(SV_HEALTH_SUMMARY), 0x00002000, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_sv_health, {"SV's Signal Component Health Status", "gps_l1.sf1.sv_health", FT_UINT32, BASE_HEX, VALS(SV_HEALTH_CODE), 0x00001f00, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_iodc_msbs, {"Issue of Data Clock (IODC) MSBs", "gps_l1.sf1.iodc_msbs", FT_UINT32, BASE_HEX, NULL, 0x000000c0, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w3_parity, {"Parity", "gps_l1.sf1.w3_parity", FT_UINT32, BASE_HEX, NULL, 0x0000003f, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w4_l2_p_data_flag, {"L2 P Data Flag", "gps_l1.sf1.l2_p_data_flag", FT_BOOLEAN, 32, NULL, 0x20000000, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w4_reserved, {"Reserved", "gps_l1.sf1.w4_reserved", FT_UINT32, BASE_HEX, NULL, 0x1fffffc0, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w4_parity, {"Parity", "gps_l1.sf1.w4_parity", FT_UINT32, BASE_HEX, NULL, 0x0000003f, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w5_reserved, {"Reserved", "gps_l1.sf1.w5_reserved", FT_UINT32, BASE_HEX, NULL, 0x3fffffc0, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w5_parity, {"Parity", "gps_l1.sf1.w5_parity", FT_UINT32, BASE_HEX, NULL, 0x0000003f, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w6_reserved, {"Reserved", "gps_l1.sf1.w6_reserved", FT_UINT32, BASE_HEX, NULL, 0x3fffffc0, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w6_parity, {"Parity", "gps_l1.sf1.w6_parity", FT_UINT32, BASE_HEX, NULL, 0x0000003f, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w7_reserved, {"Reserved", "gps_l1.sf1.w7_reserved", FT_UINT32, BASE_HEX, NULL, 0x3fffc000, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w7_tgd, {"Estimated Group Delay Differential T_GD", "gps_l1.sf1.w7_tgd", FT_INT32, BASE_DEC, NULL, 0x00003fc0, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w7_parity, {"Parity", "gps_l1.sf1.w7_parity", FT_UINT32, BASE_HEX, NULL, 0x0000003f, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w8_iodc_lsbs, {"Issue of Data Clock (IODC) LSBs", "gps_l1.sf1.w8_iodc_lsbs", FT_UINT32, BASE_HEX, NULL, 0x3fc00000, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w8_toc, {"Clock Data Reference Time t_OC", "gps_l1.sf1.w8_toc", FT_UINT32, BASE_CUSTOM, CF_FUNC(&fmt_t_oc), 0x003fffc0, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w8_parity, {"Parity", "gps_l1.sf1.w8_parity", FT_UINT32, BASE_HEX, NULL, 0x0000003f, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w9_af2, {"Drift Rate Correction Coefficient a_f2", "gps_l1.sf1.w9_af2", FT_INT32, BASE_DEC, NULL, 0x3fc00000, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w9_af1, {"SV Clock Drift Correction Coefficient a_f1", "gps_l1.sf1.w9_af1", FT_INT32, BASE_DEC, NULL, 0x003fffc0, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w9_parity, {"Parity", "gps_l1.sf1.w9_parity", FT_UINT32, BASE_HEX, NULL, 0x0000003f, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w10_af0, {"SV Clock Bias Correction Coefficient a_f0", "gps_l1.sf1.w10_af0", FT_INT32, BASE_DEC, NULL, 0x3fffffc0, NULL, HFILL}}, {&hf_ubx_gps_l1_sf1_w10_parity, {"Parity", "gps_l1.sf1.w10_parity", FT_UINT32, BASE_HEX, NULL, 0x0000003f, NULL, HFILL}}, }; expert_module_t *expert_ubx_gps_l1; static ei_register_info ei[] = { {&ei_ubx_gps_l1_tlm_preamble, {"gps_l1.tlm.preamble", PI_PROTOCOL, PI_WARN, "Illegal preamble", EXPFILL}}, {&ei_ubx_gps_l1_how_tow_count, {"gps_l1.how.tow_count", PI_PROTOCOL, PI_WARN, "Illegal TOW count", EXPFILL}}, {&ei_ubx_gps_l1_how_subframe_id, {"gps_l1.how.subframe_id", PI_PROTOCOL, PI_WARN, "Illegal subframe ID", EXPFILL}}, }; static gint *ett[] = { &ett_ubx_gps_l1, &ett_ubx_gps_l1_tlm, &ett_ubx_gps_l1_how, &ett_ubx_gps_l1_sf1_w3, &ett_ubx_gps_l1_sf1_w4, &ett_ubx_gps_l1_sf1_w5, &ett_ubx_gps_l1_sf1_w6, &ett_ubx_gps_l1_sf1_w7, &ett_ubx_gps_l1_sf1_w8, &ett_ubx_gps_l1_sf1_w9, &ett_ubx_gps_l1_sf1_w10, }; proto_ubx_gps_l1 = proto_register_protocol("GPS L1 Navigation Message", "GPS L1", "gps_l1"); register_dissector("ubx_gps_l1", dissect_ubx_gps_l1, proto_ubx_gps_l1); proto_register_field_array(proto_ubx_gps_l1, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_ubx_gps_l1 = expert_register_protocol(proto_ubx_gps_l1); expert_register_field_array(expert_ubx_gps_l1, ei, array_length(ei)); ubx_gps_l1_sf_dissector_table = register_dissector_table("ubx.rxm.sfrbx.gps_l1.sf", "GPS L1 LNAV Subframe", proto_ubx_gps_l1, FT_UINT8, BASE_DEC); } void proto_reg_handoff_ubx_gps_l1(void) { dissector_add_uint("ubx.rxm.sfrbx.gnssid", GNSS_ID_GPS, create_dissector_handle(dissect_ubx_gps_l1, proto_ubx_gps_l1)); dissector_add_uint("ubx.rxm.sfrbx.gps_l1.sf", 1, create_dissector_handle(dissect_ubx_gps_l1_sf1, proto_ubx_gps_l1)); }