20 Commits

Author SHA1 Message Date
lwvmobile
5c42c50a40 Version Naming Update; 2023-04-25 17:18:35 -04:00
lwvmobile
36399386c5 More NXDN/IDAS Tweaks and Fixes; #115 and #118 2023-04-25 16:00:16 -04:00
lwvmobile
8eee4cd699 NXDN Type-D Decoding/Trunking; NXDN Tweaks; #115 2023-04-23 19:52:36 -04:00
lwvmobile
1410e8bd81 Cap Plus Expansion; Minor DMR Tweaks; #116 2023-04-23 19:50:06 -04:00
lwvmobile
915375fb1c Initial NXDN Type D - 'IDAS' Support; #115 2023-04-13 18:20:58 -04:00
lwvmobile
52fff28dc4 NXDN Array Expansion and Message Tweaks; #113 2023-04-13 11:00:37 -04:00
lwvmobile
bd035622b8 No Color Cmake Build Option #114 2023-04-13 11:00:00 -04:00
lwvmobile
44163710f9 More XPT Work; #110 2023-04-12 18:12:10 -04:00
lwvmobile
44b1ccdeae Hashed DMR TG Multi Key Loading Fix; #112 2023-04-12 13:10:13 -04:00
lwvmobile
34113cb782 housekeeping; 2023-04-09 14:30:05 -04:00
lwvmobile
2a336a9275 Hytera XPT WIP #110 2023-04-08 19:15:33 -04:00
lwvmobile
5c08a9193c Yet Another Cmake Warning Fix #107 2023-03-28 23:33:20 -04:00
lwvmobile
2cae7f9c18 NXDN -- DFA Base Freq Fix; ADJ_SITE_INFO; #106 2023-03-28 17:30:02 -04:00
lwvmobile
e056c97d9d Issue #105 - Make Work with Named Pipe (FIFO) 2023-03-22 20:07:02 -04:00
lwvmobile
dc49e0d08b NXDN DFA Support; 2023-03-22 20:00:41 -04:00
lwvmobile
b639f6af28 Fix Cmake Warnings; 2023-03-21 22:42:09 -04:00
lwvmobile
6b45c4ba9b Issue #105 Segfault Bugfix; 2023-03-21 21:09:45 -04:00
lwvmobile
2062502a59 P2 - TDMA-CC Tuning Bugfix and callstring tweak; 2023-03-21 20:58:44 -04:00
lwvmobile
a490d9ead2 Merge pull request #104 from lwvmobile/lite
NXDN48/96 Tweak;
2023-03-12 15:55:12 -04:00
lwvmobile
c73832ac2c NXDN48/96 Tweak; 2023-03-12 15:42:49 -04:00
20 changed files with 2172 additions and 635 deletions

View File

@@ -1,11 +1,24 @@
#Ubuntu 18.04 uses 3.10.2 currently -- almost EOL
#Ubuntu 20.04 uses 3.16.3
#Ubuntu 22.04 uses 3.22.1
#Arch currently on 3.26.1 -- new nag warning starts on this one, see below
#cmake_minimum_required() should be called prior to this top-level project()
#Cygwin currently using 3.23.2 (or newer)
cmake_minimum_required(VERSION 3.10.2)
project(dsd-fme-aero)
cmake_minimum_required(VERSION 2.8.11)
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
#Set curses to ncurses, and wide true for ascii
set(CURSES_NEED_NCURSES TRUE)
set(CURSES_NEED_WIDE TRUE)
#use cmake option -DCOLORS=OFF to disable color output
option(COLORS
"Build with Colors Enabled" ON)
if (COLORS)
add_definitions(-DPRETTY_COLORS)
endif ()
include(git_revision)
git_describe(GIT_TAG)
@@ -14,7 +27,7 @@ find_package(MBE REQUIRED)
find_package(ITPP REQUIRED)
find_package(RTLSDR)
find_package(Curses REQUIRED)
find_package(PULSEAUDIO REQUIRED)
find_package(PulseAudio REQUIRED)
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR})
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${CURSES_LIBRARY})

Binary file not shown.

View File

@@ -17,7 +17,8 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
//pretty pretty colors
//defined by CMakeLists.txt -- Disable by using cmake -DCOLORS=OFF ..
#ifdef PRETTY_COLORS
#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
@@ -26,6 +27,16 @@
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"
#else
#define KNRM ""
#define KRED ""
#define KGRN ""
#define KYEL ""
#define KBLU ""
#define KMAG ""
#define KCYN ""
#define KWHT ""
#endif
#include "config.h"
#include <stdio.h>
@@ -540,7 +551,7 @@ typedef struct
//new stuff below here
uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot
uint8_t dmr_pdu_sf[2][288]; //unified pdu 'superframe' //[slot][byte]
uint8_t cap_plus_csbk_bits[12*8*8]; //CSBK Cap+ FL initial and appended block bit storage
uint8_t cap_plus_csbk_bits[2][12*8*8]; //CSBK Cap+ FL initial and appended block bit storage, by slot
uint8_t cap_plus_block_num; //received block number storage
uint8_t data_block_crc_valid[2][25]; //flag each individual block as good crc on confirmed data
char dmr_embedded_signalling[2][7][48]; //embedded signalling 2 slots by 6 vc by 48 bits (replacing TS1SuperFrame.TimeSlotRawVoiceFrame.Sync structure)
@@ -654,13 +665,21 @@ typedef struct
uint8_t nxdn_sacch_frame_segcrc[4];
uint8_t nxdn_alias_block_number;
char nxdn_alias_block_segment[4][4][8];
//site/srv/cch info
char nxdn_location_category[14];
uint32_t nxdn_location_sys_code;
uint16_t nxdn_location_site_code;
//channel access information
uint8_t nxdn_rcn;
uint8_t nxdn_base_freq;
uint8_t nxdn_step;
uint8_t nxdn_bw;
//multi-key array
unsigned long long int rkey_array[0xFFFF];
int keyloader; //let us know the keyloader is active
//dmr late entry mi
uint64_t late_entry_mi_fragment[2][7][3];
@@ -846,10 +865,15 @@ void ncursesClose ();
//new NXDN Functions start here!
void nxdn_frame (dsd_opts * opts, dsd_state * state);
void nxdn_descramble (uint8_t dibits[], int len);
//nxdn deinterleaving/depuncturing functions
void nxdn_deperm_facch (dsd_opts * opts, dsd_state * state, uint8_t bits[144]);
void nxdn_deperm_sacch (dsd_opts * opts, dsd_state * state, uint8_t bits[60]);
void nxdn_deperm_cac (dsd_opts * opts, dsd_state * state, uint8_t bits[300]);
void nxdn_deperm_facch2_udch (dsd_opts * opts, dsd_state * state, uint8_t bits[348]);
void nxdn_deperm_facch2_udch (dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type);
//type-d 'idas' deinterleaving/depuncturing functions
void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint8_t direction);
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type);
//end
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType);
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]);
@@ -859,6 +883,7 @@ static uint8_t crc6(const uint8_t buf[], int len);
static uint16_t crc12f(const uint8_t buf[], int len);
static uint16_t crc15(const uint8_t buf[], int len);
static uint16_t crc16cac(const uint8_t buf[], int len);
static uint8_t crc7_scch(uint8_t bits[], int len); //converted from op25 crc6
/* NXDN Convolution functions */
void CNXDNConvolution_start(void);
@@ -881,7 +906,9 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
void NXDN_decode_cch_info(dsd_opts * opts, dsd_state * state, uint8_t * Message);
void NXDN_decode_srv_info(dsd_opts * opts, dsd_state * state, uint8_t * Message);
void NXDN_decode_site_info(dsd_opts * opts, dsd_state * state, uint8_t * Message);
void nxdn_location_id_handler (dsd_state * state, uint32_t location_id);
void NXDN_decode_adj_site(dsd_opts * opts, dsd_state * state, uint8_t * Message);
//Type-D SCCH Message Decoder
void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uint8_t direction);
void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state);

View File

@@ -1,12 +0,0 @@
sudo cp tone8.wav /usr/share/
sudo cp tone24.wav /usr/share/
sudo cp tone48.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
sudo chmod 777 /usr/share/tone48.wav
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig

View File

@@ -34,6 +34,35 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
uint32_t target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[16], 24); //destination llid
uint32_t source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[40], 24); //source llid
//extra tgt/src handling for XPT
uint8_t target_hash[24];
uint8_t tg_hash = 0;
uint8_t is_xpt = 0;
//set flag if XPT
if (strcmp (state->dmr_branding_sub, "XPT ") == 0) is_xpt = 1;
//truncate tgt/src to 16-bit values if XPT
if (is_xpt == 1)
{
target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[24], 16); //destination llid
source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 16); //source llid
if (gi == 0)
{
for (int i = 0; i < 16; i++) target_hash[i] = dheader_bits[24+i];
tg_hash = crc8 (target_hash, 16);
}
}
uint8_t is_cap = 0;
if (strcmp (state->dmr_branding_sub, "Cap+ ") == 0) is_cap = 1;
if (is_cap)
{
//truncate tg on group? or just on private/individual data?
if (gi == 0) target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[24], 16);
source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 16);
}
//store source for dmr pdu packet handling (lrrp) when not available in completed message
if (dpf != 15) state->dmr_lrrp_source[slot] = source;
@@ -97,8 +126,8 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
fprintf (stderr, "\n");
fprintf (stderr, " Slot %d Data Header - ", slot+1);
if (gi == 1 && dpf != 15) fprintf(stderr, "GROUP - ");
if (gi == 0 && dpf != 15) fprintf(stderr, "INDIV - ");
if (gi == 1 && dpf != 15) fprintf(stderr, "Group - ");
if (gi == 0 && dpf != 15) fprintf(stderr, "Indiv - ");
if (dpf == 0) fprintf (stderr, "Unified Data Transport (UDT) ");
else if (dpf == 1) fprintf (stderr, "Response Packet ");
@@ -112,6 +141,9 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
if (a == 1 && dpf != 15) fprintf(stderr, "- Response Requested ");
if (dpf != 15) fprintf (stderr, "- Source: %d Target: %d ", source, target);
//include the hash value if this is an XPT and if its IND data
if (dpf != 15 && is_xpt == 1 && gi == 0) fprintf (stderr, "Hash: %d ", tg_hash);
//sap string handling
if (dpf == 15) sap = p_sap;

View File

@@ -379,7 +379,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
cach_err = dmr_cach (opts, state, cachdata);
fprintf (stderr, "\n");
if (opts->payload == 0) fprintf (stderr, "\n");
// run alg refresh after vc6 ambe processing
if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state);
@@ -724,7 +724,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
cach_err = dmr_cach (opts, state, cachdata);
fprintf (stderr, "\n");
if (opts->payload == 0) fprintf (stderr, "\n");
//update voice sync time for trunking purposes (particularly Con+)
if (opts->p25_is_tuned == 1) state->last_vc_sync_time = time(NULL);

View File

