EDACS: EA I-Call decoding improvements (#205)
* EDACS: formatting nit
* EDACS: add name to credits
* EDACS: Handle initial grant vs grant update for i-call
* EDACS: consistency for group vs i-call
* EDACS: file naming for i-call recordings
* EDACS: EA refactor when MT1 is 0x1F
* EDACS: check we know CC LCN before leaving it
* EDACS: fix breaking change for Standard
Revert mistake in f68367c4f3
* Fix patent number
* EDACS: Fix Compiler Error 1;
Fix Rogue Copy Paste
* EDACS: Add MT1, MT2, and FR1 and FR4 Dumps on Payload;
---------
Co-authored-by: lwvmobile <59371473+lwvmobile@users.noreply.github.com>
This commit is contained in:
parent
a7de24c47b
commit
69f532a022
|
|
@ -4,7 +4,7 @@
|
|||
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and
|
||||
[Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDRTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), [OK-DMRlib](https://github.com/OK-DMR/ok-dmrlib "OK-DMRlib"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, EDACS, YSF, M17, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users in mind, so please understand that this version may not compile, compile easily, or run correctly in other environments.
|
||||
|
||||
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu, Forts, thewraithe2008, RayAir, Cretu, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thanks to volo-zyko for cleaning up a lot of code. Thank you everybody.
|
||||
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu, Forts, thewraithe2008, RayAir, Cretu, ilyacodes, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thanks to volo-zyko for cleaning up a lot of code. Thank you everybody.
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
209
src/edacs-fme.c
209
src/edacs-fme.c
|
|
@ -15,6 +15,9 @@
|
|||
*
|
||||
* LWVMOBILE
|
||||
* 2023-11 Version EDACS-FM Florida Man Edition
|
||||
*
|
||||
* ilyacodes
|
||||
* 2024-03 added EA i-call and login message decoding
|
||||
*-----------------------------------------------------------------------------*/
|
||||
#include "dsd.h"
|
||||
|
||||
|
|
@ -526,81 +529,112 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
|
||||
//Site ID
|
||||
unsigned long long int site_id = 0; //we probably could just make this an int as well as the state variables
|
||||
if (mt1 == 0x1F && mt2 == 0xA)
|
||||
|
||||
//add mt1 and mt2 for easy debug / decode
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, " MT1: %02X; MT2: %X; ", mt1, mt2);
|
||||
|
||||
//MT1 of 0x1F indicates to use MT2 for the opcode. See US patent US7546135B2, Figure 2b.
|
||||
if (mt1 == 0x1F)
|
||||
{
|
||||
site_id = ((fr_1 & 0x1F000) >> 12) | ((fr_1 & 0x1F000000) >> 19);
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Site ID [%02llX][%03lld] Extended Addressing", site_id, site_id);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
state->edacs_site_id = site_id;
|
||||
}
|
||||
//Patch Groups
|
||||
else if (mt1 == 0x1F && mt2 == 0xC)
|
||||
{
|
||||
int patch_site = ((fr_4t & 0xFF00000000) >> 32); //is site info valid, 0 for all sites? else patch only good on site listed?
|
||||
int sourcep = ((fr_1t & 0xFFFF000) >> 12);
|
||||
int targetp = ((fr_4t & 0xFFFF000) >> 12);
|
||||
fprintf (stderr, " Patch -- Site [%d] Source [%d] Target [%d] ", patch_site, sourcep, targetp);
|
||||
}
|
||||
//Adjacent Sites
|
||||
else if (mt1 == 0x1F && mt2 == 0x1)
|
||||
{
|
||||
fprintf (stderr, " Adjacent Site");
|
||||
if ( ((fr_1t & 0xFF000) >> 12) > 0 )
|
||||
|
||||
//Test Call (not seen in the wild, see US patent US7546135B2, Figure 2b)
|
||||
if (mt2 == 0x0)
|
||||
{
|
||||
int adj = (fr_1t & 0xFF000) >> 12;
|
||||
int adj_l = (fr_1t & 0x1F000000) >> 24;
|
||||
fprintf (stderr, " [%02X][%03d] on CC LCN [%02d]", adj, adj, adj_l);
|
||||
fprintf (stderr, " Initiate Test Call");
|
||||
}
|
||||
}
|
||||
//Control Channel LCN
|
||||
else if (mt1 == 0x1F && mt2 == 0x8)
|
||||
{
|
||||
fprintf (stderr, " Control Channel LCN");
|
||||
if (((fr_4t >> 12) & 0x1F) != 0)
|
||||
|
||||
else if (mt2 == 0xA)
|
||||
{
|
||||
state->edacs_cc_lcn = ((fr_4t >> 12) & 0x1F);
|
||||
if (state->edacs_cc_lcn > state->edacs_lcn_count && lcn < 26) //26, or 27. shouldn't matter don't think cc lcn will give a status lcn val
|
||||
site_id = ((fr_1 & 0x1F000) >> 12) | ((fr_1 & 0x1F000000) >> 19);
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Site ID [%02llX][%03lld] Extended Addressing", site_id, site_id);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
state->edacs_site_id = site_id;
|
||||
}
|
||||
//Patch Groups
|
||||
else if (mt2 == 0xC)
|
||||
{
|
||||
int patch_site = ((fr_4t & 0xFF00000000) >> 32); //is site info valid, 0 for all sites? else patch only good on site listed?
|
||||
int sourcep = ((fr_1t & 0xFFFF000) >> 12);
|
||||
int targetp = ((fr_4t & 0xFFFF000) >> 12);
|
||||
fprintf (stderr, " Patch -- Site [%d] Source [%d] Target [%d] ", patch_site, sourcep, targetp);
|
||||
}
|
||||
//Serial Number Request (not seen in the wild, see US patent 20030190923, Figure 2b)
|
||||
else if (mt2 == 0xD)
|
||||
{
|
||||
fprintf (stderr, " Serial Number Request");
|
||||
}
|
||||
//Adjacent Sites
|
||||
else if (mt2 == 0x1)
|
||||
{
|
||||
fprintf (stderr, " Adjacent Site");
|
||||
if ( ((fr_1t & 0xFF000) >> 12) > 0 )
|
||||
{
|
||||
state->edacs_lcn_count = state->edacs_cc_lcn;
|
||||
}
|
||||
fprintf (stderr, " [%d]", state->edacs_cc_lcn);
|
||||
|
||||
//check for control channel lcn frequency if not provided in channel map or in the lcn list
|
||||
if (state->trunk_lcn_freq[state->edacs_cc_lcn-1] == 0)
|
||||
{
|
||||
long int lcnfreq = 0;
|
||||
//if using rigctl, we can ask for the currrent frequency
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
lcnfreq = GetCurrentFreq (opts->rigctl_sockfd);
|
||||
if (lcnfreq != 0) state->trunk_lcn_freq[state->edacs_cc_lcn-1] = lcnfreq;
|
||||
}
|
||||
//if using rtl input, we can ask for the current frequency tuned
|
||||
if (opts->audio_in_type == 3)
|
||||
{
|
||||
lcnfreq = (long int)opts->rtlsdr_center_freq;
|
||||
if (lcnfreq != 0) state->trunk_lcn_freq[state->edacs_cc_lcn-1] = lcnfreq;
|
||||
}
|
||||
}
|
||||
|
||||
//set trunking cc here so we know where to come back to
|
||||
if (opts->p25_trunk == 1 && state->trunk_lcn_freq[state->edacs_cc_lcn-1] != 0)
|
||||
{
|
||||
state->p25_cc_freq = state->trunk_lcn_freq[state->edacs_cc_lcn-1]; //index starts at zero, lcn's locally here start at 1
|
||||
int adj = (fr_1t & 0xFF000) >> 12;
|
||||
int adj_l = (fr_1t & 0x1F000000) >> 24;
|
||||
fprintf (stderr, " [%02X][%03d] on CC LCN [%02d]", adj, adj, adj_l);
|
||||
}
|
||||
}
|
||||
//Control Channel LCN
|
||||
else if (mt2 == 0x8)
|
||||
{
|
||||
fprintf (stderr, " Control Channel LCN");
|
||||
if (((fr_4t >> 12) & 0x1F) != 0)
|
||||
{
|
||||
state->edacs_cc_lcn = ((fr_4t >> 12) & 0x1F);
|
||||
if (state->edacs_cc_lcn > state->edacs_lcn_count && lcn < 26) //26, or 27. shouldn't matter don't think cc lcn will give a status lcn val
|
||||
{
|
||||
state->edacs_lcn_count = state->edacs_cc_lcn;
|
||||
}
|
||||
fprintf (stderr, " [%d]", state->edacs_cc_lcn);
|
||||
|
||||
//check for control channel lcn frequency if not provided in channel map or in the lcn list
|
||||
if (state->trunk_lcn_freq[state->edacs_cc_lcn-1] == 0)
|
||||
{
|
||||
long int lcnfreq = 0;
|
||||
//if using rigctl, we can ask for the currrent frequency
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
lcnfreq = GetCurrentFreq (opts->rigctl_sockfd);
|
||||
if (lcnfreq != 0) state->trunk_lcn_freq[state->edacs_cc_lcn-1] = lcnfreq;
|
||||
}
|
||||
//if using rtl input, we can ask for the current frequency tuned
|
||||
if (opts->audio_in_type == 3)
|
||||
{
|
||||
lcnfreq = (long int)opts->rtlsdr_center_freq;
|
||||
if (lcnfreq != 0) state->trunk_lcn_freq[state->edacs_cc_lcn-1] = lcnfreq;
|
||||
}
|
||||
}
|
||||
|
||||
//set trunking cc here so we know where to come back to
|
||||
if (opts->p25_trunk == 1 && state->trunk_lcn_freq[state->edacs_cc_lcn-1] != 0)
|
||||
{
|
||||
state->p25_cc_freq = state->trunk_lcn_freq[state->edacs_cc_lcn-1]; //index starts at zero, lcn's locally here start at 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//disabling kick command, data looks like its just FFFF, no actual values, can't verify accuracy
|
||||
// else if (mt2 == 0xB) //KICK LISTING for EA?? Unverified, but probably observed in Unitrunker way back when.
|
||||
// {
|
||||
// int kicked = (fr_4t & 0xFFFFF000) >> 12;
|
||||
// fprintf (stderr, " FR_1 [%010llX]", fr_1t);
|
||||
// fprintf (stderr, " FR_3 [%010llX]", fr_3);
|
||||
// fprintf (stderr, " FR_4 [%010llX]", fr_4t);
|
||||
// fprintf (stderr, " FR_6 [%010llX]", fr_6);
|
||||
// fprintf (stderr, " %08d REG/DEREG/AUTH?", kicked);
|
||||
// }
|
||||
// else //print frames for debug/analysis
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, " FR_1 [%010llX]", fr_1t);
|
||||
fprintf (stderr, " FR_4 [%010llX]", fr_4t);
|
||||
}
|
||||
|
||||
}
|
||||
//disabling kick command, data looks like its just FFFF, no actual values, can't verify accuracy
|
||||
// else if (mt1 == 0x1F && mt2 == 0xB) //KICK LISTING for EA?? Unverified, but probably observed in Unitrunker way back when.
|
||||
// {
|
||||
// int kicked = (fr_4t & 0xFFFFF000) >> 12;
|
||||
// fprintf (stderr, " FR_1 [%010llX]", fr_1t);
|
||||
// fprintf (stderr, " FR_3 [%010llX]", fr_3);
|
||||
// fprintf (stderr, " FR_4 [%010llX]", fr_4t);
|
||||
// fprintf (stderr, " FR_6 [%010llX]", fr_6);
|
||||
// fprintf (stderr, " Kick Command?");
|
||||
// }
|
||||
|
||||
//Voice Call Grant Update
|
||||
// mt1 0x12 is analog group voice call, 0x3 is Digital group voice call, 0x2 Group Data Channel, 0x1 TDMA call
|
||||
else if ((mt1 >= 0x1 && mt1 <= 0x3) || mt1 == 0x12)
|
||||
|
|
@ -621,6 +655,13 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " Group [%05d] Source [%08d] LCN[%02d]", group, source, lcn);
|
||||
|
||||
if (mt1 == 0x1) fprintf (stderr, " TDMA Call"); //never observed, wonder if any EDACS systems ever carried a TDMA signal (X2-TDMA?)
|
||||
else if (mt1 == 0x2) fprintf (stderr, " Group Data Call"); //Never Seen this one before
|
||||
else if (mt1 == 0x3) fprintf (stderr, " Digital Call"); //ProVoice, this is what we always get on SLERS EA
|
||||
else if (mt1 == 0x12) fprintf (stderr, " Analog Call"); //analog, to at least log that we recognize it
|
||||
else fprintf (stderr, " Unknown Type");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
char mode[8]; //allow, block, digital enc
|
||||
sprintf (mode, "%s", "");
|
||||
|
||||
|
|
@ -642,16 +683,10 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
if (state->tg_hold != 0 && state->tg_hold != group) sprintf (mode, "%s", "B");
|
||||
if (state->tg_hold != 0 && state->tg_hold == group) sprintf (mode, "%s", "A");
|
||||
|
||||
if (mt1 == 0x1) fprintf (stderr, " TDMA Call"); //never observed, wonder if any EDACS systems ever carried a TDMA signal (X2-TDMA?)
|
||||
if (mt1 == 0x2) fprintf (stderr, " Group Data Call"); //Never Seen this one before
|
||||
if (mt1 == 0x3) fprintf (stderr, " Digital Call"); //ProVoice, this is what we always get on SLERS EA
|
||||
if (mt1 == 0x12) fprintf (stderr, " Analog Call"); //analog, to at least log that we recognize it
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//this is working now with the new import setup
|
||||
if (opts->trunk_tune_group_calls == 1 && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
||||
{
|
||||
if (lcn > 0 && lcn < 26 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
||||
if (lcn > 0 && lcn < 26 && state->edacs_cc_lcn != 0 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
||||
{
|
||||
//openwav file and do per call right here, should probably check as well to make sure we have a valid trunking method active (rigctl, rtl)
|
||||
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
||||
|
|
@ -708,26 +743,31 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " I-Call Target [%08d] Source [%08d] LCN[%02d]", target, source, lcn);
|
||||
|
||||
//mt2 is 0x8 or 0xC when grant is first given, then 0xA or 0xE when call is in progress
|
||||
if (mt2 == 0x8 || mt2 == 0xA) fprintf (stderr, " Analog Call");
|
||||
else if (mt2 == 0xC || mt2 == 0xE) fprintf (stderr, " Digital Call");
|
||||
else fprintf (stderr, " Unknown Type");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
char mode[8]; //allow, block, digital enc
|
||||
sprintf (mode, "%s", "");
|
||||
|
||||
//if we don't know what type of call it is, then write 'B' to mode for block - no point trying to tune to it
|
||||
if (mt2 != 0x8 && mt2 != 0xA && mt2 != 0xC && mt2 != 0xE) sprintf (mode, "%s", "B");
|
||||
|
||||
//if we are using allow/whitelist mode, then write 'B' to mode for block - no allow/whitelist support for i-calls
|
||||
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
|
||||
|
||||
if (mt2 == 0xA) fprintf (stderr, " Analog Call");
|
||||
if (mt2 == 0xE) fprintf (stderr, " Digital Call");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//this is working now with the new import setup
|
||||
if (opts->trunk_tune_private_calls == 1 && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
||||
{
|
||||
if (lcn > 0 && lcn < 26 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
||||
if (lcn > 0 && lcn < 26 && state->edacs_cc_lcn != 0 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
||||
{
|
||||
//openwav file and do per call right here, should probably check as well to make sure we have a valid trunking method active (rigctl, rtl)
|
||||
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
||||
{
|
||||
sprintf (opts->wav_out_file, "./WAV/%s %s EDACS Site %lld TGT %d SRC %d.wav", getDateE(), timestr, state->edacs_site_id, target, source);
|
||||
if (mt2 == 0xE) //digital
|
||||
sprintf (opts->wav_out_file, "./WAV/%s %s EDACS Site %lld TGT %d SRC %d I-Call.wav", getDateE(), timestr, state->edacs_site_id, target, source);
|
||||
if (mt2 == 0xC || mt2 == 0xE) //digital
|
||||
openWavOutFile (opts, state);
|
||||
else //analog
|
||||
openWavOutFile48k (opts, state); //
|
||||
|
|
@ -741,7 +781,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
//
|
||||
if (mt2 == 0xA) //analog
|
||||
if (mt2 == 0x8 || mt2 == 0xA) //analog
|
||||
edacs_analog(opts, state, target, lcn);
|
||||
}
|
||||
|
||||
|
|
@ -765,7 +805,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
{
|
||||
int group = (fr_1t & 0xFFFF000) >> 12;
|
||||
int source = (fr_4t & 0xFFFFF000) >> 12;
|
||||
fprintf (stderr, " Login Group [%08d] Source [%08d]", group, source);
|
||||
fprintf (stderr, " Login Group [%05d] Source [%08d]", group, source);
|
||||
}
|
||||
else //print frames for debug/analysis
|
||||
{
|
||||
|
|
@ -828,7 +868,6 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
//voice call assignment
|
||||
else if (command == 0xEE || command == 0xEF)
|
||||
{
|
||||
lcn = (fr_1t & 0x3E0000000) >> 29;
|
||||
|
||||
if (lcn > state->edacs_lcn_count && lcn < 26)
|
||||
{
|
||||
|
|
@ -1012,4 +1051,4 @@ void eot_cc(dsd_opts * opts, dsd_state * state)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue