From 35bd5ccc552b621d146a4a8cfcaf996aa3bb884b Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Mon, 10 Feb 2025 23:45:56 -0500 Subject: [PATCH] Code Arrangement and Additions: Migrate Harris Alias for vPDU; Setup Harris Alias for LCW; Working Harris GPS for LCW; Harris GRG Bitmap(speculative); Migrate Tait Alias for LCW; Misc Tweaks; --- include/dsd.h | 3 + src/dsd_alias.c | 177 +++++++++++++++++++++++++++++++++++++++++++++-- src/dsd_gps.c | 20 ++++-- src/p25_lcw.c | 80 ++++++++------------- src/p25p1_ldu2.c | 4 +- src/p25p2_vpdu.c | 98 ++++---------------------- 6 files changed, 234 insertions(+), 148 deletions(-) diff --git a/include/dsd.h b/include/dsd.h index 7903a31..3309f7f 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -1265,6 +1265,9 @@ void apx_embedded_alias_blocks_phase1 (dsd_opts * opts, dsd_state * state, uint8 void apx_embedded_alias_blocks_phase2 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits); void apx_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t num_bits, uint8_t * input); void apx_embedded_alias_dump (dsd_opts * opts, dsd_state * state, uint16_t num_bytes, uint8_t * input, uint8_t * decoded); +void l3h_embedded_alias_blocks_phase1 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits); +void l3h_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t len, uint8_t * input); +void tait_iso7_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t len, uint8_t * input); void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]); void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]); void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input); diff --git a/src/dsd_alias.c b/src/dsd_alias.c index 6c8fc3d..1ead694 100644 --- a/src/dsd_alias.c +++ b/src/dsd_alias.c @@ -86,6 +86,26 @@ void apx_embedded_alias_test_phase1 (dsd_opts * opts, dsd_state * state) for (uint64_t i = 0; i < 8; i++) lcw[i+64] = (temp_b >> (7-i)) & 1; p25_lcw(opts, state, lcw, 0); + + //Harris Phase 1 GPS + state->lastsrc = 1000; + temp_a = 0x2AA41D4C24262328; temp_b = 0xAF; + memset (lcw, 0, sizeof(lcw)); + for (uint64_t i = 0; i < 64; i++) + lcw[i] = (temp_a >> (63-i)) & 1; + for (uint64_t i = 0; i < 8; i++) + lcw[i+64] = (temp_b >> (7-i)) & 1; + p25_lcw(opts, state, lcw, 0); + + temp_a = 0x2BA44E0DB2660108; temp_b = 0x14; + memset (lcw, 0, sizeof(lcw)); + for (uint64_t i = 0; i < 64; i++) + lcw[i] = (temp_a >> (63-i)) & 1; + for (uint64_t i = 0; i < 8; i++) + lcw[i+64] = (temp_b >> (7-i)) & 1; + p25_lcw(opts, state, lcw, 0); + state->lastsrc = 0; + } void apx_embedded_alias_header_phase1 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits) @@ -183,7 +203,7 @@ void apx_embedded_alias_header_phase2 (dsd_opts * opts, dsd_state * state, uint8 fprintf (stderr, " SN: %X;", sn); //NOTE: vPDU header is also a partial block, and has a block num and SN value in it fprintf (stderr, " BN: %d/%d;", bn, ta_len); - //bit array to rearrange input lc_bits from phase 2 mac to match the phase 1 header and block handling + //bit array to rearrange input lc_bits from phase 2 input to match the phase 1 header and block handling uint8_t bits[136]; memset(bits, 0, sizeof(bits)); memcpy (bits, lc_bits, 2*8*sizeof(uint8_t)); //header 0x9190 memcpy (bits+16, lc_bits+24, 4*8*sizeof(uint8_t)); //BN, SN, etc @@ -432,8 +452,8 @@ void apx_embedded_alias_dump (dsd_opts * opts, dsd_state * state, uint16_t num_b //open file by name that is supplied in the ncurses terminal, or cli pFile = fopen (opts->group_in_file, "a"); fprintf (pFile, "%d,D,", rid); //may want to not use this one - fprintf (pFile, "%s", str); //for whatever reason, Cygwin likes the string seperate (overflow on pFile?) - fprintf (pFile, ",FQS:%05X.%03X.%06X(%d),RFSS:%lld,SITE:%lld\n", wacn, sys, rid, rid, state->p2_rfssid, state->p2_siteid); + fprintf (pFile, "%s", str); + fprintf (pFile, ",FQS:%05X.%03X.%06X(%d),Moto\n", wacn, sys, rid, rid); fclose (pFile); } @@ -443,4 +463,153 @@ void apx_embedded_alias_dump (dsd_opts * opts, dsd_state * state, uint16_t num_b //end Motorola P25 OTA Alias Decoding -//TODO: Migrate Other OTA Alias functions here \ No newline at end of file +//TODO: Migrate Other OTA Alias functions here + +void l3h_embedded_alias_blocks_phase1 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits) +{ + + uint8_t op = (uint8_t)ConvertBitIntoBytes(&lc_bits[0], 8); + uint8_t ptr = op-0x32; + uint8_t bytes[7]; memset(bytes, 0, sizeof(bytes)); + for (uint8_t i = 0; i < 7; i++) + bytes[i] = (uint8_t)ConvertBitIntoBytes(&lc_bits[16+(i*8)], 8); + + //use +4 offset to match the MAC vPDU since that was already worked out long ago + memcpy(state->dmr_pdu_sf[slot]+4+(ptr*7), bytes, sizeof(bytes)); + + //to be tested + if (ptr == 4) //is there always 4 blocks, or is it a variable amount? + l3h_embedded_alias_decode(opts, state, slot, 4+28, state->dmr_pdu_sf[slot]); +} + +void l3h_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t len, uint8_t * input) +{ + + //storage info for storing to groupName, if not available + char str[40]; memset (str, 0, sizeof(str)); + char ttemp[40]; memset (ttemp, 0, sizeof(ttemp)); + uint8_t wr = 0; + uint32_t tsrc = 0, ttg = 0; + if (slot == 0 && state->lastsrc != 0) tsrc = state->lastsrc; + if (slot == 1 && state->lastsrcR != 0) tsrc = state->lastsrcR; + if (slot == 0 && state->lasttg != 0) ttg = state->lasttg; + if (slot == 1 && state->lasttgR != 0) ttg = state->lasttgR; + + int8_t ptr = 0; + fprintf (stderr, " TG: %d; SRC: %d; Talker Alias: ", ttg, tsrc); + for (int8_t i = 4; i <= len; i++) + { + if ( (input[i] > 0x19) && (input[i] < 0x7F) ) + fprintf (stderr, "%c", (char)input[i]); + else fprintf (stderr, " "); + + if (input[i] == 0x2C) //remove a comma if it exists, change it to a 0x2E dot + ttemp[ptr] = 0x2E; + else if ( (input[i] > 0x19) && (input[i] < 0x7F) ) + ttemp[ptr] = input[i]; + else if (input[i] != 0) + ttemp[ptr] = 0x20; //space + + ptr++; + } + + //assign completed talker to a more useful string instead + snprintf (str, ptr+1, "%s", ttemp); + + //The Duke Energy system may relay two src values, may be a good idea to pick one and stick with it + if (tsrc != 0) + { + for (int16_t i = 0; i < state->group_tally; i++) + { + if (state->group_array[i].groupNumber == tsrc) + { + wr = 1; //already in there, so no need to assign it + break; + } + } + + if (wr == 0) //not already in there, so save it there now + { + state->group_array[state->group_tally].groupNumber = tsrc; + sprintf (state->group_array[state->group_tally].groupMode, "%s", "D"); + sprintf (state->group_array[state->group_tally].groupName, "%s", str); + state->group_tally++; + + //if we have an opened group file, let's write what info we found into it + if (opts->group_in_file[0] != 0) //file is available + { + FILE * pFile; //file pointer + //open file by name that is supplied in the ncurses terminal, or cli + pFile = fopen (opts->group_in_file, "a"); + fprintf (pFile, "%d,D,", tsrc); + fprintf (pFile, "%s", str); + fprintf (pFile, ",TG:%d,SYS:%03llX,RFSS:%lld,SITE:%lld,Harris\n", ttg, state->p2_sysid, state->p2_rfssid, state->p2_siteid); + fclose (pFile); + } + + } + } + + //debug + // fprintf (stderr, "\n WR: %d TG: %d SRC: %d Res: %d Len: %d STR: %s", wr, ttg, tsrc, res, len, str); + + //reset storage + memset (state->dmr_pdu_sf[slot], 0, sizeof (state->dmr_pdu_sf[slot])); + +} + +void tait_iso7_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t len, uint8_t * input) +{ + + UNUSED(slot); + uint8_t alias[24]; memset(alias, 0, sizeof(alias)); + for (uint8_t i = 0; i < len; i++) + { + alias[i] = (uint8_t)ConvertBitIntoBytes(&input[16+(i*7)], 7); + fprintf (stderr, "%c", alias[i]); + if (alias[i] == 0x2C) //change a comma to a dot + alias[i] = 0x2E; + else if (alias[i] < 0x20) //change any garble / control chars to a space + alias[i] = 0x20; + } + + //flag to indicate this already exists in import or group struct + uint8_t wr = 0; + uint32_t rid = state->lastsrc; + uint16_t nac = state->nac; + + if (rid != 0) + { + for (int16_t i = 0; i < state->group_tally; i++) + { + if (state->group_array[i].groupNumber == rid) + { + wr = 1; //already in there, so no need to assign it + break; + } + } + + if (wr == 0) //not already in there, so save it there now + { + state->group_array[state->group_tally].groupNumber = rid; + sprintf (state->group_array[state->group_tally].groupMode, "%s", "D"); + sprintf (state->group_array[state->group_tally].groupName, "%s", alias); + state->group_tally++; + + //if we have an opened group file, let's write what info we found into it + if (opts->group_in_file[0] != 0) //file is available + { + FILE * pFile; //file pointer + //open file by name that is supplied in the ncurses terminal, or cli + pFile = fopen (opts->group_in_file, "a"); + fprintf (pFile, "%d,D,", rid); //may want to not use this one + fprintf (pFile, "%s,", alias); + fprintf (pFile, "%03X,", nac); //if we find this on a trunking system, may want to add the site and rfss id + fprintf (pFile, "%s", ",Tait\n"); + fclose (pFile); + } + + } + + } +} \ No newline at end of file diff --git a/src/dsd_gps.c b/src/dsd_gps.c index e475124..2bb27b2 100644 --- a/src/dsd_gps.c +++ b/src/dsd_gps.c @@ -333,16 +333,24 @@ void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t if (!nmea_ns) latitude *= -1.0f; //0 is South, 1 is North if (!nmea_ew) longitude *= -1.0f; //0 is West, 1 is East - fprintf (stderr, "\n"); + //is this from LCW, or MAC? + uint16_t header = (uint16_t)ConvertBitIntoBytes(&input[0], 16); - fprintf (stderr, " VCH: %d - SRC: %08d;", slot, src); + fprintf (stderr, "\n"); + if (header == 0x2AA4) + fprintf (stderr, " SRC: %08d;", src); + else + fprintf (stderr, " VCH: %d - SRC: %08d;", slot, src); fprintf (stderr, " GPS: %f%s, %f%s;", latitude, deg_glyph, longitude, deg_glyph); //Speed in Knots (assuming in knots, and not in mps, or kph) - if (nmea_speed > 126) - fprintf (stderr, " SPD > 126 knots or %f MPH;", fmph); //using MPH here, its Harris, they're in the U.S. - else - fprintf (stderr, " SPD: %d knots; %f MPH;", nmea_speed, fmph); + if (header != 0x2AA4) //can't yet verify this is present or accurate on LCW + { + if (nmea_speed > 126) + fprintf (stderr, " SPD > 126 knots or %f MPH;", fmph); //using MPH here, its Harris, they're in the U.S. + else + fprintf (stderr, " SPD: %d knots; %f MPH;", nmea_speed, fmph); + } //Course Over Ground (COG) fprintf (stderr, " COG: %03d%s;", nmea_cog, deg_glyph); //%360 diff --git a/src/p25_lcw.c b/src/p25_lcw.c index 62eb91e..371adc2 100644 --- a/src/p25_lcw.c +++ b/src/p25_lcw.c @@ -469,6 +469,32 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir apx_embedded_alias_blocks_phase1 (opts, state, 0, LCW_bits); } + else if (lc_mfid == 0xA4 && lc_opcode > 0x31 && lc_opcode < 0x36) + { + fprintf (stderr, " MFIDA4 (Harris) Talker Alias Blocks"); + l3h_embedded_alias_blocks_phase1 (opts, state, 0, LCW_bits); + } + + //Harris GPS on Phase 1 tested and working + else if (lc_mfid == 0xA4 && lc_opcode == 0x2A) + { + fprintf (stderr, " MFIDA4 (Harris) GPS Block 1"); + memset(state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0])); + memcpy(state->dmr_pdu_sf[0], LCW_bits, 16*sizeof(uint8_t)); //opcode and mfid for check + memcpy(state->dmr_pdu_sf[0]+40, LCW_bits+16, 56*sizeof(uint8_t)); //+40 offset to match the vPDU decoder + } + + else if (lc_mfid == 0xA4 && lc_opcode == 0x2B) + { + fprintf (stderr, " MFIDA4 (Harris) GPS Block 2"); + memcpy(state->dmr_pdu_sf[0]+40+56, LCW_bits+16, 56*sizeof(uint8_t)); //+40 +56 to offset first block + uint16_t check = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[0][0], 16); + if (check == 0x2AA4) + nmea_harris(opts, state, state->dmr_pdu_sf[0], (uint32_t)state->lastsrc, 0); + else fprintf (stderr, " Missing GPS Block 1"); + memset(state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0])); + } + //observed format value on Harris SNDCP data channel (Phase 2 CC to Phase 1 MPDU channel) else if (lc_mfid == 0xA4 && lc_format == 0x0A) { @@ -483,58 +509,8 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir //observed on Tait conventional / uplink (TODO: Move all this to dsd_alias.c) else if (lc_mfid == 0xD8 && lc_format == 0x00) { - fprintf (stderr, " MFID D8 (Tait) Talker Alias: "); - //Up to 8 ISO7 encoded characters. Can other encoding schemes also be used? - uint8_t alias[8]; memset(alias, 0, sizeof(alias)); - for (uint i = 0; i < 8; i++) - { - alias[i] = (uint8_t)ConvertBitIntoBytes(&LCW_bits[16+(i*7)], 7); - fprintf (stderr, "%c", alias[i]); - if (alias[i] == 0x2C) //change a comma to a dot - alias[i] = 0x2E; - else if (alias[i] < 0x20) //change any garble / control chars to a space - alias[i] = 0x20; - } - - //flag to indicate this already exists in import or group struct - uint8_t wr = 0; - uint32_t rid = state->lastsrc; - - if (rid != 0) - { - for (int16_t i = 0; i < state->group_tally; i++) - { - if (state->group_array[i].groupNumber == rid) - { - wr = 1; //already in there, so no need to assign it - break; - } - } - - if (wr == 0) //not already in there, so save it there now - { - state->group_array[state->group_tally].groupNumber = rid; - sprintf (state->group_array[state->group_tally].groupMode, "%s", "D"); - sprintf (state->group_array[state->group_tally].groupName, "%s", alias); - state->group_tally++; - - //if we have an opened group file, let's write what info we found into it - if (opts->group_in_file[0] != 0) //file is available - { - FILE * pFile; //file pointer - //open file by name that is supplied in the ncurses terminal, or cli - pFile = fopen (opts->group_in_file, "a"); - fprintf (pFile, "%d,D,", rid); //may want to not use this one - fprintf (pFile, "%s", alias); //for whatever reason, Cygwin likes the string seperate (overflow on pFile?) - // fprintf (pFile, ",FQS: %05X.%03X.%06X (%d),RFSS:%lld,SITE:%lld\n", wacn, sys, rid, rid, state->p2_rfssid, state->p2_siteid); - fprintf (pFile, "%s", ",Tait Talker Alias\n"); - fclose (pFile); - } - - } - - } - + fprintf (stderr, " MFIDD8 (Tait) Talker Alias: "); + tait_iso7_embedded_alias_decode(opts, state, 0, 8, LCW_bits); } //not a duplicate, this one will print if not MFID 0 or 1 diff --git a/src/p25p1_ldu2.c b/src/p25p1_ldu2.c index 54cd32e..86b15b2 100644 --- a/src/p25p1_ldu2.c +++ b/src/p25p1_ldu2.c @@ -698,8 +698,8 @@ void LFSRP(dsd_state * state) //print current ENC identifiers already known and new calculated MI fprintf (stderr, "%s", KYEL); if (state->currentslot == 0) - fprintf (stderr, " LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algid, state->payload_keyid, state->payload_miP); + fprintf (stderr, "\n LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algid, state->payload_keyid, state->payload_miP); if (state->currentslot == 1) - fprintf (stderr, " LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algidR, state->payload_keyidR, state->payload_miN); + fprintf (stderr, "\n LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algidR, state->payload_keyidR, state->payload_miN); fprintf (stderr, "%s", KNRM); } diff --git a/src/p25p2_vpdu.c b/src/p25p2_vpdu.c index 87d248f..936ee88 100644 --- a/src/p25p2_vpdu.c +++ b/src/p25p2_vpdu.c @@ -1730,97 +1730,27 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon // 6.2.36 Manufacturer Specific regarding octet 3 as len int len = MAC[3+len_a] & 0x3F; int res = MAC[3+len_a] >> 6; - int k = 0; - - //storage info for storing to groupName, if not available - char str[20]; char ttemp[20]; - int wr = 0, tsrc = 0, ttg = 0; - if (slot == 0 && state->lastsrc != 0) tsrc = state->lastsrc; - if (slot == 1 && state->lastsrcR != 0) tsrc = state->lastsrcR; - if (slot == 0 && state->lasttg != 0) ttg = state->lasttg; - if (slot == 1 && state->lasttgR != 0) ttg = state->lasttgR; - - //init str and ttemp as NULL zeroes - for (i = 0; i < 20; i++) - { - str[i] = 0; - ttemp[i] = 0; - } - - //NOTE: slot is already checked //sanity check that we don't exceed the max MAC array size if (len > 24) len = 24; //should never exceed this len, but just in case it does - //(TODO: Move Alias to dsd_alias.c) - //Harris "Talker" Alias -- Not always in the SACCH, has been seen in the FACCH as well (before MAC_PTT) - if (MAC[1+len_a] == 0xA8) //1010 1000 (so, its opcode is 0x28, with the b = 0b10 value for manufacturer message?) + //Harris "Talker" Alias + if (MAC[1+len_a] == 0xA8) { - fprintf (stderr, "\n MFID A4 (Harris); VCH %d; TG: %d; SRC: %d; Talker Alias: ", slot, ttg, tsrc); - for (i = 4; i <= len; i++) //len doesn't seem to include the CRC12 - { - if ( (MAC[i+len_a] > 0x19) && (MAC[i+len_a] < 0x7F) ) - fprintf (stderr, "%c", (char)MAC[i+len_a]); - else fprintf (stderr, " "); + // fprintf (stderr, "\n MFID A4 (Harris); VCH %d; TG: %d; SRC: %d; Talker Alias: ", slot, ttg, tsrc); + fprintf (stderr, "\n MFID A4 (Harris); VCH %d;", slot); + uint8_t bytes[24]; memset(bytes, 0, sizeof(bytes)); + for (int8_t i = 0; i < 24; i++) + bytes[i] = (uint8_t)MAC[i]; + l3h_embedded_alias_decode(opts, state, slot, len, bytes); + } - //disabled, since we load this to the generic_talker_alias string now - // if ( (MAC[i+len_a] > 0x19) && (MAC[i+len_a] < 0x7F) ) - // state->dmr_alias_block_segment[slot][0][k/4][k%4] = MAC[i+len_a]; - // else state->dmr_alias_block_segment[slot][0][k/4][k%4] = 0x20; - - if (MAC[i+len_a] == 0x2C) //remove a comma if it exists, change it to a 0x2E dot - ttemp[k] = 0x2E; - else if ( (MAC[i+len_a] > 0x19) && (MAC[i+len_a] < 0x7F) ) - ttemp[k] = MAC[i+len_a]; - else if (MAC[i+len_a] != 0) - ttemp[k] = 0x20; //space - - k++; - } - - //assign completed talker to a more useful string instead - snprintf (str, k+1, "%s", ttemp); //k+1, because we start at index k = 0; - - //see if we can fill in the groupName if we have a good src value that isn't 0 - //usually, we have TG values in the groupName field, but this is just for dumping - //information for research, etc - if (tsrc != 0) - { - for (int x = 0; x < state->group_tally; x++) - { - if (state->group_array[x].groupNumber == tsrc) - { - wr = 1; //already in there, so no need to assign it - break; - } - } - - if (wr == 0) //not already in there, so save it there now - { - state->group_array[state->group_tally].groupNumber = tsrc; - sprintf (state->group_array[state->group_tally].groupMode, "%s", "D"); - sprintf (state->group_array[state->group_tally].groupName, "%s", str); - state->group_tally++; - - //if we have an opened group file, let's write what info we found into it - if (opts->group_in_file[0] != 0) //file is available - { - FILE * pFile; //file pointer - //open file by name that is supplied in the ncurses terminal, or cli - pFile = fopen (opts->group_in_file, "a"); - // fprintf (pFile, "%d,D,%s,TG:%d,SYS:%03llX,RFSS:%lld,SITE:%lld\n", tsrc, str, ttg, state->p2_sysid, state->p2_rfssid, state->p2_siteid); //Cygwin Hates this for some reason - fprintf (pFile, "%d,D,", tsrc); - fprintf (pFile, "%s", str); //for whatever reason, Cygwin likes the string seperate (overflow on pFile?) - fprintf (pFile, ",TG:%d,SYS:%03llX,RFSS:%lld,SITE:%lld\n", ttg, state->p2_sysid, state->p2_rfssid, state->p2_siteid); - fclose (pFile); - } - - } - } - - //debug - // fprintf (stderr, "\n WR: %d TG: %d SRC: %d Res: %d Len: %d STR: %s", wr, ttg, tsrc, res, len, str); + else if (MAC[1+len_a] == 0x81) //speculative based on the EDACS message that is also flushed with all F hex values + { + fprintf (stderr, "\n MFID A4 (Harris) Group Regroup Bitmap: "); + for (i = 4; i <= len; i++) + fprintf (stderr, "%02llX", MAC[i+len_a]); } else