@@ -615,13 +615,44 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
uint8_t target_hash[24];
uint8_t tg_hash = 0;
if (gi == 0) fprintf (stderr, "Individual ");
else fprintf (stderr, "Group ");
if (content == 0) fprintf (stderr, "CSBK - ");
else fprintf (stderr, "Data - ");
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
// check to see if this is XPT
if (strcmp (state->dmr_branding_sub, "XPT ") == 0)
{
//get 16-bit truncated target and source ids
target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16); //40, or 32?
source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[64], 16); //56, or 64?
//check to see if this is indiv data (private) then we will need to report the hash value as well
if (gi == 0)
{
//the crc8 hash is the value represented in the Hytera XPT Site Status CSBK when dealing with indiv data
for (int i = 0; i < 16; i++) target_hash[i] = cs_pdu_bits[40+i];
tg_hash = crc8 (target_hash, 16);
fprintf (stderr, "Source: %d - Target: %d - Hash: %d ", source, target, tg_hash);
}
else fprintf (stderr, "Source: %d - Target: %d ", source, target);
}
// check to see if this is Cap+
else if (strcmp (state->dmr_branding_sub, "Cap+ ") == 0)
{
//truncate tg on group? or just on private/individual data?
if (gi == 0) target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16);
source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[64], 16);
int rest = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[60], 4);
fprintf (stderr, "Source: %d - Target: %d - Rest Channel: %d", source, target, rest);
}
else fprintf (stderr, "Source: %d - Target: %d ", source, target);
}
//end tier 2 csbks
@@ -656,7 +687,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
}
//Cap+ Neighbors
//Cap+ Adjacent Sites
if (csbk_o == 0x3B)
{
@@ -664,10 +695,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
fprintf (stderr, "\n");
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Capacity Plus Neighbor List ");
fprintf (stderr, " Capacity Plus Adjacent Sites\n ");
uint8_t nl[6]; //neighbors numerical value
uint8_t nr[6]; //neighbors current rest channel
uint8_t nl[6]; //adjacet site numerical value
uint8_t nr[6]; //adjacent site current rest channel
memset (nl, 0, sizeof (nl));
memset (nr, 0, sizeof (nr));
@@ -675,12 +706,12 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
{
nl[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[32+(i*8)], 4);
nr[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[36+(i*8)], 4);
if (nl[i]) fprintf (stderr, "S: %d R(%d) ", nl[i], nr[i]);
if (nl[i]) fprintf (stderr, "Site: %d Rest: %d; ", nl[i], nr[i]);
}
}
//Cap+ Channel Status
//Cap+ Channel Status -- Expanded for up to 16 LSNs and private voice/data calls and dual slot csbk_bit storage
if (csbk_o == 0x3E)
{
@@ -690,11 +721,26 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
uint8_t fl = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 2);
uint8_t ts = cs_pdu_bits[18]; //timeslot this PDU occurs in
uint8_t res = cs_pdu_bits[19]; //unknown, always seems to be 0 -- could be used in larger Cap+? like a bank switch?
uint8_t res = cs_pdu_bits[19]; //unknown or unused bit value
uint8_t rest_channel = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20], 4);
uint8_t group_tally = 0; //set this to the number of active group channels tallied
uint8_t group_tally = 0; //set this to the number of active channels tallied
uint8_t bank_one = 0;
uint8_t bank_two = 0;
uint8_t b2_start = 0;
uint8_t block_num = state->cap_plus_block_num;
uint8_t pdflag = 0;
uint8_t pdflag2 = 0;
uint16_t private_target = 0;
uint8_t pd_b2 = 0;
uint8_t start = 8;
uint8_t end = 8;
uint8_t fl_bytes = 0;
uint8_t ch[24]; //one bit per channel
uint8_t pch[24]; //private or data call channel bits
uint16_t tg = 0;
int i, j, k, x;
//tg and channel info for trunking purposes
uint16_t t_tg[24];
//sanity check
if (block_num > 6)
@@ -703,32 +749,22 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
block_num = 6;
}
uint8_t ch[8]; //one bit per channel
uint8_t pch[8]; //private or data call channel bits
uint8_t tg = 0;
int i, j, k;
//tg and channel info for trunking purposes
uint8_t t_tg[9];
//init some arrays
memset (t_tg, 0, sizeof(t_tg));
//initialize group ch and private/data channel bit arrays
for (i = 0; i < 8; i++)
{
ch[i] = 0;
pch[i] = 0;
}
memset (ch, 0, sizeof(ch));
memset (pch, 0, sizeof(pch));
//treating FL as a form of LCSS
if (fl == 2 || fl == 3) //initial or single block (fl2 or fl3)
{
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
for (i = 0; i < 10*8; i++) state->cap_plus_csbk_bits[i] = cs_pdu_bits[i];
//NOTE: this has been changed to store per slot
memset (state->cap_plus_csbk_bits[ts], 0, sizeof(state->cap_plus_csbk_bits[ts]));
for (i = 0; i < 10*8; i++) state->cap_plus_csbk_bits[ts][i] = cs_pdu_bits[i];
state->cap_plus_block_num = 0;
}
else //appended block (fl0) or final block (fl1)
else //appended block (fl 0) or final block (fl 1)
{
for (i = 0; i < 7*8; i++) state->cap_plus_csbk_bits[i+80+(7*8*block_num)] = cs_pdu_bits[i+24];
for (i = 0; i < 7*8; i++) state->cap_plus_csbk_bits[ts][i+80+(7*8*block_num)] = cs_pdu_bits[i+24];
block_num++;
state->cap_plus_block_num++;
}
@@ -750,94 +786,169 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
if (fl == 0) fprintf (stderr, " - Appended Block"); //have not yet observed a system use this fl value
if (fl == 1) fprintf (stderr, " - Final Block");
if (fl == 2) fprintf (stderr, " - Initial Block");
if (fl == 3) fprintf (stderr, " - Single Block"); //still considering a single, and not a final
if (fl == 3) fprintf (stderr, " - Single Block");
//look at each group channel bit -- run this PRIOR to checking private or data calls
//or else we will overwrite the ch bits we set below for private calls with zeroes
//these also seem to indicate data calls -- can't find a distinction of which is which
bank_one = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][24], 8);
for (int i = 0; i < 8; i++)
{
ch[i] = state->cap_plus_csbk_bits[i+24];
if (ch[i] == 1) group_tally++; //figure out where to start looking in the byte stream for the 0x80 flag
}
ch[i] = state->cap_plus_csbk_bits[ts][i+24];
if (ch[i] == 1) group_tally++; //figure out where to start looking in the byte stream for the 0next bank of calls
}
//check for private/data calls -- user will neeed to enable 'data' call tuning in order to tune them
uint8_t pdflag = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[40+(group_tally*8)], 8); //seems to be 0x80 (last block flag?) on samples I have
uint16_t private_target = 0;
//Expanded to cover larger systems up to 16 slots.
bank_two = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][32+(group_tally*8)], 8); //32
b2_start = group_tally;
if (bank_two)
{
for (int i = 0; i < 8; i++)
{
ch[i+8] = state->cap_plus_csbk_bits[ts][i+32+(b2_start*8)];
if (ch[i+8] == 1) group_tally++;
}
}
//first, check to see if we have a completed PDU
//check flag for appended private and/or data calls
pdflag = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][40+(group_tally*8)], 8);
//check for private activity on LSNs 1-8
if (fl == 1 || fl == 3)
{
//then check to see if this byte has a value, should be 0x80
//this bytes location seems to shift depending on level of activity
if (pdflag == 0x80) //now looking to see if any appended data was added
if (pdflag == 0x80)
{
k = 0; //= 0
fprintf (stderr, "\n");
fprintf (stderr, " F%X Private or Data Call", pdflag);
fprintf (stderr, " F%X Private or Data Call - ", pdflag);
for (int i = 0; i < 8; i++)
{
pch[i] = state->cap_plus_csbk_bits[i+48+(group_tally*8)];
pch[i] = state->cap_plus_csbk_bits[ts][i+48+(group_tally*8)];
if (pch[i] == 1)
{
fprintf (stderr, " Ch%d:", i+1);
private_target = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[56+(k*16)+(group_tally*8)], 16);
fprintf (stderr, " LSN %02d:", i+1);
private_target = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][56+(k*16)+(group_tally*8)], 16);
fprintf (stderr, " TGT %d;", private_target);
if (opts->trunk_tune_data_calls == 1) t_tg[i] = private_target; //set here for tuning allow/block
// if (opts->trunk_tune_data_calls == 1) t_tg[i] = private_target; //moved to below section
k++;
if (bank_one == 0) bank_one = 1; //flag on bank one if not already for private call listings
}
}
//save for starting point of the next private call bank
pd_b2 = k;
}
}
//end private/data call check on LSNs 1-8
//check flag for appended private and/or data calls -- flag two still needs work or testing, double checking, etc, disable if issues arise
pdflag2 = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][48+(group_tally*8)+(pd_b2*16)], 8);
//check for private activity on LSNs 9-16
if (fl == 1 || fl == 3)
{
//then check to see if this byte has a value, should be 0x80, could be other?
//this bytes location shifts depending on level of activity -- see banks above
if (pdflag2 == 0x80) //now looking to see if any appended data was added
{
k = 0;
fprintf (stderr, "\n");
fprintf (stderr, " F%X Private or Data Call - ", pdflag2);
for (int i = 0; i < 8; i++)
{
pch[i+8] = state->cap_plus_csbk_bits[ts][i+56+(group_tally*8)+(pd_b2*16)]; //48
if (pch[i+8] == 1)
{
fprintf (stderr, " LSN %02d:", i+1);
private_target = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][64+(k*16)+(group_tally*8)+(pd_b2*16)], 16); //64
fprintf (stderr, " TGT %d;", private_target);
// if (opts->trunk_tune_data_calls == 1) t_tg[i+8] = private_target; //moved to below section
k++;
if (bank_two == 0) bank_two = 1; //flag on bank one if not already for private call listings
}
}
}
}
//end private/data call check
//end private/data call check on LSNs 9-16
// if (fl != 2)
if (fl == 1 || fl == 3)
{
fprintf (stderr, "\n ");
k = 0;
for (i = 0; i < 8; i++)
x = 0;
//start position;
start = 8;
if (bank_one) start = 0;
else if (rest_channel < 8) start = 0;
//end position;
end = 8;
if (bank_two) end = 16;
else if (rest_channel > 8) end = 16;
//start parsing info and listing active LSNs
for (i = start; i < end; i++)
{
fprintf (stderr, "Ch%d: ", i+1);
//skip an additional k value per bank
if (i == 8) k++;
if (i == 4 || i == 12)
fprintf (stderr, "\n ");
if (i == 8 && start == 0 && end == 16)
fprintf (stderr, "\n ");
fprintf (stderr, "LSN %02d: ", i+1);
if (ch[i] == 1) //group voice channels
{
tg = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[k*8+32], 8);
if (tg != 0) fprintf (stderr, " %03d ", tg);
else fprintf (stderr, "Actv ");
//add values to trunking tg/channel potentials
t_tg[i] = tg;
if (tg != 0) k++;
tg = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][(k*8)+32], 8);
if (tg != 0) fprintf (stderr, "%5d; ", tg);
else fprintf (stderr, "Group; ");
//flag as available for tuning if group calls enabled
if (opts->trunk_tune_group_calls == 1) t_tg[i] = tg;
if (tg != 0) k++;
}
else if (pch[i] == 1) //private or data channels
{
fprintf (stderr, "P||D ");
//flag as available for tuning if enabled
if (opts->trunk_tune_data_calls == 1) ch[i] = 1;
tg = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][(group_tally*8)+(x*16)+56], 16);
if (tg != 0) fprintf (stderr, "%5d; ", tg);
else fprintf (stderr, " P||D; ");
//flag as available for tuning if data calls enabled
if (opts->trunk_tune_data_calls == 1) t_tg[i] = tg; //ch[i] = 1;
if (tg != 0) x++;
}
else if (i+1 == rest_channel) fprintf (stderr, "Rest ");
else fprintf (stderr, "Idle ");
else if (i+1 == rest_channel) fprintf (stderr, " Rest; ");
else fprintf (stderr, " Idle; ");
if (i == 3) fprintf (stderr, "\n ");
}
//debug ncurses terminal display -- LSNs 1-8
// sprintf (state->dmr_lrrp_gps[0], "CAP LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d;", 1, t_tg[0], 2, t_tg[1], 3, t_tg[2], 4, t_tg[3]);
// sprintf (state->dmr_lrrp_gps[1], "CAP LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d;", 5, t_tg[4], 6, t_tg[5], 7, t_tg[6], 8, t_tg[7]);
//debug ncurses terminal display -- LSNs 9-16
// sprintf (state->dmr_lrrp_gps[0], "CAP LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d;", 9, t_tg[8], 10, t_tg[9], 11, t_tg[10], 12, t_tg[11]);
// sprintf (state->dmr_lrrp_gps[1], "CAP LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d;", 13, t_tg[12], 14, t_tg[13], 15, t_tg[14], 16, t_tg[15]);
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)
//nullify any previous site_parm data
sprintf(state->dmr_site_parms, "%s", "");
fprintf (stderr, "%s", KNRM);
//Skip tuning group calls if group calls are disabled
if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
//Skip tuning group calls if group calls are disabled -- moved to individual switches in the parsing phase
// if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
//don't tune if vc on the current channel
if ( (time(NULL) - state->last_vc_sync_time > 2) )
{
for (j = 0; j < 8; j++) //go through the channels stored looking for active ones to tune to
for (j = start; j < end; j++) //go through the channels stored looking for active ones to tune to
{
char mode[8]; //allow, block, digital, enc, etc
@@ -857,6 +968,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
//without priority, this will tune the first one it finds (if group isn't blocked)
if (t_tg[j] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
{
//debug print for tuning verification
fprintf (stderr, "\n LSN/TG to tune to: %d - %d", j+1, t_tg[j]);
if (state->trunk_chan_map[j+1] != 0) //if we have a valid frequency
{
//RIGCTL
@@ -892,20 +1006,21 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
{
fprintf (stderr, "%s\n", KYEL);
fprintf (stderr, " CAP+ Multi Block PDU \n ");
uint8_t fl_bytes = 0;
fl_bytes = 0;
for (i = 0; i < (10+(block_num*7)); i++)
{
fl_bytes = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[i*8], 8);
fl_bytes = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][i*8], 8);
fprintf (stderr, "[%02X]", fl_bytes);
if (i == 17 || i == 35) fprintf (stderr, "\n ");
}
fprintf (stderr, "%s", KNRM);
}
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
memset (state->cap_plus_csbk_bits[ts], 0, sizeof(state->cap_plus_csbk_bits[ts]));
state->cap_plus_block_num = 0;
} //if (fl == 1 || fl == 3)
} //opcode == 0x3E
} //fid == 0x10
//Connect+ Section
@@ -952,14 +1067,14 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
//if using rigctl we can set an unknown or updated cc frequency
//by polling rigctl for the current frequency
if (opts->use_rigctl == 1 && opts->p25_is_tuned == 0) //&& state->p25_cc_freq == 0
if (opts->use_rigctl == 1 && opts->p25_is_tuned == 0)
{
ccfreq = GetCurrentFreq (opts->rigctl_sockfd);
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
}
//if using rtl input, we can ask for the current frequency tuned
if (opts->audio_in_type == 3 && opts->p25_is_tuned == 0) //&& state->p25_cc_freq == 0
if (opts->audio_in_type == 3 && opts->p25_is_tuned == 0)
{
ccfreq = (long int)opts->rtlsdr_center_freq;
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
@@ -1031,60 +1146,90 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
} //end Connect+
//Hytera XPT
//Hytera XPT -- Experimental, but values now seem very consistent and trunking is working on systems tested with
if (csbk_fid == 0x68)
{
//XPT Site Status -- Very Very Experimental, WIP, Don't be surprised by bad decodes or broken trunking
//XPT Site Status
if (csbk_o == 0x0A)
{
//initial line break
fprintf (stderr, "\n");
fprintf (stderr, "%s", KYEL);
uint8_t xpt_ch[6]; //one tg/call per timeslot
uint16_t tg = 0; //8-bit TG value or hash
uint8_t xpt_ch[6]; //one tg/call per LSN
uint16_t tg = 0; //8-bit TG value or TGT hash
int i, j;
//tg and channel info for trunking purposes
uint8_t t_tg[24];
uint8_t t_tg[6];
memset (t_tg, 0, sizeof(t_tg));
uint8_t xpt_seq = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[0], 2); //this replaces the CSBK lb and pf
uint8_t xpt_free = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 4); //free repeater channel
uint8_t xpt_free = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 4); //free repeater channel LCN
uint8_t xpt_bank = 0;
uint8_t xpt_lcn = 1;
if (xpt_seq) xpt_bank = xpt_seq*6;
//determine starting position of LCN value
if (xpt_seq == 1) xpt_lcn = 4;
if (xpt_seq == 2) xpt_lcn = 7;
//get 2-bit status values for each 6 channels (timeslots)
//determine xpt_bank value for LSN value/tuning
if (xpt_seq) xpt_bank = xpt_seq*6;
//get 2-bit status values for each 6 LSNs
for (i = 0; i < 6; i++) xpt_ch[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20+(i*2)], 2);
fprintf (stderr, " Hytera XPT Site Status - Free RPT: %d SN: %d\n ", xpt_free, xpt_seq);
fprintf (stderr, " Hytera XPT Site Status - Free LCN: %d SN: %d", xpt_free, xpt_seq);
//Print List of Channels and Activity
//Print List of LCN with LSN Activity
for (i = 0; i < 6; i++)
{
fprintf (stderr, "Ch%02d: ", i+xpt_bank+1); //(xpt_seq*6)
tg = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[i*8+32], 8);
//add LCN value for each LSN pair to help users differentiate between the two when seeing LCN on FLC
if (i == 0 || i == 2 || i == 4)
{
fprintf (stderr, "\n LCN %d - ", xpt_lcn);
xpt_lcn++;
}
//LSN value here is logical slot, in flco, we get the logical channel (which is the repeater, does not include the slot value)
fprintf (stderr, "LSN %02d: ", i+xpt_bank+1); //swapped out xpt_bank for all (xpt_seq*6) to simplify things
tg = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[i*8+32], 8);
fprintf (stderr, "ST-%X", xpt_ch[i]); //status bits value 0,1,2, or 3
if (tg != 0) fprintf (stderr, " %03d ", tg);
if (tg != 0) fprintf (stderr, " %03d; ", tg);
else
{
if (xpt_ch[i] == 3) fprintf (stderr, " Null "); //offline?, free? but also group call if the TG value is populated? Wut? Null should cover both cases...maybe
else if (xpt_ch[i] == 2) fprintf (stderr, " Priv "); //This seems to be used on both private data and private calls, but one or the other has a 0 TG value?
else if (xpt_ch[i] == 1) fprintf (stderr, " Unk "); //the 01 value has not been observed as of yet, group data?
else if (xpt_ch[i] == 0) fprintf (stderr, " Idle "); //Idle appears to always be a 0, or could indicate Group Data (including status CSBK and VLC/TLC)
if (xpt_ch[i] == 3) fprintf (stderr, " Null; "); //NULL on ST-3 indicates repeater is not active for the LSNs that would be covered by these bits
else if (xpt_ch[i] == 2) fprintf (stderr, " Priv; "); //This seems to be used on both private data and private voice calls, but occassionally has a 0 TGT value
else if (xpt_ch[i] == 1) fprintf (stderr, " Unk; "); //the 01 value has not been observed as of yet
else if (xpt_ch[i] == 0) fprintf (stderr, " Idle; "); //Idle
//if Priv/Unk occurs, add t_tg value to it for tuning purposes
if (xpt_ch[i] == 2)
{
if (opts->trunk_tune_private_calls == 1) t_tg[i] = 1;
}
//could cause erroneous tuning since we don't yet know what the unk value really is (never observed)
if (xpt_ch[i] == 1)
{
// if (opts->trunk_tune_data_calls == 1) t_tg[i] = 1; //disabled
}
}
if (i == 2) fprintf (stderr, "\n ");
// if (i == 2) fprintf (stderr, "\n ");
//add values to trunking tg/channel potentials
if (tg != 0) t_tg[i+(xpt_seq*6)] = tg;
if (tg != 0) t_tg[i+xpt_bank] = tg;
}
//debug ncurses terminal display
// sprintf (state->dmr_lrrp_gps[0], "XPT SN %d LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d;", xpt_seq, xpt_bank+1, t_tg[0], xpt_bank+2, t_tg[1], xpt_bank+3, t_tg[2]);
// sprintf (state->dmr_lrrp_gps[1], "XPT SN %d LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d;", xpt_seq, xpt_bank+4, t_tg[3], xpt_bank+5, t_tg[4], xpt_bank+6, t_tg[5]);
//add string for ncurses terminal display
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free);
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
//assign to cc freq to follow during no sync
long int ccfreq = 0;
@@ -1116,7 +1261,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
if (opts->trunk_tune_group_calls == 0) goto SKIPXPT;
//don't tune if vc on the current channel
if ( (time(NULL) - state->last_vc_sync_time > 2) )
if ( (time(NULL) - state->last_vc_sync_time) > 2 ) //parenthesis error fixed
{
for (j = 0; j < 6; j++) //go through the channels stored looking for active ones to tune to
{
@@ -1131,7 +1276,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
//and hope it doesn't clash with other normal TG values
for (int i = 0; i < state->group_tally; i++)
{
if (state->group_array[i].groupNumber == t_tg[j+(xpt_seq*6)])
if (state->group_array[i].groupNumber == t_tg[j+xpt_bank])
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
@@ -1139,16 +1284,22 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
}
//without priority, this will tune the first one it finds (if group isn't blocked)
if (t_tg[j+(xpt_seq*6)+1] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
if (t_tg[j+xpt_bank] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
{
if (state->trunk_chan_map[j+(xpt_seq*6)+1] != 0) //if we have a valid frequency
//debug print for tuning verification
fprintf (stderr, "\n LSN/TG to tune to: %d - %d", j+xpt_bank+1, t_tg[j+xpt_bank]);
if (state->trunk_chan_map[j+xpt_bank+1] != 0) //if we have a valid frequency
{
//RIGCTL
if (opts->use_rigctl == 1)
{
//debug
fprintf (stderr, " - Freq: %ld", state->trunk_chan_map[j+xpt_bank+1]);
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+(xpt_seq*6)+1]);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+(xpt_seq*6)+1];
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+xpt_bank+1]);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+xpt_bank+1];
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
j = 11; //break loop
@@ -1157,8 +1308,11 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
//rtl_udp
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, state->trunk_chan_map[j+(xpt_seq*6)+1]);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+(xpt_seq*6)+1];
//debug
fprintf (stderr, " - Freq: %ld", state->trunk_chan_map[j+xpt_bank+1]);
rtl_udp_tune (opts, state, state->trunk_chan_map[j+xpt_bank+1]);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+xpt_bank+1];
opts->p25_is_tuned = 1;
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
j = 11; //break loop
@@ -1174,20 +1328,17 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
sprintf (state->dmr_branding_sub, "XPT ");
//Trunking Note: My understanding is that XPT calls always start on the 'home' repeater, and then expand
//outward to the free repeaters, so its probably easiest for a user to load the frequencies in a csv file
//and let FME scan through them as opposed to actively trunking, it will spend most of the time on the home repeater
//and if calls occur on the home repeater, it'll be too busy with those to go to the free repeater
//DSD-FME doesn't have any sort of TG priority, so its first come first served, just block or allow
//Notes: I had a few issues to fix in this CSBK, but it does appear that this is trunking on a few small systems now,
//albeit a very quiet systems that makes it difficult to know for certain if every aspect is working correctly
//Additional Notes: I've set XPT to set a CC frequency to whichever frequency its tuned to currently and getting
//Notes: I've set XPT to set a CC frequency to whichever frequency its tuned to currently and getting
//this particular CSBK, if the status portion does work correctly, then it shouldn't matter which frequency it is on
//as long as this CSBK comes in and we can tune to other repeater lcns if they have activity and the frequency mapping
//is correct in the csv file, assuming the current frequency doesn't have voice activity
} //end 0x0A
//XPT Site Information - Adj Site Info??
//XPT Adjacent Site Information -- Have yet to find a consistent indication of 'current site' identification in any CSBK/FLC/SLC payload
if (csbk_o == 0x0B)
{
@@ -1195,58 +1346,35 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
fprintf (stderr, "\n");
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Hytera XPT CSBK 0x0B ");
int i;
uint8_t xpt_site_id[4];
uint8_t xpt_site_rp[4];
uint8_t xpt_site_u1[4];
uint8_t xpt_site_u2[4];
//wraithe's theory -- seems pretty good to me
//still only a theory though until can be verified
//by having a system with precisely known variables
uint8_t xpt_sn = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[0], 2);
//new samples show this doesn't always quite work, there seems to be
//more than one data set transmitted in this CSBK
//one set works, the other doesn't fit the pattern
// Site ID [5 bits]
// Unknown_3 [3 bits]
// Free Repeater on site [4 bits]
// Unknown_4 [4 bits]
// 11:44:58 Sync: +DMR slot1 [slot2] | Color Code=01 | CSBK
// Hytera XPT CSBK 0x0B
// DMR PDU Payload [0B][68][10][20][18][10][20][10][28][20][EF][DA]
// repeat x3 (for total of 4 sites)
// int i;
// uint8_t xpt_site_id[4];
// uint8_t xpt_site_rp[4];
// uint8_t xpt_site_u1[4];
// uint8_t xpt_site_u2[4];
// for (i = 0; i < 4; i++)
// {
// xpt_site_id[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16+(i*16)], 5);
// xpt_site_u1[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[21+(i*16)], 3);
// xpt_site_rp[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[24+(i*16)], 4);
// xpt_site_u2[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[28+(i*16)], 4);
// }
// fprintf (stderr, " Hytera XPT Site Id: %d - Free RPT: %d", xpt_site_id[0], xpt_site_rp[0]);
// // fprintf (stderr, " RS1: %d RS2: %d", xpt_site_u1[0], xpt_site_u2[1]); //debug
// fprintf (stderr, "\n");
// fprintf (stderr, " XPT Adj Site(s): ");
// for (i = 1; i < 4; i++)
// {
// if (xpt_site_id[i] != 0)
// {
// fprintf (stderr, "%d (%d) ", xpt_site_id[i], xpt_site_rp[i]);
// // fprintf (stderr, "RS1: %d RS2: %d - ", xpt_site_u1[i], xpt_site_u2[i]); //debug
// }
// }
for (i = 0; i < 4; i++)
{
xpt_site_id[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16+(i*16)], 5);
xpt_site_u1[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[21+(i*16)], 3);
xpt_site_rp[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[24+(i*16)], 4);
xpt_site_u2[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[28+(i*16)], 4);
}
fprintf (stderr, " Hytera XPT CSBK 0x0B - SN: %d", xpt_sn);
fprintf (stderr, "\n");
fprintf (stderr, " XPT Adjacent ");
for (i = 0; i < 4; i++)
{
if (xpt_site_id[i] != 0)
{
fprintf (stderr, "Site:%d Free:%d; ", xpt_site_id[i], xpt_site_rp[i]);
// fprintf (stderr, "RS1: %d RS2: %d - ", xpt_site_u1[i], xpt_site_u2[i]); //debug
}
}
sprintf (state->dmr_branding_sub, "XPT ");
} //end 0x0B
} //end Hytera XPT section

