DMR LRRP and T3 Site Id Work;

This commit is contained in:
lwvmobile 2022-12-18 21:52:59 -05:00
parent 4946897914
commit fa4e84bc77
5 changed files with 128 additions and 30 deletions

View File

@ -162,7 +162,7 @@ Trunking Note1: All samples above can also be run with the RTL input method and
Trunking Note2: CQPSK Phase 1 and Phase 2 Systems are subceptible to LSM distortion issues, but seem to do okay, but require really good signal. Some CRC issues still occur with Phase 2 TDMA LCCH Mac Signal that can affect reliability, I believe this issue is ultimately caused by the PSK demodulation inside of FME. I also don't believe this will work on 8-level PSK, but I cannot determine that at the moment. Update: I have improved the LCCH Mac Signal decoding my increasing the QPSK decision point buffers to their maximum values.
Trunking Note3: DMR Trunking has been coded, and some testing and tweaks have been carried out. Cap+, Con+, and TIII systems seem to do well with trunking now. Placing the frequency for the control channel at channel map 0 in your channel_map.csv file is not required now if using RIGCTL, RIGCTL can poll the VFO for the current frequency if it believes its on a control channel, but using channel 0 as the control channel will be required when using the rtl dongle. If you need to map out your channels for TIII, you can observe the console output and look for channel numbers. For conveniece I have included the DSDPlus channel numbering (as best as I can figure it) into the console print so it will make it easier for users from DSDPlus to map frequencies into the channel_map.csv file. Make sure your channel numbers are the Cd (channel decimal) values from the log, and not the C+ (dsdplus) values.
Trunking Note3: DMR Trunking has been coded, and some testing and tweaks have been carried out. Cap+, Con+, and TIII systems seem to do well with trunking now. Placing the frequency for the control channel at channel map 0 in your channel_map.csv file is not required now if using RIGCTL, RIGCTL can poll the VFO for the current frequency if it believes its on a control channel, but using channel 0 as the control channel will be required when using the rtl dongle. If you need to map out your channels for TIII, you can observe the console output and look for channel numbers. For conveniece I have included the DSDPlus channel numbering (as best as I can figure it) into the console print so it will make it easier for users from DSDPlus to map frequencies into the channel_map.csv file. Make sure your channel numbers are the Cd (channel decimal) values from the log, and not the C+ (dsdplus) values. Notice: TIII Site ID value needs work to determine proper DMRLA values for system area and sub area.
```
Talkgroup Voice Channel Grant (TV_GRANT) - Logical

View File

@ -223,8 +223,22 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
uint8_t model = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 2);
uint16_t net = 0;
uint16_t site = 0;
//DMR Location Area - DMRLA
uint16_t sys_area = 0;
uint16_t sub_area = 0;
uint16_t sub_mask = 0x1;
//tiny n 1-3; small 1-5; large 1-8; huge 1-10
uint16_t n = 1; //The minimum value of DMRLA is normally ≥ 1, 0 is reserved
//TODO: Add logic to set n and sub_mask values for DMRLA
char model_str[8];
char par_str[8]; //category A, B, AB, or reserved
sprintf (model_str, "%s", " ");
sprintf (par_str, "%s", "Res");
if (model == 0) //Tiny
{
net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 9);
@ -250,13 +264,17 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
sprintf (model_str, "%s", "Huge");
}
uint8_t par = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[54], 2);
uint8_t par = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[54], 2);
if (par == 1) sprintf (par_str, "%s", "A ");
if (par == 2) sprintf (par_str, "%s", "B ");
if (par == 3) sprintf (par_str, "%s", "AB");
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
fprintf (stderr, " C_ALOHA_SYS_PARMS - %s - Net ID: %d Site ID: %d Par: %d \n Reg Req: %d V: %d MS: %d", model_str, net+1, site+1, par+1, regreq, version, target);
fprintf (stderr, " C_ALOHA_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d Cat: %s\n Reg Req: %d V: %d Mask: %02X MS: %d", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, par_str, regreq, version, mask, target);
//add string for ncurses terminal display
sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, site+1, par+1);
sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1 );
//if using rigctl we can set an unknown cc frequency by polling rigctl for the current frequency
if (opts->use_rigctl == 1 && state->p25_cc_freq == 0) //if not set from channel map 0
@ -272,14 +290,13 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
}
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16);
//nullify any previous branding sub (bugfix for naughty assignments or system type switching)
//nullify any previous branding sub (bugfix for bad assignments or system type switching)
sprintf(state->dmr_branding_sub, "%s", "");
//debug print
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16);
//fprintf (stderr, "\n SYSCODE: %016b", syscode);
//fprintf (stderr, " Sys ID Code: [%04X]", sysidcode);
//fprintf (stderr, "\n SYSCODE: %04X", syscode);
}
//P_CLEAR
@ -354,8 +371,24 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
uint8_t model = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 2);
uint16_t net = 0;
uint16_t site = 0;
//DMR Location Area - DMRLA
uint16_t sys_area = 0;
uint16_t sub_area = 0;
uint16_t sub_mask = 0x1;
//tiny n 1-3; small 1-5; large 1-8; huge 1-10
uint16_t n = 1; //The minimum value of DMRLA is normally ≥ 1, 0 is reserved
//TODO: Add logic to set n and sub_mask values for DMRLA
//channel number from Broadcast Parms 2
uint16_t lpchannum = 0;
char model_str[8];
char par_str[8]; //category A, B, AB, or reserved
sprintf (model_str, "%s", " ");
sprintf (par_str, "%s", "Res");
if (model == 0) //Tiny
{
@ -382,18 +415,26 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
sprintf (model_str, "%s", "Huge");
}
uint8_t par = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[54], 2);
uint8_t par = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[54], 2);
if (par == 1) sprintf (par_str, "%s", "A ");
if (par == 2) sprintf (par_str, "%s", "B ");
if (par == 3) sprintf (par_str, "%s", "AB");
uint32_t parms2 = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
lpchannum = parms2 & 0xFFF; //7.2.19.7, for DSDPlus, this value is (lpchannum << 1) + 1;
fprintf (stderr, "\n");
fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d Par: %d ", model_str, net+1, site+1, par+1);
fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d Cat: %s Cd: %d C+: %d", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, par_str, lpchannum, (lpchannum << 1)+1 );
//add string for ncurses terminal display, if not adjacent site info
if (a_type != 6) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1);
//nullify any previous branding sub (bugfix for bad assignments or system type switching)
sprintf(state->dmr_branding_sub, "%s", "");
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16);
//fprintf (stderr, "\n SYSCODE: %016b", syscode);
//add string for ncurses terminal display - This may set adjacent site info, so just do it out of Aloha
// sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, site+1, par+1);
//nullify any previous branding sub (bugfix for naughty assignments or system type switching)
sprintf(state->dmr_branding_sub, "%s", "");
//fprintf (stderr, "\n SYSCODE: %04X", syscode);
}
@ -494,6 +535,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
state->dmr_mfid = 0x10;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
fprintf (stderr, "%s", KNRM);
//don't tune if currently a vc on the current channel
@ -567,6 +612,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
state->dmr_mfid = 0x06;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf(state->dmr_branding_sub, "Con+ ");
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
}
if (csbk_o == 0x03)
@ -585,6 +634,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf(state->dmr_branding_sub, "Con+ ");
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
//if using rigctl we can set an unknown cc frequency by polling rigctl for the current frequency
if (opts->use_rigctl == 1 && state->p25_cc_freq == 0) //if not set from channel map 0
{
@ -667,6 +719,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
state->dmr_mfid = 0x06;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf(state->dmr_branding_sub, "Con+ ");
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
}
if (csbk_o == 0x0C)
@ -683,6 +738,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
state->dmr_mfid = 0x06;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf(state->dmr_branding_sub, "Con+ ");
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
}
if (csbk_o == 0x11)
@ -694,6 +752,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
state->dmr_mfid = 0x06;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf(state->dmr_branding_sub, "Con+ ");
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
}
if (csbk_o == 0x12)
@ -705,6 +766,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
state->dmr_mfid = 0x06;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf(state->dmr_branding_sub, "Con+ ");
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
}
if (csbk_o == 0x18)
@ -716,6 +780,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
state->dmr_mfid = 0x06;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf(state->dmr_branding_sub, "Con+ ");
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
}
fprintf (stderr, "%s", KNRM);

View File

@ -412,6 +412,15 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
uint8_t ts1_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 8); //ts1 address hash (crc8) //361-1 B.3.7
uint8_t ts2_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 8); //ts2 address hash (crc8) //361-1 B.3.7
//DMR Location Area - DMRLA - should probably be state variables so we can use this in both slc and csbk
uint16_t sys_area = 0;
uint16_t sub_area = 0;
uint16_t sub_mask = 0x1;
//tiny n 1-3; small 1-5; large 1-8; huge 1-10
uint16_t n = 1; //The minimum value of DMRLA is normally ≥ 1, 0 is reserved
//TODO: Add logic to set n and sub_mask values for DMRLA
//Sys_Parms
if (slco == 0x2 || slco == 0x3)
{
@ -453,11 +462,11 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
if (slco == 0x2) //C_SYS_Parms
{
fprintf (stderr, " C_SYS_PARMS - %s - Net ID: %d Site ID: %d - Reg Req: %d - CSC: %d ", model_str, net+1, site+1, reg, csc);
fprintf (stderr, " C_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Reg Req: %d - CSC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg, csc);
//add string for ncurses terminal display
sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1 );
//disabling so we can show the par information from the CSBK
//add string for ncurses terminal display - no par since slc doesn't carrry that value
// sprintf (state->dmr_site_parms, "TIII - %s N%d-S%d ", model_str, net, site);
//if using rigctl we can set an unknown cc frequency by polling rigctl for the current frequency
if (opts->use_rigctl == 1 && state->p25_cc_freq == 0) //if not set from channel map 0
@ -471,13 +480,12 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
}
else if (slco == 0x3) //P_SYS_Parms
{
fprintf (stderr, " P_SYS_PARMS - %s - Net ID: %d Site ID: %d - Comp Ch: %d ", model_str, net+1, site+1, reg);
fprintf (stderr, " P_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Comp CC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg);
//only asssign below if the field is empty, the CSBK version on CC will carry par
//add string for ncurses terminal display - no par since slc doesn't carrry that value
if((strncmp(state->dmr_site_parms, "", 3) == 0)) sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net+1, site+1);
//add string for ncurses terminal display
sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1 );
//nullify any previous branding sub (bugfix for naughty assignments or system type switching)
//nullify any previous branding sub (bugfix for bad assignments or system type switching)
sprintf(state->dmr_branding_sub, "%s", "");
}
else if (slco == 0x0) //null
@ -490,7 +498,10 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf (state->dmr_branding_sub, "%s", "Con+ ");
fprintf (stderr, " SLCO Connect Plus Voice Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
sprintf (state->dmr_site_parms, "N%d - S%d ", con_netid, con_siteid);
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
}
else if (slco == 0xA)
@ -499,13 +510,16 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf (state->dmr_branding_sub, "%s", "Con+ ");
fprintf (stderr, " SLCO Connect Plus Control Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
sprintf (state->dmr_site_parms, "N%d - S%d ", con_netid, con_siteid);
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
//if using rigctl we can set an unknown cc frequency by polling rigctl for the current frequency
if (opts->use_rigctl == 1 && state->p25_cc_freq == 0) //if not set from channel map 0
{
ccfreq = GetCurrentFreq (opts->rigctl_sockfd);
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
}
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
}
else if (slco == 0xF)
@ -520,6 +534,9 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
{
state->p25_cc_freq = state->trunk_chan_map[restchannel];
}
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
}
else fprintf (stderr, " SLCO Unknown - %d ", slco);

View File

@ -102,11 +102,16 @@ uint8_t dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t
uint8_t report = 0;
uint8_t pot_report = 0; //potential report by finding 0x0D and backtracking a few bytes
uint8_t is_p_head = 0;
//shim for getting LRRP out of some prop head data blocks
if (state->data_p_head[slot] == 1)
{
if (DMR_PDU[1] != 0x10) goto LRRP_END; //check to see if FID is 0x10
i = 0;
message_len = blocks * block_len;
source = state->dmr_lrrp_source[state->currentslot];
is_p_head = 1;
}
else i = 12;
@ -183,7 +188,8 @@ uint8_t dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t
lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
rad = (DMR_PDU[i+9] << 8) + DMR_PDU[i+10];
i += 10; //double check
lrrp_confidence++;
if (lat > 0 && lon > 0) lrrp_confidence++; //would be better to set by absolute boundary (180 and 90?)
else lat = 0;
}
break;
@ -223,7 +229,8 @@ uint8_t dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t
lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
alt = DMR_PDU[i+9];
i += 9; //check
lrrp_confidence++;
if (lat > 0 && lon > 0) lrrp_confidence++; //would be better to set by absolute boundary (180 and 90?)
else lat = 0;
}
break;
case 0x36: //protocol-version
@ -266,7 +273,7 @@ uint8_t dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "\n LRRP Confidence: %d - Message Len: %d Octets", lrrp_confidence, message_len);
if (lrrp_confidence >= 3) //find the sweet magical number
if (lrrp_confidence >= 4) //find the sweet magical number
{
//now we can open our lrrp file and write to it as well
FILE * pFile; //file pointer
@ -398,6 +405,8 @@ uint8_t dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t
// fprintf (stderr, "\n LRRP Confidence: %d - Message Len: %d Octets", lrrp_confidence, message_len);
// }
LRRP_END:
fprintf (stderr, "%s", KNRM);

View File

@ -2433,6 +2433,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if(state->dmrburstL == 16) //only during call
{
attron(COLOR_PAIR(4));
//Embedded GPS (not LRRP)
printw ("%s ", state->dmr_embedded_gps[0]);
@ -2455,6 +2457,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//LRRP
if(state->dmrburstL != 16) //only during data
{
attron(COLOR_PAIR(4));
printw ("%s", state->dmr_lrrp_gps[0]);
}
@ -2618,6 +2621,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
//Embedded GPS (not LRRP)
attron(COLOR_PAIR(4));
printw ("%s ", state->dmr_embedded_gps[1]);
//Embedded Talker Alias Blocks
@ -2640,6 +2644,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//LRRP
if(state->dmrburstR != 16) //only during data
{
attron(COLOR_PAIR(4));
printw ("%s", state->dmr_lrrp_gps[1]);
}