View File

@@ -172,7 +172,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
//look for any Hytera XPT system, adjust TG to 16-bit allocation
//Groups use only 8 out of 16, but 16 always seems to be allocated
//private calls use 16-bit target values hased to 8-bit in the site status csbk
//private calls use 16-bit target values hashed to 8-bit in the site status csbk
//the TLC preceeds the VLC for a 'handshake' call setup in XPT
//truncate if XPT is set
@@ -186,11 +186,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
tg_hash = crc8 (target_hash, 16);
}
//XPT Call 'Grant' Setup Occurs in TLC (TermLC Handshake) with a flco 0x09
//XPT Call 'Grant/Alert' Setup Occurs in TLC with a flco 0x09
if (fid == 0x68 && flco == 0x09)
{
//The CSBK always uses an 8-bit TG; The White Papers (user manuals) say 8-bit TG and 16-bit SRC addressing
//It seems that private calls and indiv data calls use a hash of their 8 bit tgt values in the CSBK
//The CSBK always uses an 8-bit TG/TGT; The White Papers (user manuals) say 8-bit TG and 16-bit SRC addressing
//private calls and indiv data calls use a hash of their 8 bit tgt values in the CSBK
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //This is consistent with an LCN value, not an LSN value
xpt_free = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 4); //24 and 4 on 0x09
xpt_hand = (uint8_t)ConvertBitIntoBytes(&lc_bits[28], 4); //handshake kind: 0 - ordinary; 1-2 Interrupts; 3-15 reserved;
@@ -198,86 +199,69 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16); //16-bit allocation
//the bits that are left behind
xpt_res_a = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 8); //Where the SVC bits would usually be
xpt_res_a = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 4); //after the xpt_int channel, before the free repeater channel -- call being established = 7; call connected = 0; ??
xpt_res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 8); //where the first 8 bits of the SRC would be
xpt_res_c = (uint8_t)ConvertBitIntoBytes(&lc_bits[72], 8); //some unknown 8 bit value after the SRC
//speculation: 16,4 may be the current repeater channel this call will occur on? or the channel to interrupt?, could also be 8 bits?
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //not sure about this value for this FLCO
//the crc8 hash is the value represented in the CSBK when dealing with private calls
for (int i = 0; i < 16; i++) target_hash[i] = lc_bits[32+i];
tg_hash = crc8 (target_hash, 16); //This is a different poly, but using as placeholder
tg_hash = crc8 (target_hash, 16);
fprintf (stderr, "%s \n", KGRN);
fprintf (stderr, " SLOT %d ", state->currentslot+1);
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
// Here are some of the RIDs with hash address seen in that sample:
// 930 = 88
// 9317 = 198
// 10002 = 187
if (opts->payload == 1) fprintf(stderr, "HASH=%d ", tg_hash);
// if (opts->payload == 1) fprintf(stderr, "HSK [%X] ", xpt_hand);
// if (opts->payload == 1) fprintf(stderr, "CH=%d ", xpt_int);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
// if (opts->payload == 1) fprintf(stderr, "RS [%02X][%02X][%02X] ", xpt_res_a, xpt_res_b, xpt_res_c);
fprintf (stderr, " SLOT %d ", state->currentslot+1);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
fprintf (stderr, "TGT=%u SRC=%u ", target, source);
fprintf (stderr, "Hytera XPT ");
if (reserved == 1) fprintf (stderr, "Group "); //according to observation
else fprintf (stderr, "Private "); //according to observation
fprintf (stderr, "Call Alert "); //sounds more reasonable than 'protect'
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "F-Rpt %d", xpt_free);
//Group ID ranges from 1 to 240; emergency group call ID ranges from 250 to 254; all call ID is 255.
if (reserved == 1)
{
fprintf (stderr, "Group "); //according to observation
if (target > 248 && target < 255) fprintf (stderr, "Emergency ");
if (target == 255) fprintf (stderr, "All ");
}
else fprintf (stderr, "Private "); //according to observation
fprintf (stderr, "Call Alert "); //Alert or Grant
//reorganized all the 'extra' data to a second line and added extra verbosity
if (opts->payload == 1) fprintf (stderr, "\n ");
if (opts->payload == 1) fprintf (stderr, "%s", KYEL);
//only display the hashed tgt value if its a private call and not a group call
if (reserved == 0 && opts->payload == 1) fprintf(stderr, "TGT Hash=%d; ", tg_hash);
if (opts->payload == 1) fprintf(stderr, "HSK=%X; ", xpt_hand);
//extra verbosity on handshake types found in the patent
if (opts->payload == 1)
{
fprintf (stderr, "Handshake - ");
if (xpt_hand == 0) fprintf (stderr, "Ordinary; ");
else if (xpt_hand == 1) fprintf (stderr, "Callback/Alarm Interrupt; ");
else if (xpt_hand == 2) fprintf (stderr, "Release Channel Interrupt; ");
else fprintf (stderr, "Reserved; ");
}
// if (opts->payload == 1)
// {
// if (xpt_res_a == 0) fprintf (stderr, "Call Connected; ");
// if (xpt_res_a == 1) fprintf (stderr, "Data Call Request; ");
// if (xpt_res_a == 7) fprintf (stderr, "Voice Call Request; ");
// if (xpt_res_a == 2) fprintf (stderr, "Unknown Status; ");
// }
//logical repeater channel, not the logical slot value in the CSBK
if (opts->payload == 1) fprintf(stderr, "Call on LCN %d; ", xpt_int); //LCN channel call or 'interrupt' will occur on
// if (opts->payload == 1) fprintf(stderr, "RS A[%01X]B[%02X]C[%02X]; ", xpt_res_a, xpt_res_b, xpt_res_c); //leftover bits
if (opts->payload == 1) fprintf (stderr, "Free LCN %d; ", xpt_free); //current free repeater LCN channel
fprintf (stderr, "%s ", KNRM);
//add string for ncurses terminal display
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free);
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
is_xpt = 1;
goto END_FLCO;
}
//XPT 'Handshake' -- not observed as of yet on any samples
if ( fid == 0x68 && (flco == 0x2E || flco == 0x2F) )
{
//all below is according to the patent, but never observed on any samples I have
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //24-bit values according to patent
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 24); //24-bit values according to patent
xpt_free = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //16 and 4 on 2E and 2F
xpt_hand = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 4); //handshake kind: 0 - ordinary; 1-2 Interrupts; 3-15 reserved;
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 8); //Interrupt Designated Channel (No idea?)
fprintf (stderr, "%s \n", KGRN);
fprintf (stderr, " SLOT %d ", state->currentslot+1);
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
if (opts->payload == 1) fprintf(stderr, "HASH=%d ", tg_hash);
// if (opts->payload == 1) fprintf(stderr, "HSK=[%X] ", xpt_hand);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
fprintf (stderr, "Hytera XPT ");
if (reserved == 1) fprintf (stderr, "Group ");
else fprintf (stderr, "Private ");
fprintf (stderr, "Call ");
if (flco == 0x2E) fprintf (stderr, "Request ");
if (flco == 0x2F) fprintf (stderr, "Response ");
fprintf (stderr, "%s ", KNRM);
is_xpt = 1;
goto END_FLCO;
}
//Hytera XPT "something" -- seen on Embedded
if (fid == 0x68 && flco == 0x13)
//Hytera XPT 'Others' -- moved the patent opcodes here as well for now
if ( fid == 0x68 && (flco == 0x13 || flco == 0x31 || flco == 0x2E || flco == 0x2F) )
{
if (type == 1) fprintf (stderr, "%s \n", KCYN);
if (type == 2) fprintf (stderr, "%s \n", KCYN);
@@ -377,7 +361,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
fprintf (stderr, " SLOT %d ", state->currentslot+1);
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
if (opts->payload == 1 && is_xpt == 1) fprintf(stderr, "HASH=%d ", tg_hash);
if (opts->payload == 1 && is_xpt == 1 && flco == 0x3) fprintf(stderr, "HASH=%d ", tg_hash);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator (perhaps one for each MS)
@@ -403,7 +387,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
fprintf (stderr, "Private ");
}
}
else if (flco == 0x3) //UU_V_Ch_Usr -- still valid on hytera VLC
else if (flco == 0x3) //UU_V_Ch_Usr
{
sprintf (state->call_string[slot], " Private ");
fprintf (stderr, "Private ");
@@ -549,7 +533,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
END_FLCO:
if (unk == 1 || pf == 1)
{
fprintf(stderr, " FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
fprintf(stderr, " FLCO=0x%02X FID=0x%02X ", flco, fid);
fprintf (stderr, "%s", KNRM);
}
@@ -905,13 +889,13 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
else if (slco == 0x08)
{
//The Priority Repeater and Priority Hash values stem from SDRTrunk, but I've never seen these values not be zeroes
// fprintf (stderr, " SLCO Hytera XPT - Free RPT %d - PRI RPT %d - PRI HASH: %02X", xpt_free, xpt_pri, xpt_hash);
fprintf (stderr, " SLCO Hytera XPT - Free LCN %d - PRI LCN %d - PRI HASH: %02X", xpt_free, xpt_pri, xpt_hash);
//NOTE: on really busy systems, this free repeater assignment can lag due to the 4 TS requirment to get SLC
fprintf (stderr, " SLCO Hytera XPT - Free RPT %d ", xpt_free);
// fprintf (stderr, " SLCO Hytera XPT - Free LCN %d ", xpt_free);
sprintf (state->dmr_branding_sub, "XPT ");
//add string for ncurses terminal display
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free);
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
}
else fprintf (stderr, " SLCO Unknown - %d ", slco);

View File

@@ -239,9 +239,9 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
// if (irr_err == 0)
// {
// if (sbrc_hex == 0) ; //NULL
// else if (sbrc_hex == 0x313) //sbrc_hex == 0x313 and 0x643 (cap+ things)
// else if (strcmp (state->dmr_branding_sub, "Cap+ ") == 0)
// {
// //Cap+ Site ID seems to fit here on samples I've seen with the alternate SB signalling
// //Cap+ Site ID seems to fit here on samples I've seen with the alternate SB signalling, but no idea what signals that info and not the emb alg/key info
// fprintf (stderr, "%s ", KYEL);
// fprintf (stderr, "\n ");
// fprintf (stderr, " Capacity Plus Site %d", cap_site);

View File

@@ -545,6 +545,9 @@ openAudioInDevice (dsd_opts * opts)
const char ch = '.';
extension = strrchr(opts->audio_in_dev, ch); //return extension if this is a .wav or .bin file
//if no extension set, give default of .wav -- bugfix for github issue #105
// if (extension == NULL) extension = ".wav";
// get info of device/file
if (strncmp(opts->audio_in_dev, "-", 1) == 0)
{
@@ -607,6 +610,25 @@ openAudioInDevice (dsd_opts * opts)
{
opts->audio_in_type = 5;
}
//if no extension set, treat as named pipe or extensionless wav file -- bugfix for github issue #105
else if (extension == NULL)
{
opts->audio_in_type = 2;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate = opts->wav_sample_rate;
opts->audio_in_file_info->channels = 1;
opts->audio_in_file_info->seekable = 0;
opts->audio_in_file_info->format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info);
if (opts->audio_in_file == NULL)
{
fprintf(stderr, "Error, couldn't open file/pipe with libsndfile: %s\n", sf_strerror(NULL));
exit(1);
}
}
else if (strncmp(extension, ".bin", 3) == 0)
{
struct stat stat_buf;

View File

@@ -52,7 +52,7 @@ char * FM_banner[9] = {
" ██║ ██║ ╚═══██╗██║ ██║   ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
" ██████╔╝██████╔╝██████╔╝   ██║ ██║ ╚═╝ ██║███████╗",
" ╚═════╝ ╚═════╝ ╚═════╝    ╚═╝ ╚═╝ ╚═╝╚══════╝",
" 'Aero' Edition v2.0.0-64-gbd94f83 Windows 32-bit RC5 "
" 'Aero' Edition v2.0.0-84-gacd2b0b Windows 32-bit "
};
int comp (const void *a, const void *b)
@@ -234,6 +234,12 @@ noCarrier (dsd_opts * opts, dsd_state * state)
state->nxdn_location_sys_code = 0;
sprintf (state->nxdn_location_category, "%s", " ");
//channel access information
state->nxdn_rcn = 0;
state->nxdn_base_freq = 0;
state->nxdn_step = 0;
state->nxdn_bw = 0;
//dmr mfid branding and site parms
sprintf(state->dmr_branding_sub, "%s", "");
sprintf(state->dmr_branding, "%s", "");
@@ -881,13 +887,21 @@ initState (dsd_state * state)
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
state->nxdn_alias_block_number = 0;
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
//site/srv/cch info
state->nxdn_location_site_code = 0;
state->nxdn_location_sys_code = 0;
sprintf (state->nxdn_location_category, "%s", " ");
//channel access information
state->nxdn_rcn = 0;
state->nxdn_base_freq = 0;
state->nxdn_step = 0;
state->nxdn_bw = 0;
//multi-key array
memset (state->rkey_array, 0, sizeof(state->rkey_array));
memset (state->rkey_array, 0, sizeof(state->rkey_array));
state->keyloader = 0; //keyloader off
//Remus DMR End Call Alert Beep
state->dmr_end_alert[0] = 0;
@@ -1305,6 +1319,7 @@ main (int argc, char **argv)
strncpy(opts.key_in_file, optarg, 1023);
opts.key_in_file[1023] = '\0';
csvKeyImport(&opts, &state);
state.keyloader = 1;
break;
case 'Q': //'DSP' Structured Output file for OKDMRlib
@@ -1450,17 +1465,9 @@ main (int argc, char **argv)
case 'R':
sscanf (optarg, "%lld", &state.R);
if (state.R > 0x7FFF)
{
state.R = 0x7FFF;
}
// opts.dmr_mute_encL = 0;
// opts.dmr_mute_encR = 0;
if (state.R == 0)
{
// opts.dmr_mute_encL = 1;
// opts.dmr_mute_encR = 1;
}
if (state.R > 0x7FFF) state.R = 0x7FFF;
//disable keyloader in case user tries to use this and it at the same time
state.keyloader = 0;
break;
case 'H':

View File

@@ -141,7 +141,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
int x;
//24-bit TG to 16-bit hash
uint16_t hash = 0;
uint32_t hash = 0;
uint8_t hash_bits[24];
memset (hash_bits, 0, sizeof(hash_bits));
@@ -304,7 +304,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
if (state->M == 0)
{
//see if we need to hash a value larger than 16-bits
hash = state->lasttg & 0xFFFFFF;
hash = state->lasttg & 0xFFFFFF;
// fprintf (stderr, "TG: %lld Hash: %ld ", state->lasttg, hash);
if (hash > 0xFFFF) //if greater than 16-bits
{
for (int i = 0; i < 24; i++)
@@ -313,12 +314,14 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
hash = ComputeCrcCCITT16d (hash_bits, 24);
hash = hash & 0xFFFF; //make sure its no larger than 16-bits
// fprintf (stderr, "Hash: %d ", hash);
}
if (state->rkey_array[hash] != 0)
{
state->K = state->rkey_array[hash] & 0xFF; //doesn't exceed 255
state->K1 = state->H = state->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
opts->dmr_mute_encL = 0;
// fprintf (stderr, "Key: %X ", state->rkey_array[hash]);
}
// else opts->dmr_mute_encL = 1; //may cause issues for manual key entry (non-csv)
}
@@ -432,6 +435,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
{
//see if we need to hash a value larger than 16-bits
hash = state->lasttgR & 0xFFFFFF;
// fprintf (stderr, "TG: %lld Hash: %ld ", state->lasttgR, hash);
if (hash > 0xFFFF) //if greater than 16-bits
{
for (int i = 0; i < 24; i++)
@@ -440,12 +444,14 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
hash = ComputeCrcCCITT16d (hash_bits, 24);
hash = hash & 0xFFFF; //make sure its no larger than 16-bits
// fprintf (stderr, "Hash: %d ", hash);
}
if (state->rkey_array[hash] != 0)
{
state->K = state->rkey_array[hash] & 0xFF; //doesn't exceed 255
state->K1 = state->H = state->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
opts->dmr_mute_encR = 0;
// fprintf (stderr, "Key: %X ", state->rkey_array[hash]);
}
// else opts->dmr_mute_encR = 1; //may cause issues for manual key entry (non-csv)
}

View File

@@ -97,9 +97,9 @@ char * SyncTypes[44] = {
"NXDN",
"YSF", //30
"YSF",
"DMR MS VOICE",
"DMR MS DATA",
"DMR RC DATA",
"DMR",
"DMR",
"DMR",
"P25P2",
"P25P2",
"EDACS/PV", //37
@@ -378,12 +378,23 @@ void ncursesOpen (dsd_opts * opts, dsd_state * state)
setlocale(LC_ALL, "");
initscr(); //Initialize NCURSES screen window
start_color();
#ifdef PRETTY_COLORS
init_pair(1, COLOR_YELLOW, COLOR_BLACK); //Yellow/Amber for frame sync/control channel, NV style
init_pair(2, COLOR_RED, COLOR_BLACK); //Red for Terminated Calls
init_pair(3, COLOR_GREEN, COLOR_BLACK); //Green for Active Calls
init_pair(4, COLOR_CYAN, COLOR_BLACK); //Cyan for Site Extra and Patches
init_pair(5, COLOR_MAGENTA, COLOR_BLACK); //Magenta for no frame sync/signal
init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
#else
init_pair(1, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
init_pair(2, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
init_pair(3, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
init_pair(4, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
init_pair(5, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
#endif
noecho();
cbreak();
@@ -1685,6 +1696,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
void
ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
uint8_t idas = 0;
int level = 0;
int c = 0;
@@ -2061,7 +2073,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (opts->ncurses_compact == 1)
{
printw ("------------------------------------------------------------------------------\n");
printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "v2.0.0-64-gbd94f83 RC5");
printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "v2.0.0-84-gacd2b0b Win32");
}
if (opts->ncurses_compact == 0)
{
@@ -2072,8 +2084,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (i == 1) printw (" ESC to Menu");
if (i == 2) printw (" 'q' to Quit ");
if (i == 4) printw (" MBElib %s", versionstr);
if (i == 5) printw (" %s ", "Aero RC5"); //printw (" %s \n", GIT_TAG);
if (i == 6) printw (" %s \n", "v2.0.0-64-gbd94f83"); //printw (" %s \n", GIT_TAG);
if (i == 5) printw (" %s ", "Aero Win32"); //printw (" %s \n", GIT_TAG);
if (i == 6) printw (" %s \n", "v2.0.0-84-gacd2b0b"); //printw (" %s \n", GIT_TAG);
else printw ("\n");
}
attroff(COLOR_PAIR(6)); //6
@@ -2255,41 +2267,49 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//NXDN
if (lls == 28 || lls == 29)
{
if (strcmp (state->nxdn_location_category, "Type-D") == 0) idas = 1;
if (opts->p25_trunk == 1)
{
printw ("| ");
if (opts->p25_is_tuned == 0)
{
printw ("Monitoring Control Channel");
if (idas == 0) printw ("Monitoring RCCH Channel"); //Control Channel
if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2 Channel
if (state->p25_cc_freq != 0)
{
printw (" - CC Freq: [%.06lf] Mhz ", (double)state->p25_cc_freq/1000000);
printw (" - Frequency: [%.06lf] Mhz ", (double)state->p25_cc_freq/1000000);
}
}
else if (opts->p25_is_tuned == 1)
{
printw ("Monitoring Voice Channel");
if (idas == 0) printw ("Monitoring RTCH Channel"); //Traffic Channel
if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2
if (state->p25_vc_freq[0] != 0)
{
printw (" - VC Freq: [%.06lf] Mhz ", (double)state->p25_vc_freq[0]/1000000);
printw (" - Frequency: [%.06lf] Mhz ", (double)state->p25_vc_freq[0]/1000000);
}
}
printw ("\n");
}
printw ("\n");
}
printw ("| ");
printw ("NXDN - RAN: [%2d] ", rn);
if (idas == 0) printw ("NXDN - RAN: [%02d] ", rn);
if (idas == 1) printw ("IDAS - Area: [%02d] ", rn);
if (state->nxdn_location_site_code != 0)
{
printw ("Cat [%s] ", state->nxdn_location_category);
printw ("Sys Code [%d] ", state->nxdn_location_sys_code);
printw ("Site Code [%d] ", state->nxdn_location_site_code);
printw ("Cat: [%s] ", state->nxdn_location_category);
printw ("Sys Code: [%d] ", state->nxdn_location_sys_code);
printw ("Site Code: [%d] ", state->nxdn_location_site_code);
}
//if system supports Direct Frequency Assignment
if (state->nxdn_rcn == 1) printw ("DFA ");
printw ("\n");
printw ("| ");
printw ("TGT: [%5d] ", tgn);
@@ -2317,9 +2337,9 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
if (state->nxdn_cipher_type == 0x1 && state->carrier == 1)
{
attron(COLOR_PAIR(2));
if (state->R == 0) attron(COLOR_PAIR(2));
printw ("Scrambler ");
attroff(COLOR_PAIR(2));
if (state->R == 0) attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
if (state->R != 0)
{
@@ -2497,6 +2517,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw("DES-OFB");
attron(COLOR_PAIR(3));
}
if (state->payload_algid == 0x82)
{
attron(COLOR_PAIR(1));
printw("Double DES");
attron(COLOR_PAIR(3));
}
if (state->payload_algid == 0x83 || state->payload_algid == 0x23)
{
attron(COLOR_PAIR(1));
@@ -2938,7 +2964,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("| %s ", SyncTypes[call_matrix[9-j][0]]);
if (lls == 28 || lls == 29)
{
printw ("RAN [%02lld] ", call_matrix[9-j][1]);
if (idas == 0) printw ("RAN [%02lld] ", call_matrix[9-j][1]);
if (idas == 1) printw ("Area [%02lld] ", call_matrix[9-j][1]);
printw ("TG [%5lld] ", call_matrix[9-j][4]);
printw ("RID [%5lld] ", call_matrix[9-j][2]);
}
@@ -2967,7 +2994,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//DMR MS Types
if (call_matrix[9-j][0] == 32 || call_matrix[9-j][0] == 33 || call_matrix[9-j][0] == 34 )
{
//printw ("S[%d] ", call_matrix[9-j][3]);
printw ("S[%lld] ", call_matrix[9-j][3]);
printw ("TGT [%8lld] ", call_matrix[9-j][1]);
printw ("SRC [%8lld] ", call_matrix[9-j][2]);
printw ("DCC [%02lld] ", call_matrix[9-j][4]);
@@ -3225,6 +3252,16 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT");
state->group_tally++;
//if we have an opened group file, let's write a group lock out into it to make it permanent
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,B,LOCKOUT,%02X\n", state->lasttg, state->payload_algid);
fclose (pFile);
}
//extra safeguards due to sync issues with NXDN
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
@@ -3264,6 +3301,16 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT");
state->group_tally++;
//if we have an opened group file, let's write a group lock out into it to make it permanent
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,B,LOCKOUT,%02X\n", state->lasttgR, state->payload_algidR);
fclose (pFile);
}
//extra safeguards due to sync issues with NXDN
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
@@ -3347,6 +3394,19 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
opts->dmr_dmrla_is_set = 0;
opts->dmr_dmrla_n = 0;
//reset NXDN info
state->nxdn_location_site_code = 0;
state->nxdn_location_sys_code = 0;
sprintf (state->nxdn_location_category, "%s", " ");
state->nxdn_last_ran = 0;
state->nxdn_ran = 0;
state->nxdn_rcn = 0;
state->nxdn_base_freq = 0;
state->nxdn_step = 0;
state->nxdn_bw = 0;
}
//Debug/Troubleshooting Option

View File

@@ -52,13 +52,15 @@ void nxdn_descramble(uint8_t dibits[], int len)
void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
{
uint8_t deperm[144];
uint8_t depunc[192];
uint8_t trellis_buf[96];
uint8_t deperm[200]; //144
uint8_t depunc[200]; //192
uint8_t trellis_buf[400]; //96
uint16_t crc = 0; //crc calculated by function
uint16_t check = 0; //crc from payload for comparison
int out;
char buf[128];
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
for (int i=0; i<144; i++)
deperm[PERM_16_9[i]] = bits[i];
@@ -74,7 +76,7 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
uint8_t temp[210];
uint8_t s0;
uint8_t s1;
uint8_t m_data[13];
uint8_t m_data[20]; //13
memset (temp, 0, sizeof(temp));
memset (m_data, 0, sizeof(m_data));
memset (trellis_buf, 0, sizeof(trellis_buf));
@@ -119,6 +121,14 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
check = check | trellis_buf[84+i]; //80
}
if (crc != check)
{
fprintf (stderr, " FACCH");
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
@@ -130,24 +140,23 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
{
fprintf (stderr, "[%02X]", m_data[i]);
}
fprintf (stderr, " - %03X %03X", check, crc);
// fprintf (stderr, " - %03X %03X", check, crc);
}
}
//new sacch
//sacch
void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
{
//see about initializing these variables
uint8_t deperm[60];
uint8_t depunc[72];
uint8_t trellis_buf[32];
uint8_t answer[26];
uint8_t deperm[200]; //60
uint8_t depunc[200]; //72
uint8_t trellis_buf[400]; //32
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (answer, 0, sizeof(answer));
int o = 0;
uint8_t crc = 0; //value computed by crc6 on payload
uint8_t check = 0; //value pulled from last 6 bits
@@ -176,7 +185,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
uint8_t temp[90];
uint8_t s0;
uint8_t s1;
uint8_t m_data[5];
uint8_t m_data[10]; //5
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
@@ -229,16 +238,30 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
else fprintf (stderr, " ");
uint8_t nsf_sacch[26];
uint8_t nsf_sacch[400];
memset (nsf_sacch, 0, sizeof(nsf_sacch));
for (int i = 0; i < 26; i++)
{
nsf_sacch[i] = trellis_buf[i+8];
}
if (crc == check)
{
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
state->nxdn_last_ran = ran;
}
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, nsf_sacch);
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, nsf_sacch);
if (crc != check)
{
fprintf (stderr, " SACCH NSF");
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
if (opts->payload == 1)
{
fprintf (stderr, "\n SACCH NSF ");
@@ -246,8 +269,12 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
{
fprintf (stderr, "[%02X]", m_data[i]);
}
if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", check, crc);
// if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", check, crc);
}
//reset the sacch field -- Github Issue #118
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
}
@@ -257,7 +284,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
//sf and ran together are denoted as SR in the manual (more confusing acronyms)
//sf (structure field) and RAN will always exist in first 8 bits of each SACCH, then the next 18 bits are the fragment of the superframe
sf = (trellis_buf[0] << 1) | trellis_buf[1];
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
if (sf == 3) part_of_frame = 0;
else if (sf == 2) part_of_frame = 1;
else if (sf == 1) part_of_frame = 2;
@@ -268,12 +295,21 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
else fprintf (stderr, " ");
fprintf (stderr, "%s", KNRM);
if (crc != check)
{
fprintf (stderr, " SACCH SF%d", sf);
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
//reset scrambler seed to key value on new superframe
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
if (crc == check)
{
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
state->nxdn_ran = state->nxdn_last_ran = ran;
state->nxdn_sf = sf;
state->nxdn_part_of_frame = part_of_frame;
@@ -304,22 +340,24 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
{
fprintf (stderr, "[%02X]", m_data[i]);
}
if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check);
// if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check);
}
}
}
void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348])
void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type)
{
uint8_t deperm[348];
uint8_t depunc[406];
uint8_t trellis_buf[199];
uint8_t deperm[500]; //348
uint8_t depunc[500]; //406
uint8_t trellis_buf[400]; //199
int id = 0;
uint16_t crc = 0;
uint16_t check = 0;
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
for (int i=0; i<348; i++) {
deperm[PERM_12_29[i]] = bits[i];
}
@@ -341,10 +379,10 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
}
//switch to the convolutional decoder
uint8_t temp[220];
uint8_t temp[500]; //220, this one was way too small
uint8_t s0;
uint8_t s1;
uint8_t m_data[26];
uint8_t m_data[52]; //26
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
@@ -390,7 +428,17 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
check = check | trellis_buf[i+184];
}
uint8_t f2u_message_buffer[199];
if (crc != check)
{
fprintf (stderr, "%s", KYEL);
if (type == 0) fprintf (stderr, " UDCH");
if (type == 1) fprintf (stderr, " FACCH2");
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
uint8_t f2u_message_buffer[400]; //199
memset (f2u_message_buffer, 0, sizeof(f2u_message_buffer));
//just going to leave this all here in case its needed, like in cac,
@@ -401,36 +449,57 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
}
if (crc == check)
{
fprintf (stderr, " F2/U ");
//NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
NXDN_Elements_Content_decode(opts, state, 1, f2u_message_buffer);
{
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, f2u_message_buffer);
if (type == 0) ; //need handling for user data (text messages and AVL)
}
else if (opts->aggressive_framesync == 0)
{
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
if (type == 0) ; //need handling for user data (text messages and AVL)
}
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
if (opts->payload == 1)
{
fprintf (stderr, "\n");
fprintf (stderr, " F2/U Payload\n ");
if (type == 0) fprintf (stderr, " UDCH");
if (type == 1) fprintf (stderr, " FACCH2");
fprintf (stderr, " Payload\n ");
for (int i = 0; i < 26; i++)
{
if (i == 13) fprintf (stderr, "\n ");
fprintf (stderr, "[%02X]", m_data[i]);
if (i == 12) fprintf (stderr, "\n ");
}
if (crc != check) fprintf (stderr, " CRC ERR ");
// if (crc != check) fprintf (stderr, " CRC ERR ");
if (type == 0)
{
fprintf (stderr, "\n UDCH Data: ASCII - " );
for (int i = 0; i < 24; i++) //remove crc portion
{
if (m_data[i] <= 0x7E && m_data[i] >=0x20)
{
fprintf (stderr, "%c", m_data[i]);
}
else fprintf (stderr, " ");
}
}
}
}
void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
{
uint8_t deperm[300];
uint8_t depunc[350];
uint8_t trellis_buf[171];
uint8_t deperm[500]; //300
uint8_t depunc[500]; //350
uint8_t trellis_buf[400]; //171
int id = 0;
int ran = 0;
uint16_t crc = 0;
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
for (int i=0; i<300; i++) {
deperm[PERM_12_25[i]] = bits[i];
}
@@ -455,7 +524,7 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
uint8_t temp[360];
uint8_t s0;
uint8_t s1;
uint8_t m_data[26];
uint8_t m_data[52]; //26
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
@@ -490,7 +559,7 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
crc = crc16cac(trellis_buf, 171);
uint8_t cac_message_buffer[171];
uint8_t cac_message_buffer[400]; //171
memset (cac_message_buffer, 0, sizeof(cac_message_buffer));
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field
@@ -499,11 +568,27 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
cac_message_buffer[i] = trellis_buf[i+8];
}
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
else fprintf (stderr, " ");
if (crc == 0)
{
fprintf (stderr, " CAC ");
NXDN_Elements_Content_decode(opts, state, 1, cac_message_buffer);
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
state->nxdn_last_ran = ran;
}
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " CAC");
fprintf (stderr, "%s", KNRM);
if (crc != 0)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
if (crc == 0) NXDN_Elements_Content_decode(opts, state, 1, cac_message_buffer);
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, cac_message_buffer);
if (opts->payload == 1)
@@ -515,32 +600,320 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
fprintf (stderr, "[%02X]", m_data[i]);
if (i == 10) fprintf (stderr, "\n ");
}
if (crc != 0) fprintf (stderr, " CRC ERR ");
// if (crc != 0) fprintf (stderr, " CRC ERR ");
}
}
//Type-D "IDAS"
void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint8_t direction)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " SCCH");
//see about initializing these variables
uint8_t deperm[200]; //60
uint8_t depunc[200]; //72
uint8_t trellis_buf[400]; //32
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
memset (trellis_buf, 0, sizeof(trellis_buf));
int o = 0;
uint8_t crc = 0; //value computed by crc7 on payload
uint8_t check = 0; //value pulled from last 7 bits
int sf = 0;
int part_of_frame = 0;
for (int i=0; i<60; i++)
deperm[PERM_12_5[i]] = bits[i];
for (int p=0; p<60; p+= 10) {
depunc[o++] = deperm[p+0];
depunc[o++] = deperm[p+1];
depunc[o++] = deperm[p+2];
depunc[o++] = deperm[p+3];
depunc[o++] = deperm[p+4];
depunc[o++] = 0;
depunc[o++] = deperm[p+5];
depunc[o++] = deperm[p+6];
depunc[o++] = deperm[p+7];
depunc[o++] = deperm[p+8];
depunc[o++] = deperm[p+9];
depunc[o++] = 0;
}
//switch to the convolutional decoder
uint8_t temp[90];
uint8_t s0;
uint8_t s1;
uint8_t m_data[10]; //5
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
memset (trellis_buf, 0, sizeof(trellis_buf));
for (int i = 0; i < 72; i++)
{
temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+72] = 0;
}
CNXDNConvolution_start();
for (int i = 0U; i < 36U; i++)
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
CNXDNConvolution_decode(s0, s1);
}
CNXDNConvolution_chainback(m_data, 32U);
for(int i = 0; i < 4; i++)
{
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
}
crc = crc7_scch(trellis_buf, 25);
for (int i = 0; i < 7; i++)
{
check = check << 1;
check = check | trellis_buf[i+25];
}
//check the sf early for scrambler reset, if required
sf = (trellis_buf[0] << 1) | trellis_buf[1];
if (sf == 3) part_of_frame = 0;
else if (sf == 2) part_of_frame = 1;
else if (sf == 1) part_of_frame = 2;
else if (sf == 0) part_of_frame = 3;
else part_of_frame = 0;
//reset scrambler seed to key value on new superframe
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
/*
4.3.2. Mapping to Functional Channel
When Subscriber Unit performs voice communication in RTCH2, SCCH is allocated as
described below.
SCCH has super Frame Structure with 4 frame unit during communication, and has non
super Frame Structure with single frame unit at the start time and end time of sending.
Allocation of the other channel is not specified particularly.
*/
//English Translation: Superframe when voice, Non Superframe when not voice
//What I've found is that by not using the superframe structure, and decoding each 'unit'
//individually instead, we can get more expedient decoding on elements without having to
//sacrifice an entire superframe for one bad CRC, also each element cleanly divides into a
//single 'unit' except for enc parms IV, which can be stored seperately if needed
//NOTE: scch has its own message format, and thus, doesn't go to content element decoding
//like everything else does
if (crc != check)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
if (crc == check) NXDN_decode_scch (opts, state, trellis_buf, direction);
else if (opts->aggressive_framesync == 0) NXDN_decode_scch (opts, state, trellis_buf, direction);
fprintf (stderr, "%s", KNRM);
if (opts->payload == 1)
{
fprintf (stderr, "\n SCCH Payload ");
for (int i = 0; i < 4; i++)
{
fprintf (stderr, "[%02X]", m_data[i]);
}
// if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", check, crc);
}
fprintf (stderr, "%s", KNRM);
}
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type)
{
uint8_t deperm[300]; //144
uint8_t depunc[300]; //192
uint8_t trellis_buf[600]; //96
uint8_t f3_udch2[288]; //completed bitstream without crc and tailing bits attached
uint8_t f3_udch2_bytes[36]; //completed bytes - with crc and tail
uint16_t crc[2]; //crc calculated by function
uint16_t check[2]; //crc from payload for comparison
int out;
//switch to the convolutional decoder
uint8_t temp[500];
uint8_t s0;
uint8_t s1;
uint8_t m_data[40]; //13
memset (temp, 0, sizeof(temp));
memset (m_data, 0, sizeof(m_data));
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
memset (crc, 0, sizeof(crc));
memset (check, 0, sizeof(check));
memset (f3_udch2, 0, sizeof(f3_udch2));
memset (f3_udch2_bytes, 0, sizeof(f3_udch2_bytes));
for (int j=0; j<2; j++)
{
for (int i=0; i<144; i++)
deperm[PERM_16_9[i]] = bits[i+(j*144)];
out = 0;
for (int i=0; i<144; i+=3) {
depunc[out++] = deperm[i+0];
depunc[out++] = 0;
depunc[out++] = deperm[i+1];
depunc[out++] = deperm[i+2];
}
for (int i = 0; i < 192; i++)
{
temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+192] = 0;
}
CNXDNConvolution_start();
for (int i = 0U; i < 100U; i++)
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
CNXDNConvolution_decode(s0, s1);
}
CNXDNConvolution_chainback(m_data, 96U);
for(int i = 0; i < 12; i++)
{
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
}
crc[j] = crc12f (trellis_buf, 84); //84
for (int i = 0; i < 12; i++)
{
check[j] = check[j] << 1;
check[j] = check[j] | trellis_buf[84+i]; //84
}
//transfer to storage sans crc and tail bits
for (int i = 0; i < 80; i++) f3_udch2[i+(j*80)] = trellis_buf[i];
for (int i = 0; i < 12; i++) f3_udch2_bytes[i+(j*12)] = m_data[i];
}
if (crc[0] != check[0] || crc[1] != check[1])
{
if (type == 0) fprintf (stderr, " UDCH2");
if (type == 1) fprintf (stderr, " FACCH3");
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
if (crc[0] == check[0] && crc[1] == check[1])
{
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
if (type == 0) ; //need handling for user data (text messages and AVL)
}
else if (opts->aggressive_framesync == 0)
{
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
if (type == 0) ; //need handling for user data (text messages and AVL)
}
if (opts->payload == 1)
{
fprintf (stderr, "\n");
if (type == 0) fprintf (stderr, " UDCH2");
if (type == 1) fprintf (stderr, " FACCH3");
fprintf (stderr, " Payload \n ");
for (int i = 0; i < 24; i++)
{
if (i == 12) fprintf (stderr, "\n ");
fprintf (stderr, "[%02X]", f3_udch2_bytes[i]);
}
// fprintf (stderr, " - %03X %03X", check[0], crc[0]);
// fprintf (stderr, " - %03X %03X", check[1], crc[1]);
if (type == 0)
{
fprintf (stderr, "\n UDCH2 Data: ASCII - " );
for (int i = 0; i < 22; i++) //all but last crc portion
{
if (i == 12) i = 14; //skip first crc portion
if (f3_udch2_bytes[i] <= 0x7E && f3_udch2_bytes[i] >=0x20)
{
fprintf (stderr, "%c", f3_udch2_bytes[i]);
}
else fprintf (stderr, " ");
}
}
}
}
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
{
//NOTE: Most Req/Resp (request and respone) share same message type but differ depending on channel type
//RTCH Outbound will take precedent when differences may occur (except CALL_ASSGN)
fprintf (stderr, "%s", KYEL);
if (MessageType == 0x10) fprintf(stderr, " IDLE");
else if (MessageType == 0x11) fprintf(stderr, " DISC"); //disconnect
else if (MessageType == 0x00) fprintf(stderr, " CALL_RESP");
else if (MessageType == 0x01) fprintf(stderr, " VCALL");
else if (MessageType == 0x02) fprintf(stderr, " VCALL_REC_REQ");
else if (MessageType == 0x03) fprintf(stderr, " VCALL_IV");
else if (MessageType == 0x07) fprintf(stderr, " TX_REL_EX");
else if (MessageType == 0x08) fprintf(stderr, " TX_REL");
else if (MessageType == 0x04) fprintf(stderr, " VCALL_ASSGN");
else if (MessageType == 0x05) fprintf(stderr, " VCALL_ASSGN_DUP");
else if (MessageType == 0x06) fprintf(stderr, " CALL_CONN_RESP");
else if (MessageType == 0x07) fprintf(stderr, " TX_REL_EX");
else if (MessageType == 0x08) fprintf(stderr, " TX_REL");
else if (MessageType == 0x09) fprintf(stderr, " DCALL_HEADER");
else if (MessageType == 0x0A) fprintf(stderr, " DCALL_REC_REQ");
else if (MessageType == 0x0B) fprintf(stderr, " DCALL_UDATA");
else if (MessageType == 0x0C) fprintf(stderr, " DCALL_ACK");
else if (MessageType == 0x0D) fprintf(stderr, " DCALL_ASSGN_DUP");
else if (MessageType == 0x0E) fprintf(stderr, " DCALL_ASSGN");
else if (MessageType == 0x11) fprintf(stderr, " DISC");
else if (MessageType == 0x17) fprintf(stderr, " DST_ID_INFO");
else if (MessageType == 0x18) fprintf(stderr, " SITE_INFO");
else if (MessageType == 0x19) fprintf(stderr, " SRV_INFO");
else if (MessageType == 0x1C) fprintf(stderr, " FAIL_STAT_INFO");
else if (MessageType == 0x19) fprintf(stderr, " SRV_INFO");
else if (MessageType == 0x1A) fprintf(stderr, " CCH_INFO");
else if (MessageType == 0x1B) fprintf(stderr, " ADJ_SITE_INFO");
else if (MessageType == 0x1C) fprintf(stderr, " FAIL_STAT_INFO");
else if (MessageType == 0x20) fprintf(stderr, " REG_RESP");
else if (MessageType == 0x22) fprintf(stderr, " REG_C_RESP");
else if (MessageType == 0x24) fprintf(stderr, " GRP_REG_RESP");
@@ -549,23 +922,22 @@ void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
else if (MessageType == 0x38) fprintf(stderr, " SDCALL_REQ_HEADER");
else if (MessageType == 0x39) fprintf(stderr, " SDCALL_REQ_USERDATA");
else if (MessageType == 0x3B) fprintf(stderr, " SDCALL_RESP");
else if (MessageType == 0x3F) fprintf(stderr, " ALIAS");
else if (MessageType == 0x0C) fprintf(stderr, " DCALL_ACK");
else fprintf(stderr, " Unknown M-%02X", MessageType);
fprintf (stderr, "%s", KNRM);
//zero out stale values so they won't persist after a transmit release, idle, or disconnect
if (MessageType == 0x08 || MessageType == 0x10 || MessageType == 0x11) //tx_rel, idle, or disc
//Zero out stale values on DISC or TX_REL only (IDLE messaages occur often on NXDN96 VCH, and randomly on Type-C FACCH1 steals for some reason)
if (MessageType == 0x08 || MessageType == 0x11)
{
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
state->nxdn_last_rid = 0;
state->nxdn_last_tg = 0;
state->nxdn_cipher_type = 0;
if (state->M == 0) state->nxdn_cipher_type = 0;
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
sprintf (state->nxdn_call_type, "%s", "");
}
}
}
//voice descrambler
@@ -677,4 +1049,23 @@ static uint16_t crc16cac(const uint8_t buf[], int len)
}
crc = crc ^ 0xffff;
return crc & 0xffff;
}
static uint8_t crc7_scch(uint8_t bits[], int len)
{
uint8_t s[7];
uint8_t a;
for (int i=0;i<7;i++)
s[i] = 1;
for (int i=0;i<len;i++) {
a = bits[i] ^ s[0];
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[3] = a ^ s[4];
s[4] = s[5];
s[5] = s[6];
s[6] = a;
}
return load_i(s, 7);
}

File diff suppressed because it is too large Load Diff

View File

@@ -32,28 +32,42 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
// length is implicitly 192, with frame sync in first 10 dibits
uint8_t dbuf[182];
uint8_t lich;
int answer_len=0;
int answer_len = 0;
uint8_t answer[32];
uint8_t sacch_answer[32];
int lich_parity_received;
int lich_parity_computed;
int voice=0;
int facch=0;
int facch2=0;
int sacch=0;
int cac=0;
int voice = 0;
int facch = 0;
int facch2 = 0;
int udch = 0;
int sacch = 0;
int cac = 0;
int sr_structure;
int sr_ran;
//new, and even more confusing NXDN Type-D / "IDAS" acronyms
int idas = 0;
int scch = 0;
int facch3 = 0;
int udch2 = 0;
//new breakdown of lich codes
uint8_t lich_rf = 0; //RF Channel Type
uint8_t lich_fc = 0; //Functional Channel Type
uint8_t lich_op = 0; //Options
uint8_t direction; //inbound or outbound direction
uint8_t lich_dibits[8];
uint8_t sacch_bits[60];
uint8_t facch_bits_a[144];
uint8_t facch_bits_b[144];
uint8_t cac_bits[300];
uint8_t facch2_bits[348]; //facch2 or udch, same amount of bits
uint8_t facch3_bits[288]; //facch3 or udch2, same amoount of bits
//nxdn bit buffer, for easy assignment handling
int nxdn_bit_buffer[364];
//nxdn bit buffer, for easy assignment handling
int nxdn_bit_buffer[364];
int nxdn_dibit_buffer[182];
//init all arrays
@@ -71,7 +85,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
memset (nxdn_dibit_buffer, 0, sizeof(nxdn_dibit_buffer));
//collect lich bits first, if they are good, then we can collect the rest of them
for (int i = 0; i < 8; i++) lich_dibits[i] = dbuf[i] = getDibit(opts, state);
for (int i = 0; i < 8; i++) lich_dibits[i] = dbuf[i] = getDibit(opts, state);
nxdn_descramble (lich_dibits, 8);
@@ -82,11 +96,9 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
lich_parity_computed = ((lich >> 7) + (lich >> 6) + (lich >> 5) + (lich >> 4)) & 1;
lich = lich >> 1;
if (lich_parity_received != lich_parity_computed)
{
// fprintf(stderr, "NXDN lich parity error, ignoring frame \n"); //debug
// state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
{
state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
goto END;
// return;
}
voice = 0;
@@ -100,7 +112,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
if (lich % 2 == 0 && opts->p25_trunk == 1)
{
if (opts->payload == 1) fprintf(stderr, " Simplex/Inbound NXDN lich on trunking system - type 0x%02X\n", lich);
// state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
goto END;
}
@@ -111,21 +123,20 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
break;
case 0x28: //facch2 types
case 0x29:
case 0x2e:
case 0x2f:
case 0x48:
case 0x49:
facch2 = 1;
break;
case 0x2e: //udch types
case 0x2f:
case 0x4e:
case 0x4f:
case 0x69:
case 0x6f:
facch2 = 1;
udch = 1;
break;
case 0x32: //facch in 1, vch in 2
case 0x33:
case 0x52:
case 0x53:
case 0x73:
voice = 2;
facch = 1;
sacch = 1;
@@ -133,8 +144,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
case 0x34: //vch in 1, facch in 2
case 0x35:
case 0x54:
case 0x55:
case 0x75:
case 0x55: //disabled for testing, IDAS system randomly triggers this one, probably due to poor signal
voice = 1;
facch = 2;
sacch = 1;
@@ -143,7 +153,6 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
case 0x37:
case 0x56:
case 0x57:
case 0x77:
voice = 3;
facch = 0;
sacch = 1;
@@ -156,8 +165,6 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
case 0x41:
case 0x50:
case 0x51:
case 0x61:
case 0x71:
voice = 0;
facch = 3;
sacch = 1;
@@ -166,6 +173,59 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
case 0x39:
sacch = 1;
break;
//NXDN "Type-D" or "IDAS" Specific Lich Codes
case 0x76: //normal vch voice (in one and two)
case 0x77:
idas = 1;
scch = 1;
voice = 3;
break;
case 0x74: //vch in 1, facch1 in 2 (facch 2 steal)
case 0x75:
idas = 1;
scch = 1;
voice = 1;
facch = 2;
break;
case 0x72: //facch in 1, vch in 2 (facch 1 steal)
case 0x73:
idas = 1;
scch = 1;
voice = 2;
facch = 1;
break;
case 0x70: //facch steal in vch 1 and vch 2 (during voice only)
case 0x71:
idas = 1;
scch = 1;
facch = 3;
break;
case 0x6E: //udch2
case 0x6F:
idas = 1;
scch = 1;
udch2 = 1;
break;
case 0x68:
case 0x69: //facch3
idas = 1;
scch = 1;
facch3 = 1;
break;
case 0x62:
case 0x63: //facch1 in 1, null data and post field in 2
idas = 1;
scch = 1;
facch = 1;
break;
case 0x60:
case 0x61: //facch1 in both (non vch)
idas = 1;
scch = 1;
facch = 3;
break;
default:
if (opts->payload == 1) fprintf(stderr, " false sync or unsupported NXDN lich type 0x%02X\n", lich);
//reset the sacch field, we probably got a false sync and need to wipe or give a bad crc
@@ -178,16 +238,24 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
} // end of switch(lich)
//printframesync after determining we have a good lich and it has something in it
if (voice || facch || sacch || facch2 || cac)
if (idas)
{
if (opts->frame_nxdn48 == 1)
{
printFrameSync (opts, state, "IDAS D ", 0, "-");
}
if (opts->payload == 1)
fprintf (stderr, "L%02X - ", lich);
}
else if (voice || facch || sacch || facch2 || cac)
{
// if (state->synctype == 28) fprintf (stderr, " +");
// else fprintf (stderr, " -");
if (opts->frame_nxdn48 == 1)
{
printFrameSync (opts, state, "NXDN48 ", 0, "-");
}
else printFrameSync (opts, state, "NXDN96 ", 0, "-");
if (opts->payload == 1) fprintf (stderr, "L%02X -", lich);
if (opts->payload == 1)
fprintf (stderr, "L%02X - ", lich);
}
//now that we have a good LICH, we can collect all of our dibits
@@ -206,7 +274,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
nxdn_bit_buffer[i*2+1] = dbuf[i] & 1;
}
//sacch
//sacch or scch bits
for (int i = 0; i < 60; i++)
{
sacch_bits[i] = nxdn_bit_buffer[i+16];
@@ -231,22 +299,64 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
facch2_bits[i] = nxdn_bit_buffer[i+16];
}
//udch2 or facch3
for (int i = 0; i < 288; i++)
{
facch3_bits[i] = nxdn_bit_buffer[i+16+60];
}
//vch frames stay inside dbuf, easier to assign that to ambe_fr frames
//sacch needs extra handling depending on superframe or non-superframe variety
//Add advanced decoding of LICH (RF, FC, OPT, and Direction
lich_rf = (lich >> 5) & 0x3;
lich_fc = (lich >> 3) & 0x3;
lich_op = (lich >> 1) & 0x3;
if (lich % 2 == 0) direction = 0;
else direction = 1;
// RF Channel Type
if (lich_rf == 0) fprintf (stderr, "RCCH ");
else if (lich_rf == 1) fprintf (stderr, "RTCH ");
else if (lich_rf == 2) fprintf (stderr, "RDCH ");
else
{
if (lich < 0x60) fprintf (stderr, "RTCH_C ");
else fprintf (stderr, "RTCH2 ");
}
// Functional Channel Type -- things start to get really convoluted here
// These will echo when handled, either with the decoded message type, or relevant crc err
// if (lich_rf == 0) //CAC Type
// {
// //Technically, we should be checking direction as well, but the fc never has split meaning on CAC
// if (lich_fc == 0) fprintf (stderr, "CAC ");
// else if (lich_fc == 1) fprintf (stderr, "Long CAC ");
// else if (lich_fc == 3) fprintf (stderr, "Short CAC ");
// else fprintf (stderr, "Reserved ");
// }
// else //USC Type
// {
// if (lich_fc == 0) fprintf (stderr, "NSF SACCH ");
// else if (lich_fc == 1) fprintf (stderr, "UDCH ");
// else if (lich_fc == 2) fprintf (stderr, "SF SACCH ");
// else if (lich_fc == 3) fprintf (stderr, "SF SACCH/IDLE ");
// }
//Option/Steal Flags echoed in Voice, V+F, or Data
if (voice && !facch) //voice only, no facch steal
{
fprintf (stderr, "%s", KGRN);
fprintf (stderr, " Voice ");
fprintf (stderr, "%s", KNRM);
}
else if (voice && facch) //voice with facch steal
else if (voice && facch) //voice with facch1 steal
{
fprintf (stderr, "%s", KGRN);
fprintf (stderr, " V%d+F%d ", 3 - facch, facch); //print which position on each
fprintf (stderr, "%s", KNRM);
}
else
else //Covers FACCH1 in both, FACCH2, UDCH, UDCH2, CAC
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Data ");
@@ -284,16 +394,22 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
if (lich == 0x20 || lich == 0x21 || lich == 0x61 || lich == 0x40 || lich == 0x41) state->nxdn_sacch_non_superframe = TRUE;
else state->nxdn_sacch_non_superframe = FALSE;
if (sacch) nxdn_deperm_sacch(opts, state, sacch_bits);
if (cac) nxdn_deperm_cac(opts, state, cac_bits);
if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits);
//TODO Later: Add Direction and/or LICH to all decoding functions
if (scch) nxdn_deperm_scch (opts, state, sacch_bits, direction);
//testing purposes -- don't run facch steals on enc -- causing issues with key loader (VCALL_ASSGN_DUP)
if (state->nxdn_cipher_type == 0 || state->R == 0) //!voice
{
if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
}
if (udch2) nxdn_deperm_facch3_udch2(opts, state, facch3_bits, 0);
if (facch3) nxdn_deperm_facch3_udch2(opts, state, facch3_bits, 1);
if (sacch) nxdn_deperm_sacch(opts, state, sacch_bits);
if (cac) nxdn_deperm_cac(opts, state, cac_bits);
//Seperated UDCH user data from facch2 data
if (udch) nxdn_deperm_facch2_udch(opts, state, facch2_bits, 0);
if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits, 1);
//SHOULD be okay to run facch1's again on steal frames, will need testing
if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
if (voice)
{
@@ -301,26 +417,29 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
//update last voice sync time
state->last_vc_sync_time = time(NULL);
//turn on scrambler if forced by user option
if (state->M == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
//process voice frame
nxdn_voice (opts, state, voice, dbuf);
}
//close MBE file if no voice and its open
if (!voice)
{
if (opts->mbe_out_f != NULL)
{
if (opts->frame_nxdn96 == 1) //nxdn96 has voice and data mixed together, so we will need to do a time check first
if (opts->frame_nxdn96 == 1) //nxdn96 has pure voice and data frames mixed together, so we will need to do a time check first
{
if ( (time(NULL) - state->last_vc_sync_time) > 1) //test for optimal time, 1 sec should be okay
{
closeMbeOutFile (opts, state);
}
}
if (opts->frame_nxdn48 == 1) closeMbeOutFile (opts, state); //okay to close right away if nxdn48, no data/voice mixing
if (opts->frame_nxdn48 == 1) closeMbeOutFile (opts, state); //okay to close right away if nxdn48, no data/voice frames mixing
}
}
if (voice && facch == 2) //facch steal 2 -- after voice
if (voice && facch == 2) //facch steal 2 -- after voice 1
{
//roll the voice scrambler LFSR here if key available to advance seed -- half rotation on a facch steal
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
@@ -334,7 +453,8 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
}
}
if (opts->payload == 1 && !voice) fprintf (stderr, "\n");
else if (opts->payload == 0) fprintf (stderr, "\n");
fprintf (stderr, "\n");
END: ; //do nothing
}

View File

@@ -2,7 +2,7 @@
* p25_frequency.c
* P25 Channel to Frequency Calculator
*
* NXDN Channel to Frequency, Courtesy of IcomIcR20 and EricCottrell (base values)
* NXDN Channel to Frequency Calculator
*
* LWVMOBILE
* 2022-11 DSD-FME Florida Man Edition
@@ -59,16 +59,16 @@ long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channe
}
//NXDN Channel to Frequency, Courtesy of IcomIcR20 on RR Forums
long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t channel)
{
long int freq;
long int base = 0;
long int step = 0;
//the base freq value is per EricCottrell in the Understanding NXDN Trunking Forum Thread
//will need to do some research or tests to confirm these values are accurate
//reworked to include Direct Frequency Assignment if available
//first, check channel map
//first, check channel map for imported value, DFA systems most likely won't need an import,
//unless it has 'system definable' attributes
if (state->trunk_chan_map[channel] != 0)
{
freq = state->trunk_chan_map[channel];
@@ -76,42 +76,41 @@ long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t
return (freq);
}
//then, let's see if its DFA instead -- 6.5.36
else if (state->nxdn_rcn == 1)
{
//determine the base frequency in Hz
if (state->nxdn_base_freq == 1) base = 100000000; //100 MHz
else if (state->nxdn_base_freq == 2) base = 330000000; //330 Mhz
else if (state->nxdn_base_freq == 3) base = 400000000; //400 Mhz
else if (state->nxdn_base_freq == 4) base = 750000000; //750 Mhz
else base = 0; //just set to zero, will be system definable most likely and won't be able to calc
//determine the step value in Hz
if (state->nxdn_step = 2) step = 1250; //1.25 kHz
else if (state->nxdn_step = 3) step = 3125; //3.125 kHz
else step = 0; //just set to zero, will be system definable most likely and won't be able to calc
//if we have a valid base and step, then calc frequency
//6.5.45. Outbound/Inbound Frequency Number (OFN/IFN)
if (base && step)
{
freq = base + (channel * step);
fprintf (stderr, "\n DFA Frequency [%.6lf] MHz", (double)freq/1000000);
return (freq);
}
else
{
fprintf(stderr, "\n Custom DFA Settings -- Unknown Freq;");
return (0);
}
}
else
{
fprintf(stderr, "\n Channel not found in import file");
return (0);
}
//if not found, attempt to find it via calculation
//disabled, frequency 'band plan' isn't standard
//like originally believed
// else
// {
// if ((channel > 0) && (channel <= 400))
// {
// if (opts->frame_nxdn48 == 1) base = 450000000;
// else base = 451000000;
// freq = base + (channel - 1) * 12500;
// fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
// return (freq);
// }
// else if ((channel >= 401) && (channel <= 800))
// {
// if (opts->frame_nxdn48 == 1) base = 460000000;
// else base = 461000000;
// freq = base + (channel - 401) * 12500;
// fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
// return (freq);
// }
// else
// {
// fprintf(stderr, "\n Non-standard frequency or channel not found in import file");
// return (0);
// }
// }
}

View File

@@ -711,12 +711,23 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
}
else fprintf (stderr, "VCH S ");
//check to see when last voice activity occurred in order to allow tuning on phase 2
//mac_signal or mac_idle when no more voice activity on current channel
//this is primarily a fix for TDMA control channels that carry voice (Duke P25)
//but may also allow for chain tuning without returning to the control channel <--may be problematic since we can assign a p25_cc_freq from the pdu
if (duid_decoded == 13 && opts->p25_is_tuned == 1 && ((time(NULL) - state->last_vc_sync_time) > opts->trunk_hangtime) ) //version for MAC_SIGNAL only, no idle
{
opts->p25_is_tuned = 0;
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
}
if (duid_decoded == 0)
{
fprintf (stderr, " 4V %d", state->fourv_counter[state->currentslot]+1);
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0 &&
state->p2_wacn != 0xFFFFF && state->p2_cc != 0xFFF && state->p2_sysid != 0xFFF)
{
state->last_vc_sync_time = time(NULL);
process_4V (opts, state);
}
}
@@ -726,6 +737,7 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0 &&
state->p2_wacn != 0xFFFFF && state->p2_cc != 0xFFF && state->p2_sysid != 0xFFF)
{
state->last_vc_sync_time = time(NULL);
process_2V (opts, state);
}
}
@@ -823,22 +835,21 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
void processP2 (dsd_opts * opts, dsd_state * state)
{
state->dmr_stereo = 1;
//state->currentslot = 1;
p2_dibit_buffer (opts, state);
//look at our ISCH values and determine location in superframe before running frame scramble
for (framing_counter = 0; framing_counter < 4; framing_counter++) //12
for (framing_counter = 0; framing_counter < 4; framing_counter++)
{
process_ISCH (opts, state); //run ISCH in here so we know when to start descramble offset
//run ISCH in here so we know when to start descramble offset
process_ISCH (opts, state);
}
//set initial current slot depending on offset value
if (state->p2_scramble_offset % 2)
{
state->currentslot = 0;
state->currentslot = 1;
}
else state->currentslot = 1;
else state->currentslot = 0;
//frame_scramble runs lfsr and creates an array of unscrambled bits to pull from
process_Frame_Scramble (opts, state);

View File

@@ -13,6 +13,9 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
//Figure out which PDU we are looking at, see above info on 8.4.1
//reorganize bits into bytes and process accordingly
//new slot variable with flipped assignment for SACCH
uint8_t slot = (state->currentslot ^ 1) & 1;
unsigned long long int SMAC[24] = {0}; //22.5 bytes for SACCH MAC PDUs
int byte = 0;
int k = 0;
@@ -206,6 +209,9 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
//close any open MBEout files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
//blank the call string here -- slot variable is already flipped accordingly for sacch
sprintf (state->call_string[slot], "%s", " "); //21 spaces
}
if (state->currentslot == 0)
{
@@ -236,6 +242,10 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
fprintf (stderr, "%s", KYEL);
process_MAC_VPDU(opts, state, 1, SMAC);
fprintf (stderr, "%s", KNRM);
//blank the call string here -- slot variable is already flipped accordingly for sacch
sprintf (state->call_string[slot], "%s", " "); //21 spaces
}
if (opcode == 0x4 && err == 0)
{
@@ -280,6 +290,9 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
//Figure out which PDU we are looking at, see above info on 8.4.1
//reorganize bits into bytes and process accordingly
//new slot variable
uint8_t slot = state->currentslot;
unsigned long long int FMAC[24] = {0}; //19.5 bytes for FACCH MAC PDUs, add padding to end
int byte = 0;
int k = 0;
@@ -433,6 +446,9 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
//close any open MBEout files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
//blank the call string here
sprintf (state->call_string[slot], "%s", " "); //21 spaces
}
if (state->currentslot == 1)
@@ -484,6 +500,10 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
fprintf (stderr, "%s", KYEL);
process_MAC_VPDU(opts, state, 0, FMAC);
fprintf (stderr, "%s", KNRM);
//blank the call string here
sprintf (state->call_string[slot], "%s", " "); //21 spaces
}
if (opcode == 0x4 && err == 0)
{