mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
Compare commits
44 Commits
win32-rc4
...
win32-aero
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c42c50a40 | ||
|
|
36399386c5 | ||
|
|
8eee4cd699 | ||
|
|
1410e8bd81 | ||
|
|
915375fb1c | ||
|
|
52fff28dc4 | ||
|
|
bd035622b8 | ||
|
|
44163710f9 | ||
|
|
44b1ccdeae | ||
|
|
34113cb782 | ||
|
|
2a336a9275 | ||
|
|
5c08a9193c | ||
|
|
2cae7f9c18 | ||
|
|
e056c97d9d | ||
|
|
dc49e0d08b | ||
|
|
b639f6af28 | ||
|
|
6b45c4ba9b | ||
|
|
2062502a59 | ||
|
|
a490d9ead2 | ||
|
|
c73832ac2c | ||
|
|
fe1fa79f70 | ||
|
|
f2f29f2287 | ||
|
|
3181e58b19 | ||
|
|
6204aec2a5 | ||
|
|
267180ed0e | ||
|
|
8d9cbb3720 | ||
|
|
8af6d2e185 | ||
|
|
abeb92ff8a | ||
|
|
be47075611 | ||
|
|
1640b58ae4 | ||
|
|
7a34d531b1 | ||
|
|
0af814c72f | ||
|
|
1477190dea | ||
|
|
b0cd1881bb | ||
|
|
44ad75ec17 | ||
|
|
1ce487dc13 | ||
|
|
ed9a96fdc8 | ||
|
|
c677efda49 | ||
|
|
fea4f97b89 | ||
|
|
f2e3834e0a | ||
|
|
b8b62ef69a | ||
|
|
4a8a4a088a | ||
|
|
9308c5b251 | ||
|
|
cdfe9435d3 |
@@ -1,11 +1,24 @@
|
||||
project(dsd-fme-lite)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
#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)
|
||||
|
||||
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})
|
||||
@@ -38,24 +51,24 @@ list(APPEND SRCS "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c")
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
ADD_EXECUTABLE(dsd-fme-lite ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme-lite ${LIBS})
|
||||
ADD_EXECUTABLE(dsd-fme-aero ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme-aero ${LIBS})
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS dsd-fme-lite DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(TARGETS dsd-fme-aero DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# man page
|
||||
find_program(HELP2MAN_FOUND help2man)
|
||||
if (HELP2MAN_FOUND)
|
||||
add_custom_command(TARGET dsd-fme-lite POST_BUILD
|
||||
add_custom_command(TARGET dsd-fme-aero POST_BUILD
|
||||
COMMAND help2man
|
||||
ARGS -n "Digital Speech Decoder"
|
||||
--version-string=${GIT_TAG}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-lite.1
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-aero.1
|
||||
--no-info
|
||||
$<TARGET_FILE:dsd-fme-lite>
|
||||
$<TARGET_FILE:dsd-fme-aero>
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-lite.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-aero.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
|
||||
Binary file not shown.
@@ -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>
|
||||
@@ -325,7 +336,9 @@ typedef struct
|
||||
|
||||
int p25_trunk; //experimental P25 trunking with RIGCTL (or RTLFM)
|
||||
int p25_is_tuned; //set to 1 if currently on VC, set back to 0 if on CC
|
||||
int trunk_hangtime; //hangtime in seconds before tuning back to CC
|
||||
float trunk_hangtime; //hangtime in seconds before tuning back to CC
|
||||
|
||||
int scanner_mode; //experimental -- use the channel map as a conventional scanner, quicker tuning, but no CC
|
||||
|
||||
//csv import filenames
|
||||
char group_in_file[1024];
|
||||
@@ -538,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)
|
||||
@@ -595,6 +608,7 @@ typedef struct
|
||||
int p2_is_lcch; //flag to tell us when a frame is lcch and not sacch
|
||||
|
||||
//iden freq storage for frequency calculations
|
||||
int p25_chan_tdma[16]; //set from iden_up vs iden_up_tdma
|
||||
int p25_chan_iden;
|
||||
int p25_chan_type[16];
|
||||
int p25_trans_off[16];
|
||||
@@ -651,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];
|
||||
@@ -811,6 +833,9 @@ int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync);
|
||||
void upsample (dsd_state * state, float invalue);
|
||||
void processDSTAR (dsd_opts * opts, dsd_state * state);
|
||||
|
||||
//new p25lcw
|
||||
void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t irrecoverable_errors);
|
||||
|
||||
void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo);
|
||||
void processHDU (dsd_opts * opts, dsd_state * state);
|
||||
void processLDU1 (dsd_opts * opts, dsd_state * state);
|
||||
@@ -823,7 +848,8 @@ void processX2TDMAvoice (dsd_opts * opts, dsd_state * state);
|
||||
void processDSTAR_HD (dsd_opts * opts, dsd_state * state);
|
||||
void processYSF(dsd_opts * opts, dsd_state * state); //YSF
|
||||
void processP2(dsd_opts * opts, dsd_state * state); //P2
|
||||
void processTSBK(dsd_opts * opts, dsd_state * state);
|
||||
void processTSBK(dsd_opts * opts, dsd_state * state); //P25 Trunking Single Block
|
||||
void processMPDU(dsd_opts * opts, dsd_state * state); //P25 Multi Block PDU (SAP 0x61 FMT 0x15 or 0x17 for Trunking Blocks)
|
||||
short dmr_filter(short sample);
|
||||
short nxdn_filter(short sample);
|
||||
short dpmr_filter(short sample);
|
||||
@@ -839,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]);
|
||||
|
||||
@@ -852,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);
|
||||
@@ -874,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);
|
||||
|
||||
|
||||
12
install.sh
12
install.sh
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -128,12 +160,12 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
if (dpf == 15)
|
||||
{
|
||||
if (p_mfid == 0x10) sprintf (mfid_string, "%s", "Motorola");
|
||||
else if (p_mfid == 0x58) sprintf (mfid_string, "%s", "Tait ");
|
||||
else if (p_mfid == 0x68) sprintf (mfid_string, "%s", "Hytera ");
|
||||
else if (p_mfid == 0x08) sprintf (mfid_string, "%s", "Hytera ");
|
||||
else if (p_mfid == 0x58) sprintf (mfid_string, "%s", "Tait");
|
||||
else if (p_mfid == 0x68) sprintf (mfid_string, "%s", "Hytera");
|
||||
else if (p_mfid == 0x08) sprintf (mfid_string, "%s", "Hytera");
|
||||
else if (p_mfid == 0x06) sprintf (mfid_string, "%s", "Trid/Mot");
|
||||
else if (p_mfid == 0x00) sprintf (mfid_string, "%s", "Standard");
|
||||
else sprintf (mfid_string, "%s", "Other ");
|
||||
else sprintf (mfid_string, "%s", "Other");
|
||||
}
|
||||
|
||||
//udt format string handling
|
||||
@@ -324,6 +356,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
state->data_conf_data[slot] = 0;
|
||||
state->data_block_counter[slot] = 1;
|
||||
state->data_header_blocks[slot] = 1;
|
||||
state->data_header_format[slot] = 7;
|
||||
|
||||
}
|
||||
|
||||
@@ -384,7 +417,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
uint32_t CRCExtracted = 0;
|
||||
uint32_t IrrecoverableErrors = 0;
|
||||
|
||||
uint8_t dmr_pdu_sf_bits[8*8*50]; //give plenty of space so we don't go oob
|
||||
uint8_t dmr_pdu_sf_bits[8*24*50]; //give plenty of space so we don't go oob
|
||||
|
||||
//MBC Header and Block CRC
|
||||
uint8_t mbc_crc_good[2]; //header and blocks crc pass/fail local storage
|
||||
|
||||
@@ -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);
|
||||
|
||||
470
src/dmr_csbk.c
470
src/dmr_csbk.c
@@ -391,9 +391,12 @@ 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);
|
||||
|
||||
if (gi) fprintf (stderr, " Group");
|
||||
if (!gi) fprintf (stderr, " Private");
|
||||
|
||||
if (p_kind == 0) fprintf (stderr, " Disable Target PTT (DIS_PTT)");
|
||||
if (p_kind == 1) fprintf (stderr, " Enable Target PTT (EN_PTT)");
|
||||
if (p_kind == 2) fprintf (stderr, " Private Call (ILLEGALLY_PARKED)");
|
||||
if (p_kind == 2) fprintf (stderr, " Call (ILLEGALLY_PARKED)");
|
||||
if (p_kind == 3) fprintf (stderr, " Enable Target MS PTT (EN_PTT_ONE_MS)");
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
@@ -612,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
|
||||
|
||||
@@ -653,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)
|
||||
{
|
||||
|
||||
@@ -661,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));
|
||||
|
||||
@@ -672,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)
|
||||
{
|
||||
|
||||
@@ -687,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)
|
||||
@@ -700,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++;
|
||||
}
|
||||
@@ -747,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
|
||||
|
||||
@@ -854,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
|
||||
@@ -889,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
|
||||
@@ -949,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;
|
||||
@@ -1028,76 +1146,122 @@ 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+1, 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+1);
|
||||
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
|
||||
|
||||
//assign to cc freq to follow during no sync
|
||||
//current theory is that user should set channel 0 as the 'home repeater' frequency
|
||||
//this can change if this is ever tested by anybody properly
|
||||
if (state->trunk_chan_map[0] != 0)
|
||||
long int ccfreq = 0;
|
||||
|
||||
//if using rigctl we can set an unknown or updated cc frequency
|
||||
if (opts->use_rigctl == 1 )
|
||||
{
|
||||
state->p25_cc_freq = state->trunk_chan_map[0];
|
||||
//set to always tuned
|
||||
opts->p25_is_tuned = 1;
|
||||
ccfreq = GetCurrentFreq (opts->rigctl_sockfd);
|
||||
if (ccfreq != 0)
|
||||
{
|
||||
state->p25_cc_freq = ccfreq;
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//if using rtl input, we can ask for the current frequency tuned
|
||||
if (opts->audio_in_type == 3 )
|
||||
{
|
||||
ccfreq = (long int)opts->rtlsdr_center_freq;
|
||||
if (ccfreq != 0)
|
||||
{
|
||||
state->p25_cc_freq = ccfreq;
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Skip tuning calls if group calls are disabled
|
||||
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
|
||||
{
|
||||
@@ -1112,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);
|
||||
@@ -1120,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
|
||||
@@ -1138,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
|
||||
@@ -1155,15 +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
|
||||
|
||||
//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)
|
||||
{
|
||||
|
||||
@@ -1171,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
|
||||
|
||||
146
src/dmr_flco.c
146
src/dmr_flco.c
@@ -84,6 +84,14 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
if (slot == 0) state->dmr_flco = flco;
|
||||
else state->dmr_flcoR = flco;
|
||||
|
||||
//FID 0x10 and FLCO 0x14, 0x15, 0x16 and 0x17 confirmed as Moto EMB Alias
|
||||
//Can probably assume FID 0x10 FLCO 0x18 is Moto EMB GPS -- to be tested
|
||||
if ( fid == 0x10 && (flco == 0x14 || flco == 0x15 || flco == 0x16 || flco == 0x17 || flco == 0x18) )
|
||||
{
|
||||
flco = flco - 0x10;
|
||||
fid = 0;
|
||||
}
|
||||
|
||||
//Embedded Talker Alias Header Only (format and len storage)
|
||||
if ( (fid == 0 || fid == 0x68) && type == 3 && flco == 0x04)
|
||||
{
|
||||
@@ -113,8 +121,8 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16);
|
||||
}
|
||||
|
||||
//Unknown CapMax/Moto Things -- 0x14, 0x15, 0x16 are new ones on emb
|
||||
if (fid == 0x10 && (flco == 0x08 || flco == 0x28 || flco == 0x14 || flco == 0x15 || flco == 0x16))
|
||||
//Unknown CapMax/Moto Things
|
||||
if (fid == 0x10 && (flco == 0x08 || flco == 0x28))
|
||||
{
|
||||
//NOTE: fid 0x10 and flco 0x08 (emb) produces a lot of 'zero' bytes
|
||||
//this has been observed to happen often on CapMax systems, so I believe it could be some CapMax 'thing'
|
||||
@@ -164,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
|
||||
@@ -178,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;
|
||||
|
||||
@@ -190,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);
|
||||
|
||||
//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=%X ", xpt_int+1); //repeater channel to 'interrupt' with this call?
|
||||
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 Protect ");
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "F-Rpt %d", xpt_free+1);
|
||||
//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+1);
|
||||
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);
|
||||
@@ -369,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)
|
||||
@@ -395,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 ");
|
||||
@@ -541,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);
|
||||
}
|
||||
|
||||
@@ -897,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+1);
|
||||
// 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+1);
|
||||
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
|
||||
}
|
||||
|
||||
else fprintf (stderr, " SLCO Unknown - %d ", slco);
|
||||
@@ -955,6 +947,10 @@ void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_b
|
||||
uint8_t len = state->dmr_alias_len[slot];
|
||||
uint8_t start; //starting position depends on context of block and format
|
||||
|
||||
//Cap Max Variation
|
||||
uint8_t fid = (uint8_t)ConvertBitIntoBytes(&lc_bits[8], 8);
|
||||
if (fid == 0x10) block = block - 0x10; //CapMax adds 0x10 to its FLCO (block num) in its Embedded Aliasing
|
||||
|
||||
//there is some issue with the next three lines of code that prevent proper assignments, not sure what.
|
||||
//if (block > 4) start = 16;
|
||||
//else if (block == 4 && format > 0) start = 23; //8-bit and 16-bit chars
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -486,10 +486,6 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
state->currentslot = 0;
|
||||
sprintf (state->fsubtype, " LDU1 ");
|
||||
state->numtdulc = 0;
|
||||
if (state->payload_algid == 0x81)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
processLDU1 (opts, state);
|
||||
}
|
||||
@@ -542,8 +538,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
// state->lasttg = 0;
|
||||
// state->lastsrc = 0;
|
||||
state->lastp25type = 0;
|
||||
state->err_str[0] = 0;
|
||||
sprintf (state->fsubtype, " TDULC ");
|
||||
@@ -604,10 +600,11 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
else if (strcmp (duid, "30") == 0)
|
||||
{
|
||||
state->dmrburstL = 29;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," PDU\n"); //multi block/packet PDU
|
||||
fprintf (stderr," MBF\n"); //multi block format PDU
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
@@ -619,79 +616,11 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
resumeScan (opts, state);
|
||||
}
|
||||
state->lastp25type = 4;
|
||||
sprintf (state->fsubtype, " PDU ");
|
||||
sprintf (state->fsubtype, " MBF ");
|
||||
|
||||
processMPDU(opts, state);
|
||||
}
|
||||
|
||||
// try to guess based on previous frame if unknown type
|
||||
// disabling the guessing game on P1
|
||||
|
||||
// else if (state->lastp25type == 1)
|
||||
// {
|
||||
// if (opts->errorbars == 1)
|
||||
// {
|
||||
// printFrameInfo (opts, state);
|
||||
// fprintf (stderr,"(LDU2) ");
|
||||
// }
|
||||
// // if (opts->mbe_out_dir[0] != 0)
|
||||
// // {
|
||||
// // if (opts->mbe_out_f == NULL)
|
||||
// // {
|
||||
// // openMbeOutFile (opts, state);
|
||||
// // }
|
||||
// // }
|
||||
// //state->lastp25type = 0;
|
||||
// // Guess that the state is LDU2
|
||||
// state->lastp25type = 2;
|
||||
// sprintf (state->fsubtype, "(LDU2) ");
|
||||
// state->numtdulc = 0;
|
||||
// processLDU2 (opts, state);
|
||||
// }
|
||||
// else if (state->lastp25type == 2)
|
||||
// {
|
||||
// if (opts->errorbars == 1)
|
||||
// {
|
||||
// printFrameInfo (opts, state);
|
||||
// fprintf (stderr,"(LDU1) ");
|
||||
// }
|
||||
// if (opts->mbe_out_dir[0] != 0)
|
||||
// {
|
||||
// if (opts->mbe_out_f == NULL)
|
||||
// {
|
||||
// openMbeOutFile (opts, state);
|
||||
// }
|
||||
// }
|
||||
// //state->lastp25type = 0;
|
||||
// // Guess that the state is LDU1
|
||||
// state->lastp25type = 1;
|
||||
// sprintf (state->fsubtype, "(LDU1) ");
|
||||
// state->numtdulc = 0;
|
||||
// processLDU1 (opts, state);
|
||||
// }
|
||||
// else if (state->lastp25type == 3)
|
||||
// {
|
||||
// if (opts->errorbars == 1)
|
||||
// {
|
||||
// printFrameInfo (opts, state);
|
||||
// fprintf (stderr," (TSBK)\n");
|
||||
// }
|
||||
// //state->lastp25type = 0;
|
||||
// // Guess that the state is TSBK
|
||||
// state->lastp25type = 3;
|
||||
// sprintf (state->fsubtype, "(TSBK) ");
|
||||
|
||||
// // Now processing NID
|
||||
// skipDibit (opts, state, 328-25);
|
||||
// }
|
||||
// else if (state->lastp25type == 4)
|
||||
// {
|
||||
// if (opts->errorbars == 1)
|
||||
// {
|
||||
// printFrameInfo (opts, state);
|
||||
// fprintf (stderr," (PDU)\n");
|
||||
// }
|
||||
// state->lastp25type = 0;
|
||||
// }
|
||||
|
||||
else
|
||||
{
|
||||
state->lastp25type = 0;
|
||||
@@ -699,8 +628,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," duid:%s *Unknown DUID*\n", duid); //prints on dPMR frame 3
|
||||
// fprintf (stderr, "\n"); //prints on dPMR frame 3
|
||||
// fprintf (stderr," duid:%s *Unknown DUID*\n", duid);
|
||||
fprintf (stderr," duid:%s \n", duid); //DUID ERR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//start control channel hunting if using trunking, time needs updating on each successful sync
|
||||
//will need to assign frequencies to a CC array for P25 since that isn't imported from CSV
|
||||
if (state->dmr_rest_channel == -1 && opts->p25_is_tuned == 0 && opts->p25_trunk == 1 && ( (time(NULL) - state->last_cc_sync_time) > (opts->trunk_hangtime + 2) ) )
|
||||
if (state->dmr_rest_channel == -1 && opts->p25_is_tuned == 0 && opts->p25_trunk == 1 && ( (time(NULL) - state->last_cc_sync_time) > (opts->trunk_hangtime + 0) ) ) //was 3, go to hangtime value
|
||||
{
|
||||
|
||||
//test to switch back to 10/4 P1 QPSK for P25 FDMA CC
|
||||
@@ -163,10 +163,23 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
//start going through the lcn/frequencies CC/signal hunting
|
||||
fprintf (stderr, "Control Channel Signal Lost. Searching for Control Channel.\n");
|
||||
//make sure our current roll value doesn't exceed value of frequencies imported
|
||||
if (state->lcn_freq_roll > state->lcn_freq_count)
|
||||
if (state->lcn_freq_roll >= state->lcn_freq_count) //fixed this to skip the extra wait out at the end of the list
|
||||
{
|
||||
state->lcn_freq_roll = 0; //reset to zero
|
||||
}
|
||||
//roll an extra value up if the current is the same as what's already loaded -- faster hunting on Cap+, etc
|
||||
if (state->lcn_freq_roll != 0)
|
||||
{
|
||||
if (state->trunk_lcn_freq[state->lcn_freq_roll-1] == state->trunk_lcn_freq[state->lcn_freq_roll])
|
||||
{
|
||||
state->lcn_freq_roll++;
|
||||
//check roll again if greater than expected, then go back to zero
|
||||
if (state->lcn_freq_roll >= state->lcn_freq_count)
|
||||
{
|
||||
state->lcn_freq_roll = 0; //reset to zero
|
||||
}
|
||||
}
|
||||
}
|
||||
//check that we have a non zero value first, then tune next frequency
|
||||
if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0)
|
||||
{
|
||||
@@ -182,7 +195,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
rtl_udp_tune (opts, state, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
}
|
||||
|
||||
fprintf (stderr, "Tuning to Control Channel Frequency: %.06lf MHz\n",
|
||||
fprintf (stderr, "Tuning to Frequency: %.06lf MHz\n",
|
||||
(double)state->trunk_lcn_freq[state->lcn_freq_roll]/1000000);
|
||||
|
||||
}
|
||||
|
||||
162
src/dsd_main.c
162
src/dsd_main.c
@@ -52,7 +52,7 @@ char * FM_banner[9] = {
|
||||
" ██║ ██║ ╚═══██╗██║ ██║ ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
|
||||
" ██████╔╝██████╔╝██████╔╝ ██║ ██║ ╚═╝ ██║███████╗",
|
||||
" ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝",
|
||||
" 'Lite' Edition v2.0.0-40-gc999c97 Windows 32-bit RC4 "
|
||||
" 'Aero' Edition v2.0.0-84-gacd2b0b Windows 32-bit "
|
||||
};
|
||||
|
||||
int comp (const void *a, const void *b)
|
||||
@@ -77,6 +77,67 @@ void
|
||||
noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
// // experimental conventional frequency scanner mode
|
||||
// if (opts->scanner_mode == 1)
|
||||
// {
|
||||
|
||||
// if (state->lcn_freq_roll > state->lcn_freq_count) //with >= we were cutting one short
|
||||
// {
|
||||
// state->lcn_freq_roll = 0; //reset to zero
|
||||
// }
|
||||
// //check that we have a non zero value first, then tune next frequency
|
||||
// if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0)
|
||||
// {
|
||||
// //rigctl
|
||||
// if (opts->use_rigctl == 1)
|
||||
// {
|
||||
// if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
// SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
// }
|
||||
// //rtludp
|
||||
// if (opts->audio_in_type == 3)
|
||||
// {
|
||||
// rtl_udp_tune (opts, state, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
// }
|
||||
|
||||
// if (state->lastsynctype != -1) fprintf (stderr, "Resume Scanning Mode\n");
|
||||
|
||||
// }
|
||||
// state->lcn_freq_roll++;
|
||||
// }
|
||||
// //end experimental conventional frequency scanner mode
|
||||
|
||||
//experimental conventional frequency scanner mode
|
||||
if (opts->scanner_mode == 1 && ( (time(NULL) - state->last_cc_sync_time) > opts->trunk_hangtime))
|
||||
{
|
||||
|
||||
if (state->lcn_freq_roll >= state->lcn_freq_count)
|
||||
{
|
||||
state->lcn_freq_roll = 0; //reset to zero
|
||||
}
|
||||
//check that we have a non zero value first, then tune next frequency
|
||||
if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0)
|
||||
{
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
}
|
||||
//rtludp
|
||||
if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
}
|
||||
|
||||
if (state->lastsynctype != -1) fprintf (stderr, "Resume Scanning Mode\n");
|
||||
|
||||
}
|
||||
state->lcn_freq_roll++;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
}
|
||||
//end experimental conventional frequency scanner mode
|
||||
|
||||
//tune back to last known CC when using trunking after x second hangtime
|
||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && ( (time(NULL) - state->last_cc_sync_time) > opts->trunk_hangtime) )
|
||||
{
|
||||
@@ -173,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", "");
|
||||
@@ -501,7 +568,9 @@ initOpts (dsd_opts * opts)
|
||||
|
||||
opts->p25_trunk = 0; //0 disabled, 1 is enabled
|
||||
opts->p25_is_tuned = 0; //set to 1 if currently on VC, set back to 0 on carrier drop
|
||||
opts->trunk_hangtime = 1; //1 second hangtime by default before tuning back to CC
|
||||
opts->trunk_hangtime = 1; //1 second hangtime by default before tuning back to CC, going sub 1 sec causes issues with cc slip
|
||||
|
||||
opts->scanner_mode = 0; //0 disabled, 1 is enabled
|
||||
|
||||
//reverse mute
|
||||
opts->reverse_mute = 0;
|
||||
@@ -818,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;
|
||||
@@ -884,13 +961,13 @@ usage ()
|
||||
{
|
||||
|
||||
printf ("\n");
|
||||
printf ("Usage: dsd-fme-lite [options] Decoder/Trunking Mode\n");
|
||||
printf (" or: dsd-fme-lite [options] -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" or: dsd-fme-lite -h Show help\n");
|
||||
printf ("Usage: dsd-fme-aero [options] Decoder/Trunking Mode\n");
|
||||
printf (" or: dsd-fme-aero [options] -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" or: dsd-fme-aero -h Show help\n");
|
||||
printf ("\n");
|
||||
printf ("Display Options:\n");
|
||||
printf (" -N Use NCurses Terminal\n");
|
||||
printf (" dsd-fme-lite -N 2> log.ans \n");
|
||||
printf (" dsd-fme-aero -N 2> log.ans \n");
|
||||
printf (" -Z Log MBE/PDU Payloads to console\n");
|
||||
printf ("\n");
|
||||
printf ("Input/Output options:\n");
|
||||
@@ -935,7 +1012,7 @@ usage ()
|
||||
printf (" bw <num> RTL-SDR VFO Bandwidth kHz (default = 12)(6, 8, 12, 24) \n");
|
||||
printf (" sq <num> RTL-SDR Squelch Level (0 - Open, 25 - Little, 50 - Higher)\n");
|
||||
printf (" udp <num> RTL-SDR UDP Remote Port (default = 6020)\n");
|
||||
printf (" Example: dsd-fme-lite -fp -i rtl:0:851.375M:22:-2:12:0:6021\n");
|
||||
printf (" Example: dsd-fme-aero -fp -i rtl:0:851.375M:22:-2:12:0:6021\n");
|
||||
printf ("\n");
|
||||
printf ("Decoder options:\n");
|
||||
printf (" -fa Legacy Auto Detection (old methods default)\n");
|
||||
@@ -979,6 +1056,8 @@ usage ()
|
||||
printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n");
|
||||
printf (" -F Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n");
|
||||
printf (" Enabling on some systems could lead to bad voice/data decoding if bad or marginal signal\n");
|
||||
printf (" -F Relax NXDN SACCH/FACCH/CAC/F2U CRC Pass/Fail\n");
|
||||
printf (" Not recommended on NXDN, but can be bypassed if desired.\n");
|
||||
printf ("\n");
|
||||
printf (" -K <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
|
||||
printf ("\n");
|
||||
@@ -1002,6 +1081,9 @@ usage ()
|
||||
printf (" -G <file> Import Group List Allow/Block and Label from csv file.\n");
|
||||
printf (" (See group.csv for example)\n");
|
||||
printf (" -T Enable Trunking Features (NXDN/P25/EDACS/DMR) with RIGCTL/TCP or RTL Input\n");
|
||||
printf (" -Y Enable Fast Scanning Mode with RIGCTL/TCP or RTL Input (Lower z) \n");
|
||||
printf (" Experimental -- Can only scan for sync with enabled decoders, don't mix NXDN and DMR/P25!\n");
|
||||
printf (" This is not a Trunking Feature, just scans through conventional frequencies fast!\n");
|
||||
printf (" -W Use Imported Group List as a Trunking Allow/White List -- Only Tune with Mode A\n");
|
||||
printf (" -p Disable Tune to Private Calls (DMR TIII and P25)\n");
|
||||
printf (" -E Disable Tune to Group Calls (DMR TIII, Con+, Cap+ and P25)\n");
|
||||
@@ -1012,10 +1094,10 @@ usage ()
|
||||
printf (" -B <Hertz> Set RIGCTL Setmod Bandwidth in Hertz (0 - default - OFF)\n");
|
||||
printf (" P25 - 7000-12000; P25 (QPSK) - 12000; NXDN48 - 4000; DMR - 7000; EDACS/PV - 12500;\n");
|
||||
printf (" May vary based on system stregnth, etc.\n");
|
||||
printf (" -t <secs> Set Trunking VC/sync loss hangtime in seconds. (default = 1 second)\n");
|
||||
printf (" -t <secs> Set Trunking or Fast Scan VC/sync loss hangtime in seconds. (default = 1 second) (decimal values permitted) \n");
|
||||
printf ("\n");
|
||||
printf (" Trunking Example TCP: dsd-fme-lite -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf (" Trunking Example RTL: dsd-fme-lite -fs -i rtl:0:450M:26:-2:8:0:6020 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf (" Trunking Example TCP: dsd-fme-aero -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf (" Trunking Example RTL: dsd-fme-aero -fs -i rtl:0:450M:26:-2:8:0:6020 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf ("\n");
|
||||
exit (0);
|
||||
}
|
||||
@@ -1212,7 +1294,7 @@ main (int argc, char **argv)
|
||||
|
||||
exitflag = 0;
|
||||
|
||||
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:Y:K:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1)
|
||||
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:YK:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1)
|
||||
{
|
||||
opterr = 0;
|
||||
switch (c)
|
||||
@@ -1224,15 +1306,20 @@ main (int argc, char **argv)
|
||||
opts.call_alert = 1;
|
||||
break;
|
||||
|
||||
//Free'd up switches include Q,Y,z
|
||||
//Free'd up switches include
|
||||
//make sure to put a colon : after each if they need an argument
|
||||
//or remove colon if no argument required
|
||||
|
||||
case 'Y': //conventional scanner mode
|
||||
opts.scanner_mode = 1; //enable scanner
|
||||
opts.p25_trunk = 0; //turn off trunking mode if user enabled it
|
||||
break;
|
||||
|
||||
case 'k': //NXDN multi-key loader
|
||||
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
|
||||
@@ -1315,6 +1402,7 @@ main (int argc, char **argv)
|
||||
case 'T': //new letter assignment for trunking, flow down to allow temp numbers
|
||||
case '3':
|
||||
opts.p25_trunk = 1;
|
||||
opts.scanner_mode = 0; //turn off scanner mode if user enabled it
|
||||
break;
|
||||
|
||||
case 'U': //New letter assignment for RIGCTL TCP port, flow down to allow temp numbers
|
||||
@@ -1323,9 +1411,14 @@ main (int argc, char **argv)
|
||||
if (opts.rigctlportno != 0) opts.use_rigctl = 1;
|
||||
break;
|
||||
|
||||
//NOTE: I changed trunk_hangtime to a float, BUT! time(NULL) returns in second whole numbers
|
||||
//so using anything but whole numbers won't affect the outcome (rounded up?), in the future though,
|
||||
//may change to a different return on sync times and this will matter!
|
||||
|
||||
case 't': //New letter assignment for Trunk Hangtime, flow down to allow temp numbers
|
||||
case '6': //hangtime in seconds, default is 1;
|
||||
sscanf (optarg, "%d", &opts.trunk_hangtime);
|
||||
case '6': //hangtime in seconds, default is 1;
|
||||
sscanf (optarg, "%f", &opts.trunk_hangtime); //updated for float/decimal values
|
||||
fprintf (stderr, "Trunking or Fast Scanner Hang Time set to: %.02f sec\n", opts.trunk_hangtime);
|
||||
break;
|
||||
|
||||
case 'q': //New letter assignment for Reverse Mute, flow down to allow temp numbers
|
||||
@@ -1372,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':
|
||||
@@ -1465,6 +1550,7 @@ main (int argc, char **argv)
|
||||
//fprintf (stderr,"DMR Stereo Aggressive Resync Disabled!\n");
|
||||
fprintf (stderr, "Relax P25 Phase 2 MAC_SIGNAL CRC Checksum Pass/Fail\n");
|
||||
fprintf (stderr, "Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n");
|
||||
fprintf (stderr, "Relax NXDN SACCH/FACCH/CAC/F2U CRC Pass/Fail\n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
break;
|
||||
|
||||
@@ -1489,7 +1575,7 @@ main (int argc, char **argv)
|
||||
// fprintf (stderr,"Writing mbe data temporarily disabled!\n");
|
||||
break;
|
||||
|
||||
case 'c': //now is symbol capture bin output like FME Lite
|
||||
case 'c':
|
||||
strncpy(opts.symbol_out_file, optarg, 1023);
|
||||
opts.symbol_out_file[1023] = '\0';
|
||||
fprintf (stderr,"Writing + Appending symbol capture to file %s\n", opts.symbol_out_file);
|
||||
@@ -1612,7 +1698,7 @@ main (int argc, char **argv)
|
||||
opts.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
state.dmr_stereo = 0;
|
||||
opts.setmod_bw = 12500;
|
||||
// opts.setmod_bw = 12500;
|
||||
sprintf (opts.output_name, "EDACS/PV");
|
||||
fprintf (stderr,"Setting symbol rate to 9600 / second\n");
|
||||
fprintf (stderr,"Decoding only ProVoice frames.\n");
|
||||
@@ -1639,7 +1725,9 @@ main (int argc, char **argv)
|
||||
opts.dmr_mono = 0;
|
||||
opts.pulse_digi_rate_out = 48000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.setmod_bw = 12000;
|
||||
// opts.setmod_bw = 12000;
|
||||
opts.ssize = 36; //128 current default, fall back to old default on P1 only systems
|
||||
opts.msize = 15; //1024 current default, fall back to old default on P1 only systems
|
||||
sprintf (opts.output_name, "P25P1");
|
||||
fprintf (stderr,"Decoding only P25 Phase 1 frames.\n");
|
||||
}
|
||||
@@ -1720,7 +1808,7 @@ main (int argc, char **argv)
|
||||
opts.dmr_stereo = 1;
|
||||
state.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
opts.setmod_bw = 12000;
|
||||
// opts.setmod_bw = 12000;
|
||||
sprintf (opts.output_name, "P25P2");
|
||||
fprintf (stderr,"Decoding P25-P2 frames C4FM or OP25 Symbol Captures!\n");
|
||||
}
|
||||
@@ -1743,7 +1831,7 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 0;
|
||||
opts.dmr_stereo = 1;
|
||||
opts.dmr_mono = 0;
|
||||
opts.setmod_bw = 7000;
|
||||
// opts.setmod_bw = 7000;
|
||||
opts.pulse_digi_rate_out = 24000;
|
||||
opts.pulse_digi_out_channels = 2;
|
||||
sprintf (opts.output_name, "DMR Stereo");
|
||||
@@ -1771,7 +1859,7 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 0;
|
||||
opts.dmr_stereo = 1;
|
||||
opts.dmr_mono = 0;
|
||||
opts.setmod_bw = 12000; //safe default on both DMR and P25
|
||||
// opts.setmod_bw = 12000; //safe default on both DMR and P25
|
||||
opts.pulse_digi_rate_out = 24000;
|
||||
opts.pulse_digi_out_channels = 2;
|
||||
sprintf (opts.output_name, "XDMA");
|
||||
@@ -1823,7 +1911,7 @@ main (int argc, char **argv)
|
||||
opts.dmr_mono = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
state.dmr_stereo = 0; //0
|
||||
opts.setmod_bw = 7000;
|
||||
// opts.setmod_bw = 7000;
|
||||
sprintf (opts.output_name, "DMR Mono");
|
||||
fprintf(stderr, "Notice: DMR cannot autodetect polarity. \n Use -xr option if Inverted Signal expected.\n");
|
||||
fprintf (stderr,"Decoding only DMR Mono. \nUsing DMR Stereo '-fs' or XDMA '-ft' is highly encouraged.\n");
|
||||
@@ -1889,7 +1977,7 @@ main (int argc, char **argv)
|
||||
opts.mod_qpsk = 1;
|
||||
opts.mod_gfsk = 0;
|
||||
state.rf_mod = 1;
|
||||
opts.setmod_bw = 12000;
|
||||
// opts.setmod_bw = 12000;
|
||||
fprintf (stderr,"Enabling only QPSK modulation optimizations.\n");
|
||||
}
|
||||
else if (optarg[0] == '2')
|
||||
@@ -1900,7 +1988,7 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 1;
|
||||
state.samplesPerSymbol = 8;
|
||||
state.symbolCenter = 3;
|
||||
opts.setmod_bw = 12000;
|
||||
// opts.setmod_bw = 12000;
|
||||
fprintf (stderr,"Enabling 6000 sps P25p2 CQPSK.\n");
|
||||
}
|
||||
//test
|
||||
@@ -1912,7 +2000,7 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 0;
|
||||
state.samplesPerSymbol = 10;
|
||||
state.symbolCenter = 4;
|
||||
opts.setmod_bw = 12000;
|
||||
// opts.setmod_bw = 12000;
|
||||
fprintf (stderr,"Enabling 6000 sps P25p2 C4FM.\n");
|
||||
}
|
||||
else if (optarg[0] == '4')
|
||||
@@ -1923,7 +2011,7 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 0;
|
||||
state.samplesPerSymbol = 8;
|
||||
state.symbolCenter = 3;
|
||||
opts.setmod_bw = 12000;
|
||||
// opts.setmod_bw = 12000;
|
||||
fprintf (stderr,"Enabling 6000 sps P25p2 all optimizations.\n");
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -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->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
|
||||
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->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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 - Win32 %s \n", "v2.0.0-40-gc999c97 RC4");
|
||||
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 ", "Win32 RC4"); //printw (" %s \n", GIT_TAG);
|
||||
if (i == 6) printw (" %s \n", "v2.0.0-40-gc999c97"); //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
|
||||
@@ -2179,6 +2191,20 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw ("| Reverse Mute - Muting Unencrypted Voice\n");
|
||||
}
|
||||
if (opts->aggressive_framesync == 0) printw ("| Selective CRC ERR Bypass Enabled (RAS) \n");
|
||||
if (state->M == 1)
|
||||
{
|
||||
if (state->R != 0) printw ("| Forcing Key Priority -- NXDN Sc Key: %05lld \n", state->R);
|
||||
if (state->K != 0) printw ("| Forcing Key Priority -- Moto BP Key: %03lld \n", state->K);
|
||||
if (state->K1 != 0) printw ("| Forcing Key Priority -- tera BP Key: %016llX \n", state->K1);
|
||||
if (state->K != 0 && state->K1 != 0) printw ("| Warning! Multiple DMR Key Types Loaded! \n"); //warning may not be required
|
||||
}
|
||||
if (opts->scanner_mode == 1)
|
||||
{
|
||||
printw ("| Fast Scan Mode Enabled ");
|
||||
if (state->lcn_freq_roll != 0)
|
||||
printw (" - Frequency: [%.06lf] Mhz", (double)state->trunk_lcn_freq[state->lcn_freq_roll-1]/1000000);
|
||||
printw (" Speed: %.02lf sec \n", opts->trunk_hangtime); //not sure values less than 1 make a difference, may be system/environment dependent
|
||||
}
|
||||
|
||||
printw ("------------------------------------------------------------------------------\n");
|
||||
attroff(COLOR_PAIR(4));
|
||||
@@ -2241,45 +2267,53 @@ 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: [%4d] ", tgn);
|
||||
printw ("SRC: [%4d] ", src);
|
||||
printw ("TGT: [%5d] ", tgn);
|
||||
printw ("SRC: [%5d] ", src);
|
||||
if (state->nxdn_alias_block_segment[0][0] > 0)
|
||||
{
|
||||
printw ("ALIAS: [");
|
||||
@@ -2303,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)
|
||||
{
|
||||
@@ -2317,7 +2351,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (state->nxdn_cipher_type == 0x2 && state->carrier == 1)
|
||||
{
|
||||
printw ("IV: [%016llX]", state->payload_miN);
|
||||
attron(COLOR_PAIR(1));
|
||||
printw ("IV: [%016llX] ", state->payload_miN);
|
||||
attron(COLOR_PAIR(2));
|
||||
printw ("DES-OFB ");
|
||||
attroff(COLOR_PAIR(2));
|
||||
@@ -2325,7 +2360,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (state->nxdn_cipher_type == 0x3 && state->carrier == 1)
|
||||
{
|
||||
printw ("IV: [%016llX]", state->payload_miN);
|
||||
attron(COLOR_PAIR(1));
|
||||
printw ("IV: [%016llX] ", state->payload_miN);
|
||||
attron(COLOR_PAIR(2));
|
||||
printw ("AES-256 ");
|
||||
attroff(COLOR_PAIR(2));
|
||||
@@ -2481,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));
|
||||
@@ -2922,9 +2964,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw ("| %s ", SyncTypes[call_matrix[9-j][0]]);
|
||||
if (lls == 28 || lls == 29)
|
||||
{
|
||||
printw ("RAN [%2lld] ", call_matrix[9-j][1]);
|
||||
printw ("TG [%4lld] ", call_matrix[9-j][4]);
|
||||
printw ("RID [%4lld] ", call_matrix[9-j][2]);
|
||||
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]);
|
||||
}
|
||||
//dPMR
|
||||
if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27)
|
||||
@@ -2951,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]);
|
||||
@@ -3007,6 +3050,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
else opts->p25_trunk = 1;
|
||||
}
|
||||
|
||||
if (c == 121) //'y' key, toggle scanner mode
|
||||
{
|
||||
if (opts->scanner_mode == 1) opts->scanner_mode = 0;
|
||||
else opts->scanner_mode = 1;
|
||||
opts->p25_trunk = 0; //turn off trunking mode
|
||||
}
|
||||
|
||||
if (c == 97) //'a' key, toggle call alert beep
|
||||
{
|
||||
if (opts->call_alert == 1) opts->call_alert = 0;
|
||||
@@ -3193,38 +3243,103 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
// }
|
||||
//
|
||||
|
||||
// //Lockout bug in EDACS prevents any group from tuning when using this, not sure why yet
|
||||
// //WARNING! USE THESE WITH CAUTION! IF BREAKING ISSUES OBSERVED, THEN RESTART AND DON'T USE THEM!!
|
||||
if (opts->frame_provoice != 1 && c == 49) //'1' key, lockout slot 1 or conventional tg from tuning/playback during session
|
||||
|
||||
//test jumping back to CC on group lockout instead of random frequency to break framesync
|
||||
if (state->lasttg != 0 && opts->frame_provoice != 1 && c == 49) //'1' key, lockout slot 1 or conventional tg from tuning/playback during session
|
||||
{
|
||||
state->group_array[state->group_tally].groupNumber = state->lasttg;
|
||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "B");
|
||||
sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT");
|
||||
state->group_tally++;
|
||||
|
||||
//test tuning away to break sync, if not working so well, then disable
|
||||
//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));
|
||||
|
||||
//reset dmr blocks
|
||||
dmr_reset_blocks (opts, state);
|
||||
|
||||
//zero out additional items
|
||||
state->lasttg = 0;
|
||||
state->lasttgR = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lastsrcR = 0;
|
||||
state->payload_algid = 0;
|
||||
state->payload_algidR = 0;
|
||||
state->payload_keyid = 0;
|
||||
state->payload_keyidR = 0;
|
||||
state->payload_mi = 0;
|
||||
state->payload_miR = 0;
|
||||
state->payload_miP = 0;
|
||||
state->payload_miN = 0;
|
||||
opts->p25_is_tuned = 0;
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||
|
||||
//tune back to the control channel
|
||||
//RIGCTL
|
||||
if (opts->frame_provoice != 1 && opts->p25_is_tuned == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, 450000000);
|
||||
if (opts->p25_trunk == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||
|
||||
//rtl_udp
|
||||
if (opts->frame_provoice != 1 && opts->p25_is_tuned == 1 && opts->audio_in_type == 3) rtl_udp_tune (opts, state, 450000000);
|
||||
if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_udp_tune (opts, state, state->p25_cc_freq);
|
||||
|
||||
}
|
||||
|
||||
if (opts->frame_provoice != 1 && c == 50) //'2' key, lockout slot 2 tdma tgR from tuning/playback during session
|
||||
if (state->lasttgR != 0 && opts->frame_provoice != 1 && c == 50) //'2' key, lockout slot 2 tdma tgR from tuning/playback during session
|
||||
{
|
||||
state->group_array[state->group_tally].groupNumber = state->lasttgR;
|
||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "B");
|
||||
sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT");
|
||||
state->group_tally++;
|
||||
|
||||
//test tuning away to break sync, if not working so well, then disable
|
||||
//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));
|
||||
|
||||
//reset dmr blocks
|
||||
dmr_reset_blocks (opts, state);
|
||||
|
||||
//zero out additional items
|
||||
state->lasttg = 0;
|
||||
state->lasttgR = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lastsrcR = 0;
|
||||
state->payload_algid = 0;
|
||||
state->payload_algidR = 0;
|
||||
state->payload_keyid = 0;
|
||||
state->payload_keyidR = 0;
|
||||
state->payload_mi = 0;
|
||||
state->payload_miR = 0;
|
||||
state->payload_miP = 0;
|
||||
state->payload_miN = 0;
|
||||
opts->p25_is_tuned = 0;
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||
|
||||
//tune back to the control channel
|
||||
//RIGCTL
|
||||
if (opts->p25_is_tuned == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, 450000000);
|
||||
if (opts->p25_trunk == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||
|
||||
//rtl_udp
|
||||
if (opts->p25_is_tuned == 1 && opts->audio_in_type == 3) rtl_udp_tune (opts, state, 450000000);
|
||||
if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_udp_tune (opts, state, state->p25_cc_freq);
|
||||
|
||||
}
|
||||
|
||||
@@ -3279,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
|
||||
|
||||
@@ -42,7 +42,8 @@ static const int PARITY[] = {
|
||||
//decoding functions here
|
||||
void nxdn_descramble(uint8_t dibits[], int len)
|
||||
{
|
||||
for (int i=0; i<sizeof(scramble_t); i++) {
|
||||
for (int i=0; i<len; i++)
|
||||
{
|
||||
if (scramble_t[i] >= len)
|
||||
break;
|
||||
dibits[scramble_t[i]] ^= 0x2; // invert sign of scrambled dibits
|
||||
@@ -51,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];
|
||||
@@ -73,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));
|
||||
@@ -118,8 +121,16 @@ 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->payload == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
@@ -129,18 +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])
|
||||
{
|
||||
uint8_t deperm[60];
|
||||
uint8_t depunc[72];
|
||||
uint8_t trellis_buf[32];
|
||||
uint8_t answer[26];
|
||||
//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 crc6 on payload
|
||||
uint8_t check = 0; //value pulled from last 6 bits
|
||||
@@ -169,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));
|
||||
@@ -186,7 +202,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
}
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0U; i < 40U; i++)
|
||||
for (int i = 0U; i < 36U; i++) //40
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
@@ -195,7 +211,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
}
|
||||
|
||||
//stored as 5 bytes, will need to convert to trellis_buf after running
|
||||
CNXDNConvolution_chainback(m_data, 36U);
|
||||
CNXDNConvolution_chainback(m_data, 32U); //36
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
@@ -222,14 +238,29 @@ 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)
|
||||
{
|
||||
@@ -238,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));
|
||||
|
||||
}
|
||||
|
||||
@@ -249,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;
|
||||
@@ -260,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;
|
||||
@@ -296,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];
|
||||
}
|
||||
@@ -333,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));
|
||||
@@ -382,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,
|
||||
@@ -393,35 +449,57 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
}
|
||||
|
||||
if (crc == check)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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, 0, f2u_message_buffer);
|
||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
@@ -446,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));
|
||||
@@ -481,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
|
||||
@@ -490,12 +568,29 @@ 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)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
@@ -505,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 == 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 == 0x02) fprintf(stderr, " VCALL_REC_REQ");
|
||||
else if (MessageType == 0x03) fprintf(stderr, " VCALL_IV");
|
||||
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");
|
||||
@@ -539,24 +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
|
||||
//disable if random messages wipe out the alias
|
||||
if (MessageType == 0x08 || MessageType == 0x10) //idle, tx_rel
|
||||
//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
|
||||
@@ -668,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);
|
||||
}
|
||||
1210
src/nxdn_element.c
1210
src/nxdn_element.c
File diff suppressed because it is too large
Load Diff
278
src/nxdn_frame.c
278
src/nxdn_frame.c
@@ -32,53 +32,73 @@ 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;
|
||||
|
||||
uint8_t lich_dibits[8] = {0};
|
||||
uint8_t sacch_bits[60] = {0};
|
||||
uint8_t facch_bits_a[144] = {0};
|
||||
uint8_t facch_bits_b[144] = {0};
|
||||
uint8_t cac_bits[300] = {0};
|
||||
uint8_t facch2_bits[348] = {0}; //facch2 or udch, same amount of bits
|
||||
//new, and even more confusing NXDN Type-D / "IDAS" acronyms
|
||||
int idas = 0;
|
||||
int scch = 0;
|
||||
int facch3 = 0;
|
||||
int udch2 = 0;
|
||||
|
||||
//nxdn bit buffer, for easy assignment handling
|
||||
int nxdn_bit_buffer[364] = {0};
|
||||
int nxdn_dibit_buffer[182] = {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];
|
||||
int nxdn_dibit_buffer[182];
|
||||
|
||||
//init all arrays
|
||||
memset (dbuf, 0, sizeof(dbuf));
|
||||
memset (answer, 0, sizeof(answer));
|
||||
memset (sacch_answer, 0, sizeof(sacch_answer));
|
||||
memset (lich_dibits, 0, sizeof(lich_dibits));
|
||||
memset (sacch_bits, 0, sizeof(sacch_bits));
|
||||
memset (facch_bits_b, 0, sizeof(facch_bits_b));
|
||||
memset (facch_bits_a, 0, sizeof(facch_bits_a));
|
||||
memset (cac_bits, 0, sizeof(cac_bits));
|
||||
memset (facch2_bits, 0, sizeof(facch2_bits));
|
||||
|
||||
memset (nxdn_bit_buffer, 0, sizeof(nxdn_bit_buffer));
|
||||
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);
|
||||
|
||||
lich = 0;
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
lich |= (lich_dibits[i] >> 1) << (7-i);
|
||||
}
|
||||
for (int i=0; i<8; i++) lich |= (lich_dibits[i] >> 1) << (7-i);
|
||||
|
||||
lich_parity_received = lich & 1;
|
||||
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");
|
||||
return;
|
||||
{
|
||||
state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
|
||||
goto END;
|
||||
}
|
||||
|
||||
voice = 0;
|
||||
@@ -92,6 +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
|
||||
goto END;
|
||||
}
|
||||
|
||||
@@ -102,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;
|
||||
@@ -124,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;
|
||||
@@ -134,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;
|
||||
@@ -147,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;
|
||||
@@ -157,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
|
||||
@@ -169,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
|
||||
@@ -197,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];
|
||||
@@ -222,23 +299,71 @@ 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
|
||||
|
||||
if (voice)
|
||||
//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
|
||||
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 //Covers FACCH1 in both, FACCH2, UDCH, UDCH2, CAC
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Data ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//roll the voice scrambler LFSR here if key available to advance seed (usually just needed on NXDN96)
|
||||
if (state->nxdn_cipher_type == 0x1 && state->R != 0) //!voice, or voice == 0
|
||||
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
|
||||
{
|
||||
char ambe_temp[49] = {0};
|
||||
char ambe_d[49] = {0};
|
||||
@@ -248,41 +373,88 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (voice && facch == 1) //facch steal 1 -- before voice
|
||||
{
|
||||
//force scrambler here, but with unspecified key (just use what's loaded)
|
||||
if (state->M == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
|
||||
//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)
|
||||
{
|
||||
char ambe_temp[49] = {0};
|
||||
char ambe_d[49] = {0};
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
LFSRN(ambe_temp, ambe_d, 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);
|
||||
|
||||
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)
|
||||
{
|
||||
//restore MBE file open here
|
||||
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 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)
|
||||
{
|
||||
char ambe_temp[49] = {0};
|
||||
char ambe_d[49] = {0};
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
LFSRN(ambe_temp, ambe_d, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->payload == 1 && !voice) fprintf (stderr, "\n");
|
||||
else if (opts->payload == 0) fprintf (stderr, "\n");
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
END: ; //do nothing
|
||||
}
|
||||
|
||||
@@ -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,33 +76,41 @@ long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t
|
||||
return (freq);
|
||||
}
|
||||
|
||||
//if not found, attempt to find it via calculation
|
||||
else
|
||||
//then, let's see if its DFA instead -- 6.5.36
|
||||
else if (state->nxdn_rcn == 1)
|
||||
{
|
||||
if ((channel > 0) && (channel <= 400))
|
||||
{
|
||||
if (opts->frame_nxdn48 == 1) base = 450000000;
|
||||
else base = 451000000;
|
||||
//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
|
||||
|
||||
freq = base + (channel - 1) * 12500;
|
||||
fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
|
||||
//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 if ((channel >= 401) && (channel <= 800))
|
||||
else
|
||||
{
|
||||
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");
|
||||
fprintf(stderr, "\n Custom DFA Settings -- Unknown Freq;");
|
||||
return (0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "\n Channel not found in import file");
|
||||
return (0);
|
||||
}
|
||||
|
||||
}
|
||||
460
src/p25_lcw.c
460
src/p25_lcw.c
@@ -1,160 +1,340 @@
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo)
|
||||
//new p25_lcw function here -- TIA-102.AABF-D LCW Format Messages (if anybody wants to fill the rest out)
|
||||
void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t irrecoverable_errors)
|
||||
{
|
||||
uint8_t lc_format = (uint8_t)ConvertBitIntoBytes(&LCW_bits[0], 8); //format
|
||||
uint8_t lc_opcode = (uint8_t)ConvertBitIntoBytes(&LCW_bits[2], 8); //opcode portion of format
|
||||
uint8_t lc_mfid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[8], 8); //mfid
|
||||
uint8_t lc_svcopt = (uint8_t)ConvertBitIntoBytes(&LCW_bits[16], 8); //service options
|
||||
uint8_t lc_pf = LCW_bits[0]; //protect flag
|
||||
uint8_t lc_sf = LCW_bits[1]; //Implicit / Explicit MFID Format
|
||||
|
||||
char tgid[17], tmpstr[255];
|
||||
long talkgroup, source;
|
||||
int i, j;
|
||||
if (lc_pf == 1) //check the protect flag -- if set, its an encrypted lcw
|
||||
{
|
||||
fprintf (stderr, "%s",KRED);
|
||||
fprintf (stderr, " LCW Protected ");
|
||||
fprintf (stderr, "%s",KNRM);
|
||||
}
|
||||
|
||||
tgid[16] = 0;
|
||||
if (lc_pf == 0) //not protected/encrypted lcw
|
||||
{
|
||||
|
||||
if (opts->p25lc == 1)
|
||||
{
|
||||
fprintf (stderr, "lcformat: %s mfid: %s lcinfo: %s ", lcformat, mfid, lcinfo);
|
||||
if (opts->p25tg == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
if (opts->payload == 1) fprintf (stderr, " LCW");
|
||||
|
||||
if (strcmp (lcformat, "00000100") == 0)
|
||||
//check to see if we need to run these as MFID 0 or 1 only (standard)
|
||||
if (lc_mfid == 0 || lc_mfid == 1) //lc_mfid == 0
|
||||
{
|
||||
|
||||
// first tg is the active channel
|
||||
j = 0;
|
||||
for (i = 40; i < 52; i++)
|
||||
//check the service options on applicable formats
|
||||
if (lc_format == 0x4A || lc_format == 0x46 || lc_format == 0x45
|
||||
|| lc_format == 0x44 || lc_format == 0x03 || lc_format == 0x00)
|
||||
{
|
||||
|
||||
if (lc_svcopt & 0x80) fprintf (stderr, " Emergency");
|
||||
if (lc_svcopt & 0x40) fprintf (stderr, " Encrypted");
|
||||
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
{
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tg[state->tgcount][j] = lcinfo[i];
|
||||
}
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
if (lc_svcopt & 0x20) fprintf (stderr, " Duplex");
|
||||
if (lc_svcopt & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (lc_svcopt & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", lc_svcopt & 0x7); //call priority
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
state->lasttg = talkgroup;
|
||||
if (state->tgcount < 24)
|
||||
}
|
||||
|
||||
if (lc_format == 0x00)
|
||||
{
|
||||
fprintf (stderr, " Group Voice Channel User");
|
||||
uint8_t res = (uint8_t)ConvertBitIntoBytes(&LCW_bits[24], 7);
|
||||
uint8_t explicit = LCW_bits[24]; //explicit source id required == 1, full SUID on seperate LCW
|
||||
uint16_t group = (uint16_t)ConvertBitIntoBytes(&LCW_bits[32], 16);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
|
||||
fprintf (stderr, " - Group %d Source %d", group, source);
|
||||
|
||||
//don't set this when zero, annoying blink occurs in ncurses
|
||||
if (group != 0) state->lasttg = group;
|
||||
if (source != 0) state->lastsrc = source;
|
||||
|
||||
sprintf (state->call_string[0], " Group ");
|
||||
if (lc_svcopt & 0x80) strcat (state->call_string[0], " Emergency ");
|
||||
else if (lc_svcopt & 0x40) strcat (state->call_string[0], " Encrypted ");
|
||||
else strcat (state->call_string[0], " ");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x03)
|
||||
{
|
||||
fprintf (stderr, " Unit to Unit Voice Channel User");
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&LCW_bits[24], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
|
||||
fprintf (stderr, " - Target %d Source %d", target, source);
|
||||
|
||||
//don't set this when zero, annoying blink occurs in ncurses
|
||||
if (target != 0) state->lasttg = target;
|
||||
if (source != 0) state->lastsrc = source;
|
||||
|
||||
sprintf (state->call_string[0], " Private ");
|
||||
if (lc_svcopt & 0x80) strcat (state->call_string[0], " Emergency ");
|
||||
else if (lc_svcopt & 0x40) strcat (state->call_string[0], " Encrypted ");
|
||||
else strcat (state->call_string[0], " ");
|
||||
|
||||
}
|
||||
|
||||
//uses explicit bit?
|
||||
else if (lc_format == 0x42) //is this group only, or group and private?
|
||||
{
|
||||
fprintf (stderr, " Group Voice Channel Update - ");
|
||||
uint16_t channel1 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[8], 16);
|
||||
uint16_t group1 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[24], 16);
|
||||
uint16_t channel2 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[40], 16);
|
||||
uint16_t group2 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[56], 16);
|
||||
|
||||
if (channel1 && group1)
|
||||
{
|
||||
state->tgcount = state->tgcount + 1;
|
||||
}
|
||||
if (opts->p25tg == 1)
|
||||
{
|
||||
fprintf (stderr, "tg: %li ", talkgroup);
|
||||
fprintf (stderr, "Ch: %04X TG: %d; ", channel1, group1);
|
||||
sprintf (state->dmr_lrrp_gps[0], "Active Ch: %04X TG: %d;", channel1, group1);
|
||||
}
|
||||
|
||||
if (opts->p25tg == 1)
|
||||
if (channel2 && group2 && group1 != group2)
|
||||
{
|
||||
fprintf (stderr, "tg: %li ", talkgroup);
|
||||
|
||||
// the remaining 3 appear to be other active tg's on the system
|
||||
j = 0;
|
||||
for (i = 28; i < 40; i++)
|
||||
{
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
fprintf (stderr, "%li ", talkgroup);
|
||||
j = 0;
|
||||
for (i = 16; i < 28; i++)
|
||||
{
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
fprintf (stderr, "%li ", talkgroup);
|
||||
j = 0;
|
||||
for (i = 4; i < 16; i++)
|
||||
{
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
fprintf (stderr, "%li\n", talkgroup);
|
||||
fprintf (stderr, "Ch: %04X TG: %d; ", channel2, group2);
|
||||
sprintf (state->dmr_lrrp_gps[1], "Active Ch: %04X TG: %d;", channel2, group2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else if (lc_format == 0x44)
|
||||
{
|
||||
fprintf (stderr, " Group Voice Channel Update – Explicit");
|
||||
uint16_t group1 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[24], 16);
|
||||
uint16_t channelt = (uint16_t)ConvertBitIntoBytes(&LCW_bits[40], 16);
|
||||
uint16_t channelr = (uint16_t)ConvertBitIntoBytes(&LCW_bits[56], 16);
|
||||
fprintf (stderr, "Ch: %04X TG: %d; ", channelt, group1);
|
||||
}
|
||||
|
||||
else if (lc_format == 0x45)
|
||||
{
|
||||
fprintf (stderr, " Unit to Unit Answer Request");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x46)
|
||||
{
|
||||
fprintf (stderr, " Telephone Interconnect Voice Channel User");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x47)
|
||||
{
|
||||
fprintf (stderr, " Telephone Interconnect Answer Request");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x49)
|
||||
{
|
||||
fprintf (stderr, " Souce ID Extension");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x4A)
|
||||
{
|
||||
fprintf (stderr, " Unit to Unit Voice Channel User – Extended");
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&LCW_bits[16], 24);
|
||||
uint32_t suid = (uint32_t)ConvertBitIntoBytes(&LCW_bits[40], 24);
|
||||
fprintf (stderr, "TGT: %04X SUID: %d; ", target, suid);
|
||||
}
|
||||
|
||||
else if (lc_format == 0x50)
|
||||
{
|
||||
fprintf (stderr, " Group Affiliation Query");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x51)
|
||||
{
|
||||
fprintf (stderr, " Unit Registration Command");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x52) //wonder if anybody uses this if its deleted/obsolete
|
||||
{
|
||||
fprintf (stderr, " Unit Authentication Command - OBSOLETE");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x53)
|
||||
{
|
||||
fprintf (stderr, " Status Query");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x54)
|
||||
{
|
||||
fprintf (stderr, " Status Update");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x55)
|
||||
{
|
||||
fprintf (stderr, " Status Update");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x56)
|
||||
{
|
||||
fprintf (stderr, " Call Alert");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x57)
|
||||
{
|
||||
fprintf (stderr, " Extended Function Command");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x58)
|
||||
{
|
||||
fprintf (stderr, " Channel Identifier Update");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x59)
|
||||
{
|
||||
fprintf (stderr, " Channel Identifier Update VU");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x5A)
|
||||
{
|
||||
fprintf (stderr, " Status Update – Source ID Extension Required");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x5C)
|
||||
{
|
||||
fprintf (stderr, " Extended Function Command – Source ID Extension Required");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x60)
|
||||
{
|
||||
fprintf (stderr, " System Service Broadcast");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x61)
|
||||
{
|
||||
fprintf (stderr, " Secondary Control Channel Broadcast");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x62)
|
||||
{
|
||||
fprintf (stderr, " Adjacent Site Status Broadcast");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x63)
|
||||
{
|
||||
fprintf (stderr, " RFSS Status Broadcast");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x64)
|
||||
{
|
||||
fprintf (stderr, " Network Status Broadcast");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x65)
|
||||
{
|
||||
fprintf (stderr, " Protection Parameter Broadcast - OBSOLETE");
|
||||
}
|
||||
|
||||
|
||||
else if (lc_format == 0x66)
|
||||
{
|
||||
fprintf (stderr, " Secondary Control Channel Broadcast – Explicit (LCSCBX)");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x67) //explicit
|
||||
{
|
||||
fprintf (stderr, " Adjacent Site Status (LCASBX)");
|
||||
uint8_t lra = (uint8_t)ConvertBitIntoBytes(&LCW_bits[8], 8);
|
||||
uint16_t channelt = (uint16_t)ConvertBitIntoBytes(&LCW_bits[16], 16);
|
||||
uint8_t rfssid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[32], 8);
|
||||
uint8_t siteid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[40], 8);
|
||||
uint16_t channelr = (uint16_t)ConvertBitIntoBytes(&LCW_bits[48], 16);
|
||||
uint8_t cfva = (uint8_t)ConvertBitIntoBytes(&LCW_bits[64], 4);
|
||||
fprintf (stderr, " - RFSS %d Site %d CH %04X", rfssid, siteid, channelt);
|
||||
|
||||
//debug print only
|
||||
// fprintf (stderr, "\n ");
|
||||
// fprintf (stderr, " LRA [%02X] RFSS [%03d] SITE [%03d] CHAN-T [%04X] CHAN-R [%02X] CFVA [%X]\n ", lra, rfssid, siteid, channelt, channelr, cfva);
|
||||
// if (cfva & 0x8) fprintf (stderr, " Conventional");
|
||||
// if (cfva & 0x4) fprintf (stderr, " Failure Condition");
|
||||
// if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
|
||||
// else fprintf (stderr, " Last Known");
|
||||
if (cfva & 0x1) fprintf (stderr, "- Connection Active");
|
||||
// process_channel_to_freq (opts, state, channelt);
|
||||
//end debug, way too much for a simple link control line
|
||||
|
||||
|
||||
}
|
||||
|
||||
else if (lc_format == 0x68)
|
||||
{
|
||||
fprintf (stderr, " RFSS Status Broadcast – Explicit (LCRSBX)");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x69)
|
||||
{
|
||||
fprintf (stderr, " Network Status Broadcast – Explicit (LCNSBX)");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x6A)
|
||||
{
|
||||
fprintf (stderr, " Conventional Fallback");
|
||||
}
|
||||
|
||||
else if (lc_format == 0x6B)
|
||||
{
|
||||
fprintf (stderr, " Message Update – Source ID Extension Required");
|
||||
}
|
||||
|
||||
//tune back to CC here - save about 1-2 seconds
|
||||
else if (lc_format == 0x4F) //# Call Termination/Cancellation
|
||||
{
|
||||
fprintf (stderr, " Call Termination/Cancellation");
|
||||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
|
||||
{
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
// state->payload_miP = 0;
|
||||
//reset some strings
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
sprintf (state->dmr_lrrp_gps[0], "%s", ""); //this is used for active ch in p25 trunking
|
||||
sprintf (state->dmr_lrrp_gps[1], "%s", ""); //this is used for active ch in p25 trunking
|
||||
opts->p25_is_tuned = 0;
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||
}
|
||||
//rtl_udp
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
// state->payload_miP = 0;
|
||||
//reset some strings
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
sprintf (state->dmr_lrrp_gps[0], "%s", ""); //this is used for active ch in p25 trunking
|
||||
sprintf (state->dmr_lrrp_gps[1], "%s", ""); //this is used for active ch in p25 trunking
|
||||
opts->p25_is_tuned = 0;
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||
rtl_udp_tune (opts, state, state->p25_cc_freq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else fprintf (stderr, " Unknown Format %02X MFID %02X SVC %02X", lc_format, lc_mfid, lc_svcopt);
|
||||
}
|
||||
|
||||
else if (strcmp (lcformat, "00000000") == 0)
|
||||
{
|
||||
j = 0;
|
||||
if (strcmp (mfid, "10010000") == 0)
|
||||
{
|
||||
for (i = 20; i < 32; i++)
|
||||
{
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tg[state->tgcount][j] = lcinfo[i];
|
||||
}
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 16; i < 32; i++)
|
||||
{
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tg[state->tgcount][j] = lcinfo[i];
|
||||
}
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
state->lasttg = talkgroup;
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tgcount = state->tgcount + 1;
|
||||
}
|
||||
if (opts->p25tg == 1)
|
||||
{
|
||||
fprintf (stderr, "tg: %li ", talkgroup);
|
||||
}
|
||||
//not a duplicate, this one will print if not MFID 0 or 1
|
||||
else fprintf (stderr, " Unknown Format %02X MFID %02X ", lc_format, lc_mfid);
|
||||
}
|
||||
|
||||
//ending line break
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
j = 0;
|
||||
for (i = 32; i < 56; i++)
|
||||
{
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[24] = 0;
|
||||
source = strtol (tmpstr, NULL, 2);
|
||||
state->lastsrc = source;
|
||||
if (opts->p25tg == 1)
|
||||
{
|
||||
fprintf (stderr, "src: %li emr: %c\n", source, lcinfo[0]);
|
||||
}
|
||||
}
|
||||
else if ((opts->p25tg == 1) && (opts->p25lc == 1))
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
107
src/p25p1_hdu.c
107
src/p25p1_hdu.c
@@ -453,93 +453,40 @@ processHDU(dsd_opts* opts, dsd_state* state)
|
||||
status = getDibit (opts, state);
|
||||
//TODO: Do something useful with the status bits...
|
||||
|
||||
//if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, and no errors??
|
||||
if (state->carrier == 1)
|
||||
{
|
||||
algidhex = strtol (algid, NULL, 2);
|
||||
kidhex = strtol (kid, NULL, 2);
|
||||
|
||||
state->payload_algid = algidhex;
|
||||
state->payload_keyid = kidhex;
|
||||
//state->payload_mfid = ConvertBitIntoBytes(&mfid[0], 7);
|
||||
//state->payload_mfid = strtol (mfid, NULL, 2);
|
||||
|
||||
mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32);
|
||||
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
|
||||
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
|
||||
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
|
||||
state->payload_miP = (mihex1 << 32) | (mihex2);
|
||||
}
|
||||
algidhex = strtol (algid, NULL, 2);
|
||||
kidhex = strtol (kid, NULL, 2);
|
||||
mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32);
|
||||
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
|
||||
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
|
||||
|
||||
//set vc counter to 0
|
||||
state->p25vc = 0;
|
||||
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
|
||||
if (irrecoverable_errors == 0)
|
||||
{
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX MFID: 0x%02X", algidhex, kidhex, mihex1, mihex2, mihex3, state->payload_mfid);
|
||||
fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
state->payload_algid = algidhex;
|
||||
state->payload_keyid = kidhex;
|
||||
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
|
||||
state->payload_miP = (mihex1 << 32) | (mihex2);
|
||||
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " ENC");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " ENC \n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (opts->p25enc == 1 && opts->payload == 0)
|
||||
{
|
||||
algidhex = strtol (algid, NULL, 2);
|
||||
kidhex = strtol (kid, NULL, 2);
|
||||
}
|
||||
if (opts->p25lc == 1)
|
||||
{
|
||||
fprintf (stderr, "mfid: %s tgid: %s ", mfid, tgid);
|
||||
if (opts->p25tg == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
j = 0;
|
||||
if (strcmp (mfid, "10010000") == 0)
|
||||
{
|
||||
for (i = 4; i < 16; i++)
|
||||
{
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tg[state->tgcount][j] = tgid[i];
|
||||
}
|
||||
tmpstr[j] = tgid[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = '0';
|
||||
tmpstr[13] = '0';
|
||||
tmpstr[14] = '0';
|
||||
tmpstr[15] = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tg[state->tgcount][j] = tgid[i];
|
||||
}
|
||||
tmpstr[j] = tgid[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
state->lasttg = talkgroup;
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tgcount = state->tgcount + 1;
|
||||
}
|
||||
if (opts->p25tg == 1)
|
||||
{
|
||||
fprintf (stderr, "tg: %li\n", talkgroup);
|
||||
}
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " HDU FEC ERR \n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -324,15 +324,53 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
lcinfo[54] = hex_data[ 0][4] + '0';
|
||||
lcinfo[55] = hex_data[ 0][5] + '0';
|
||||
|
||||
unsigned long long int lcinfohex = 0;
|
||||
if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, otherwise, garbage values may be collected
|
||||
{
|
||||
state->payload_mfid = strtol (mfid, NULL, 2);
|
||||
int j;
|
||||
uint8_t LCW_bytes[9];
|
||||
uint8_t LCW_bits[72];
|
||||
memset (LCW_bytes, 0, sizeof(LCW_bytes));
|
||||
memset (LCW_bits, 0, sizeof(LCW_bits));
|
||||
|
||||
//state->payload_mfid = ConvertBitIntoBytes(&mfid[0], 7);
|
||||
lcinfohex = ConvertBitIntoBytes(&lcinfo[0], 55);
|
||||
//fprintf (stderr, " LDU1 LCINFO %16llX \n", lcinfohex);
|
||||
//load array above into byte form first
|
||||
LCW_bytes[0] = (uint8_t) ConvertBitIntoBytes(&lcformat[0], 8);
|
||||
LCW_bytes[1] = (uint8_t) ConvertBitIntoBytes(&mfid[0], 8);
|
||||
for (i = 0; i < 7; i++) LCW_bytes[i+2] = (uint8_t) ConvertBitIntoBytes(&lcinfo[i*8], 8);
|
||||
|
||||
//load as bit array next (easier to process data in bit form)
|
||||
for(i = 0, j = 0; i < 9; i++, j+=8)
|
||||
{
|
||||
LCW_bits[j + 0] = (LCW_bytes[i] >> 7) & 0x01;
|
||||
LCW_bits[j + 1] = (LCW_bytes[i] >> 6) & 0x01;
|
||||
LCW_bits[j + 2] = (LCW_bytes[i] >> 5) & 0x01;
|
||||
LCW_bits[j + 3] = (LCW_bytes[i] >> 4) & 0x01;
|
||||
LCW_bits[j + 4] = (LCW_bytes[i] >> 3) & 0x01;
|
||||
LCW_bits[j + 5] = (LCW_bytes[i] >> 2) & 0x01;
|
||||
LCW_bits[j + 6] = (LCW_bytes[i] >> 1) & 0x01;
|
||||
LCW_bits[j + 7] = (LCW_bytes[i] >> 0) & 0x01;
|
||||
}
|
||||
|
||||
//send to new P25 LCW function
|
||||
if (irrecoverable_errors == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
p25_lcw (opts, state, LCW_bits, 0);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s",KRED);
|
||||
fprintf (stderr, " LCW FEC ERR ");
|
||||
fprintf (stderr, "%s\n", KNRM);
|
||||
}
|
||||
|
||||
processP25lcw (opts, state, lcformat, mfid, lcinfo);
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
fprintf (stderr, " P25 LCW Payload ");
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", LCW_bytes[i]);
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s\n", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,37 +357,37 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
kid[14] = hex_data[ 0][4] + '0';
|
||||
kid[15] = hex_data[ 0][5] + '0';
|
||||
|
||||
algidhex = strtol (algid, NULL, 2);
|
||||
kidhex = strtol (kid, NULL, 2);
|
||||
mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32);
|
||||
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
|
||||
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
|
||||
|
||||
//if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, and no errors??
|
||||
if (state->carrier == 1)
|
||||
{
|
||||
|
||||
algidhex = strtol (algid, NULL, 2);
|
||||
kidhex = strtol (kid, NULL, 2);
|
||||
|
||||
state->payload_algid = algidhex;
|
||||
state->payload_keyid = kidhex;
|
||||
|
||||
mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32);
|
||||
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
|
||||
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
|
||||
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
|
||||
state->payload_miP = (mihex1 << 32) | (mihex2);
|
||||
|
||||
}
|
||||
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
|
||||
if (irrecoverable_errors == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
|
||||
state->payload_algid = algidhex;
|
||||
state->payload_keyid = kidhex;
|
||||
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
|
||||
state->payload_miP = (mihex1 << 32) | (mihex2);
|
||||
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " ENC");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " ENC \n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " LDU2 FEC ERR \n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
463
src/p25p1_mdpu.c
Normal file
463
src/p25p1_mdpu.c
Normal file
@@ -0,0 +1,463 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* p25p1_mpdu.c
|
||||
* P25p1 Multi Block PDU and Multi Block Trunking
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2023-03 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
static uint32_t crc32mbf(uint8_t buf[], int len)
|
||||
{
|
||||
uint32_t g = 0x04c11db7;
|
||||
uint64_t crc = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
crc <<= 1;
|
||||
int b = ( buf [i / 8] >> (7 - (i % 8)) ) & 1;
|
||||
if (((crc >> 32) ^ b) & 1) crc ^= g;
|
||||
}
|
||||
crc = (crc & 0xffffffff) ^ 0xffffffff;
|
||||
return crc;
|
||||
}
|
||||
|
||||
void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int tsbkbit[196]; //tsbk bit array, 196 trellis encoded bits
|
||||
int tsbk_dibit[98];
|
||||
|
||||
memset (tsbkbit, 0, sizeof(tsbkbit));
|
||||
memset (tsbk_dibit, 0, sizeof(tsbk_dibit));
|
||||
|
||||
int dibit = 0;
|
||||
|
||||
uint8_t tsbk_byte[12]; //12 byte return from bd_bridge (block_deinterleave)
|
||||
memset (tsbk_byte, 0, sizeof(tsbk_byte));
|
||||
|
||||
unsigned long long int PDU[24];
|
||||
memset (PDU, 0, sizeof(PDU));
|
||||
|
||||
int tsbk_decoded_bits[190]; //decoded bits from tsbk_bytes for sending to crc16_lb_bridge
|
||||
memset (tsbk_decoded_bits, 0, sizeof(tsbk_decoded_bits));
|
||||
|
||||
uint8_t mpdu_decoded_bits[288];
|
||||
memset (mpdu_decoded_bits, 0, sizeof(mpdu_decoded_bits));
|
||||
|
||||
uint8_t mpdu_crc_bits[196];
|
||||
memset (mpdu_crc_bits, 0, sizeof(mpdu_crc_bits));
|
||||
|
||||
uint8_t mpdu_crc_bytes[24];
|
||||
memset (mpdu_crc_bytes, 0, sizeof(mpdu_crc_bytes));
|
||||
|
||||
int flushing_bits[196]; //for flushing the trellis state machine
|
||||
memset (flushing_bits, 0, sizeof(flushing_bits));
|
||||
|
||||
int i, j, k, b, x, y;
|
||||
int ec[3]; //error value returned from (block_deinterleave)
|
||||
int err[2]; //error value returned from ccrc16 or crc32
|
||||
memset (ec, -2, sizeof(ec));
|
||||
memset (err, -2, sizeof(err));
|
||||
|
||||
int skipdibit = 14; //initial status dibit will occur at 14, then add 36 each time it occurs
|
||||
int protectbit = 0;
|
||||
int MFID = 0xFF; //Manufacturer ID
|
||||
|
||||
uint8_t mpdu_byte[36];
|
||||
memset (mpdu_byte, 0, sizeof(mpdu_byte));
|
||||
|
||||
uint8_t io = 0;
|
||||
uint8_t fmt = 0;
|
||||
uint8_t sap = 0;
|
||||
uint8_t blks = 0;
|
||||
uint8_t opcode = 0;
|
||||
|
||||
//CRC32
|
||||
uint32_t CRCComputed = 0;
|
||||
uint32_t CRCExtracted = 0;
|
||||
|
||||
//collect three reps of 101 dibits (98 valid dibits with status dibits interlaced)
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
k = 0;
|
||||
for (i = 0; i < 101; i++)
|
||||
{
|
||||
|
||||
dibit = getDibit(opts, state);
|
||||
|
||||
if (i+(j*101) != skipdibit) //
|
||||
{
|
||||
tsbk_dibit[k] = dibit;
|
||||
tsbkbit[k*2] = (dibit >> 1) & 1;
|
||||
tsbkbit[k*2+1] = (dibit & 1);
|
||||
k++;
|
||||
}
|
||||
|
||||
if (i+(j*101) == skipdibit)
|
||||
{
|
||||
skipdibit += 36; //was set to 35, this was the bug
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//flushing the trellis state machine
|
||||
if (j == 0)
|
||||
{
|
||||
bd_bridge(flushing_bits, tsbk_byte);
|
||||
//reset tsbk_byte afterwards
|
||||
memset (tsbk_byte, 0, sizeof(tsbk_byte));
|
||||
}
|
||||
|
||||
//send tsbkbit to block_deinterleave and return tsbk_byte
|
||||
ec[j] = bd_bridge(tsbkbit, tsbk_byte);
|
||||
|
||||
//too many bit manipulations!
|
||||
k = 0;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
for (x = 0; x < 8; x++)
|
||||
{
|
||||
tsbk_decoded_bits[k] = ((tsbk_byte[i] << x) & 0x80) >> 7;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
//CRC16 on the header
|
||||
if (j == 0) err[0] = crc16_lb_bridge(tsbk_decoded_bits, 80);
|
||||
|
||||
//load into bit array for storage (easier decoding for future PDUs)
|
||||
for (i = 0; i < 96; i++) mpdu_decoded_bits[i+(j*96)] = (uint8_t)tsbk_decoded_bits[i];
|
||||
|
||||
//shuffle corrected bits back into tsbk_byte
|
||||
k = 0;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
int byte = 0;
|
||||
for (x = 0; x < 8; x++)
|
||||
{
|
||||
byte = byte << 1;
|
||||
byte = byte | tsbk_decoded_bits[k];
|
||||
k++;
|
||||
}
|
||||
tsbk_byte[i] = byte;
|
||||
mpdu_byte[i+(j*12)] = byte; //add to completed MBF format bytes
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
io = (mpdu_byte[0] >> 5) & 0x1;
|
||||
fmt = mpdu_byte[0] & 0x1F;
|
||||
sap = mpdu_byte[1] & 0x3F;
|
||||
blks = mpdu_byte[6] & 0x7F;
|
||||
MFID = mpdu_byte[2];
|
||||
|
||||
//group list mode so we can look and see if we need to block tuning any groups, etc
|
||||
char mode[8]; //allow, block, digital, enc, etc
|
||||
|
||||
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||
//comparison below will look for an 'A' to write to mode if it is allowed
|
||||
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
|
||||
|
||||
fprintf (stderr, "%s",KGRN);
|
||||
fprintf (stderr, " P25 MBF FMT: %02X SAP: %02X", fmt, sap);
|
||||
fprintf (stderr, " Blocks: %02X MFID: %02X", blks, MFID);
|
||||
|
||||
//trunking blocks
|
||||
if ((sap == 0x3D) && ((fmt == 0x17) || (fmt == 0x15)))
|
||||
{
|
||||
if (fmt == 0x15) fprintf (stderr, " UNC");
|
||||
else fprintf (stderr, " ALT");
|
||||
fprintf (stderr, " MBT"); //find way to convert to vPDU or TSBK format?
|
||||
if (fmt == 0x17) opcode = mpdu_byte[7] & 0x3F; //alt MBT
|
||||
else opcode = mpdu_byte[12] & 0x3F; //unconf MBT
|
||||
fprintf (stderr, " - OP: %02X", opcode);
|
||||
}
|
||||
|
||||
//CRC32 is now working!
|
||||
for (i = 0; i < 196; i++) mpdu_crc_bits[i] = mpdu_decoded_bits[i+96];
|
||||
for (i = 0; i < 24; i++) mpdu_crc_bytes[i] = mpdu_byte[i+12];
|
||||
if (blks == 1) //blocks to follow is 1
|
||||
{
|
||||
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&mpdu_crc_bits[96-32], 32);
|
||||
CRCComputed = crc32mbf(mpdu_crc_bytes, 96-32);
|
||||
if (CRCComputed == CRCExtracted) err[1] = 0;
|
||||
}
|
||||
if (blks == 2) //blocks to follow is 2
|
||||
{
|
||||
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&mpdu_crc_bits[192-32], 32);
|
||||
CRCComputed = crc32mbf(mpdu_crc_bytes, 192-32);
|
||||
if (CRCComputed == CRCExtracted) err[1] = 0;
|
||||
}
|
||||
|
||||
//just going to do a couple for now -- the extended format will not be vPDU compatible :(
|
||||
if (err[0] == 0 && err[1] == 0 && io == 1 && fmt == 0x17) //ALT Format
|
||||
{
|
||||
//NET_STS_BCST -- TIA-102.AABC-D 6.2.11.2
|
||||
if (opcode == 0x3B)
|
||||
{
|
||||
int lra = mpdu_byte[3];
|
||||
int sysid = ((mpdu_byte[4] & 0xF) << 8) | mpdu_byte[5];
|
||||
int res_a = mpdu_byte[8];
|
||||
int res_b = mpdu_byte[9];
|
||||
long int wacn = (mpdu_byte[12] << 12) | (mpdu_byte[13] << 4) | (mpdu_byte[14] >> 4);
|
||||
int channelt = (mpdu_byte[15] << 8) | mpdu_byte[16];
|
||||
int channelr = (mpdu_byte[17] << 8) | mpdu_byte[18];
|
||||
int ssc = mpdu_byte[19];
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
fprintf (stderr, "\n Network Status Broadcast MBT - Extended \n");
|
||||
fprintf (stderr, " LRA [%02X] WACN [%05lX] SYSID [%03X] NAC [%03llX]\n", lra, wacn, sysid, state->p2_cc);
|
||||
fprintf (stderr, " CHAN-T [%04X] CHAN-R [%04X]", channelt, channelr);
|
||||
long int ct_freq = process_channel_to_freq(opts, state, channelt);
|
||||
long int cr_freq = process_channel_to_freq(opts, state, channelr);
|
||||
|
||||
state->p25_cc_freq = ct_freq;
|
||||
state->p25_cc_is_tdma = 0; //flag off for CC tuning purposes when system is qpsk
|
||||
|
||||
//place the cc freq into the list at index 0 if 0 is empty, or not the same,
|
||||
//so we can hunt for rotating CCs without user LCN list
|
||||
if (state->trunk_lcn_freq[0] == 0 || state->trunk_lcn_freq[0] != state->p25_cc_freq)
|
||||
{
|
||||
state->trunk_lcn_freq[0] = state->p25_cc_freq;
|
||||
}
|
||||
|
||||
//only set IF these values aren't already hard set by the user
|
||||
if (state->p2_hardset == 0)
|
||||
{
|
||||
state->p2_wacn = wacn;
|
||||
state->p2_sysid = sysid;
|
||||
}
|
||||
}
|
||||
//RFSS Status Broadcast - Extended 6.2.15.2
|
||||
else if (opcode == 0x3A)
|
||||
{
|
||||
int lra = mpdu_byte[3];
|
||||
int lsysid = ((mpdu_byte[4] & 0xF) << 8) | mpdu_byte[5];
|
||||
int rfssid = mpdu_byte[12];
|
||||
int siteid = mpdu_byte[13];
|
||||
int channelt = (mpdu_byte[14] << 8) | mpdu_byte[15];
|
||||
int channelr = (mpdu_byte[16] << 8) | mpdu_byte[17];
|
||||
int sysclass = mpdu_byte[18];
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
fprintf (stderr, "\n RFSS Status Broadcast MBF - Extended \n");
|
||||
fprintf (stderr, " LRA [%02X] SYSID [%03X] RFSS ID [%02X] SITE ID [%02X]\n CHAN-T [%04X] CHAN-R [%02X] SSC [%02X] ", lra, lsysid, rfssid, siteid, channelt, channelr, sysclass);
|
||||
process_channel_to_freq (opts, state, channelt);
|
||||
process_channel_to_freq (opts, state, channelr);
|
||||
|
||||
state->p2_siteid = siteid;
|
||||
state->p2_rfssid = rfssid;
|
||||
}
|
||||
|
||||
//Adjacent Status Broadcast (ADJ_STS_BCST) Extended 6.2.2.2
|
||||
else if (opcode == 0x3C)
|
||||
{
|
||||
int lra = mpdu_byte[3];
|
||||
int cfva = mpdu_byte[4] >> 4;
|
||||
int lsysid = ((mpdu_byte[4] & 0xF) << 8) | mpdu_byte[5];
|
||||
int rfssid = mpdu_byte[8];
|
||||
int siteid = mpdu_byte[9];
|
||||
int channelt = (mpdu_byte[12] << 8) | mpdu_byte[13];
|
||||
int channelr = (mpdu_byte[14] << 8) | mpdu_byte[15];
|
||||
int sysclass = mpdu_byte[16];
|
||||
long int wacn = (mpdu_byte[17] << 12) | (mpdu_byte[18] << 4) | (mpdu_byte[19] >> 4);
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
fprintf (stderr, "\n Adjacent Status Broadcast - Extended\n");
|
||||
fprintf (stderr, " LRA [%02X] CFVA [%X] RFSS[%03d] SYSID [%03X] SITE [%03X]\n CHAN-T [%04X] CHAN-R [%04X] SSC [%02X] WACN [%05lX]\n ", lra, cfva, rfssid, lsysid, siteid, channelt, channelr, sysclass, wacn);
|
||||
if (cfva & 0x8) fprintf (stderr, " Conventional");
|
||||
if (cfva & 0x4) fprintf (stderr, " Failure Condition");
|
||||
if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
|
||||
else fprintf (stderr, " Last Known");
|
||||
if (cfva & 0x1) fprintf (stderr, " Valid RFSS Connection Active");
|
||||
process_channel_to_freq (opts, state, channelt);
|
||||
process_channel_to_freq (opts, state, channelr);
|
||||
|
||||
}
|
||||
|
||||
//Group Voice Channel Grant - Extended
|
||||
else if (opcode == 0x0)
|
||||
{
|
||||
int svc = mpdu_byte[8]; //look up what these do!
|
||||
int channelt = (mpdu_byte[14] << 8) | mpdu_byte[15];
|
||||
int channelr = (mpdu_byte[16] << 8) | mpdu_byte[17];
|
||||
long int source = (mpdu_byte[3] << 16) |(mpdu_byte[4] << 8) | mpdu_byte[5];
|
||||
int group = (mpdu_byte[18] << 8) | mpdu_byte[19];
|
||||
long int freq1 = 0;
|
||||
long int freq2 = 0;
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
fprintf (stderr, "\n Group Voice Channel Grant Update - Extended");
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Group [%d][%04X]", svc, channelt, channelr, group, group);
|
||||
freq1 = process_channel_to_freq (opts, state, channelt);
|
||||
freq2 = process_channel_to_freq (opts, state, channelr);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[0], "Active Ch: %04X TG: %d", channelt, group);
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
if (state->group_array[i].groupNumber == group)
|
||||
{
|
||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||
strcpy (mode, state->group_array[i].groupMode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
{
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
}
|
||||
//rtl_udp
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Unit to Unit Voice Channel Grant - Extended
|
||||
else if (opcode == 0x6)
|
||||
{
|
||||
//I'm not doing EVERY element of this, just enough for tuning!
|
||||
int svc = mpdu_byte[8]; //look up what these do!
|
||||
int channelt = (mpdu_byte[22] << 8) | mpdu_byte[23];
|
||||
int channelr = (mpdu_byte[24] << 8) | mpdu_byte[25]; //optional!
|
||||
//using source and target address, not source and target id (is this correct?)
|
||||
long int source = (mpdu_byte[3] << 16) |(mpdu_byte[4] << 8) | mpdu_byte[5];
|
||||
long int target = (mpdu_byte[19] << 16) |(mpdu_byte[20] << 8) | mpdu_byte[21];
|
||||
long int freq1 = 0;
|
||||
long int freq2 = 0;
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
fprintf (stderr, "\n Unit to Unit Voice Channel Grant Update - Extended");
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Source [%ld][%04lX] Target [%ld][%04lX]", svc, channelt, channelr, source, source, target, target);
|
||||
freq1 = process_channel_to_freq (opts, state, channelt);
|
||||
freq2 = process_channel_to_freq (opts, state, channelr); //optional!
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[0], "Active Ch: %04X TGT: %ld;", channelt, target);
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
if (state->group_array[i].groupNumber == target)
|
||||
{
|
||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||
strcpy (mode, state->group_array[i].groupMode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Skip tuning private calls if group calls are disabled
|
||||
if (opts->trunk_tune_private_calls == 0) goto SKIPCALL;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
{
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
}
|
||||
//rtl_udp
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//convert mpdu_byte to vPDU format and get indication of what the message was
|
||||
PDU[0] = 0x0C; //P25p1 MB Duid 0x0C
|
||||
PDU[1] = opcode;
|
||||
PDU[2] = MFID;
|
||||
PDU[1] = PDU[1] ^ 0xC0; //flip bits to make it compatible with MAC_PDUs explicit format
|
||||
|
||||
//without any extra bytes filled in, we can atleast see what the MBT is supposed to be
|
||||
//Hopefully, no 0 value things will cause issues -- call grants, iden_up, etc!
|
||||
// fprintf (stderr, "%s",KYEL);
|
||||
// process_MAC_VPDU(opts, state, 0, PDU);
|
||||
// fprintf (stderr, "%s",KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
SKIPCALL: ; //do nothing
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
fprintf (stderr, "\n P25 MBF Payload \n ");
|
||||
for (i = 0; i < 36; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", mpdu_byte[i]);
|
||||
if (i == 11 || i == 23) fprintf (stderr, "\n ");
|
||||
|
||||
}
|
||||
fprintf (stderr, " CRC EXT %08X CMP %08X", CRCExtracted, CRCComputed);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
fprintf (stderr, "\n ");
|
||||
|
||||
//Header
|
||||
if (err[0] != 0)
|
||||
{
|
||||
fprintf (stderr, "%s",KRED);
|
||||
fprintf (stderr, " (HDR CRC16 ERR)");
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
}
|
||||
//Completed MBF
|
||||
if (err[1] != 0)
|
||||
{
|
||||
fprintf (stderr, "%s",KRED);
|
||||
fprintf (stderr, " (MBF CRC32 ERR)");
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
@@ -33,4 +33,8 @@ processTDU (dsd_opts* opts, dsd_state* state)
|
||||
status = getDibit (opts, state) + '0';
|
||||
// TODO: do something useful with the status bits...
|
||||
}
|
||||
|
||||
//reset some strings -- since its a tdu, blank out any call strings, only want during actual call
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
}
|
||||
|
||||
@@ -390,11 +390,60 @@ processTDULC (dsd_opts* opts, dsd_state* state)
|
||||
lcinfo[53] = dodeca_data[0][ 9] + '0';
|
||||
lcinfo[54] = dodeca_data[0][10] + '0';
|
||||
lcinfo[55] = dodeca_data[0][11] + '0';
|
||||
/*
|
||||
if (state->carrier == 1) //only update when carrier is present, otherwise, garbage values may be collected
|
||||
|
||||
int j;
|
||||
uint8_t LCW_bytes[9];
|
||||
uint8_t LCW_bits[72];
|
||||
memset (LCW_bytes, 0, sizeof(LCW_bytes));
|
||||
memset (LCW_bits, 0, sizeof(LCW_bits));
|
||||
|
||||
//load array above into byte form first
|
||||
LCW_bytes[0] = (uint8_t) ConvertBitIntoBytes(&lcformat[0], 8);
|
||||
LCW_bytes[1] = (uint8_t) ConvertBitIntoBytes(&mfid[0], 8);
|
||||
for (i = 0; i < 7; i++) LCW_bytes[i+2] = (uint8_t) ConvertBitIntoBytes(&lcinfo[i*8], 8);
|
||||
|
||||
//load as bit array next (easier to process data in bit form)
|
||||
for(i = 0, j = 0; i < 9; i++, j+=8)
|
||||
{
|
||||
state->payload_mfid = strtol (mfid, NULL, 2); //wonder if this is accurate info or not
|
||||
LCW_bits[j + 0] = (LCW_bytes[i] >> 7) & 0x01;
|
||||
LCW_bits[j + 1] = (LCW_bytes[i] >> 6) & 0x01;
|
||||
LCW_bits[j + 2] = (LCW_bytes[i] >> 5) & 0x01;
|
||||
LCW_bits[j + 3] = (LCW_bytes[i] >> 4) & 0x01;
|
||||
LCW_bits[j + 4] = (LCW_bytes[i] >> 3) & 0x01;
|
||||
LCW_bits[j + 5] = (LCW_bytes[i] >> 2) & 0x01;
|
||||
LCW_bits[j + 6] = (LCW_bytes[i] >> 1) & 0x01;
|
||||
LCW_bits[j + 7] = (LCW_bytes[i] >> 0) & 0x01;
|
||||
}
|
||||
*/
|
||||
processP25lcw (opts, state, lcformat, mfid, lcinfo);
|
||||
|
||||
//send to new P25 LCW function
|
||||
if (irrecoverable_errors == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
p25_lcw (opts, state, LCW_bits, 0);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s",KRED);
|
||||
fprintf (stderr, " LCW FEC ERR ");
|
||||
fprintf (stderr, "%s\n", KNRM);
|
||||
}
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
fprintf (stderr, " P25 LCW Payload ");
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", LCW_bytes[i]);
|
||||
}
|
||||
|
||||
|
||||
fprintf (stderr, "%s\n", KNRM);
|
||||
}
|
||||
|
||||
//reset some strings -- since its a tdu, blank out any call strings, only want during actual call
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
|
||||
}
|
||||
|
||||
104
src/p25p1_tsbk.c
104
src/p25p1_tsbk.c
@@ -8,82 +8,29 @@
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
int block_convolution (int payload[196], uint8_t decoded[12])
|
||||
{
|
||||
int ec = -1; //initialize error value
|
||||
|
||||
uint8_t deinterleaved_bits[196];
|
||||
uint8_t trellis_bytes[12];
|
||||
uint8_t m_data[14];
|
||||
uint8_t temp[210]; //temp bit position buffer for convolution
|
||||
|
||||
//initialize our deinterleaved bits and bytes with zeroes
|
||||
for (int i = 0; i < 196; i++) deinterleaved_bits[i] = 0;
|
||||
for (int i = 0; i < 210; i++) temp[i] = 0;
|
||||
for (int i = 0; i < 12; i++) trellis_bytes[i] = 0;
|
||||
for (int i = 0; i < 14; i++) m_data[i] = 0;
|
||||
|
||||
//convolution decoder
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
|
||||
//initialize our decoded byte buffer with zeroes
|
||||
for (int i = 0; i < 12; i++) decoded[i] = 0;
|
||||
|
||||
static const uint16_t deinterleave_tsbk[] = {
|
||||
0, 1, 2, 3, 52, 53, 54, 55, 100,101,102,103, 148,149,150,151,
|
||||
4, 5, 6, 7, 56, 57, 58, 59, 104,105,106,107, 152,153,154,155,
|
||||
8, 9, 10, 11, 60, 61, 62, 63, 108,109,110,111, 156,157,158,159,
|
||||
12, 13, 14, 15, 64, 65, 66, 67, 112,113,114,115, 160,161,162,163,
|
||||
16, 17, 18, 19, 68, 69, 70, 71, 116,117,118,119, 164,165,166,167,
|
||||
20, 21, 22, 23, 72, 73, 74, 75, 120,121,122,123, 168,169,170,171,
|
||||
24, 25, 26, 27, 76, 77, 78, 79, 124,125,126,127, 172,173,174,175,
|
||||
28, 29, 30, 31, 80, 81, 82, 83, 128,129,130,131, 176,177,178,179,
|
||||
32, 33, 34, 35, 84, 85, 86, 87, 132,133,134,135, 180,181,182,183,
|
||||
36, 37, 38, 39, 88, 89, 90, 91, 136,137,138,139, 184,185,186,187,
|
||||
40, 41, 42, 43, 92, 93, 94, 95, 140,141,142,143, 188,189,190,191,
|
||||
44, 45, 46, 47, 96, 97, 98, 99, 144,145,146,147, 192,193,194,195,
|
||||
48, 49, 50, 51 };
|
||||
|
||||
//get the deinterleaved bits
|
||||
for (int i = 0; i < 196; i++) deinterleaved_bits[deinterleave_tsbk[i]] = payload[i];
|
||||
|
||||
//shift into proper position for the convolutional decoder
|
||||
for (int i = 0; i < 196; i++) temp[i] = deinterleaved_bits[i] << 1;
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0U; i < 98U; i++) //102U
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
|
||||
CNXDNConvolution_decode(s0, s1);
|
||||
}
|
||||
|
||||
CNXDNConvolution_chainback(m_data, 96U); //98U
|
||||
|
||||
//debug print
|
||||
fprintf (stderr, "\n Convolution Chainback - ");
|
||||
for (int i = 0; i < 14; i++) fprintf (stderr, "[%02X]", m_data[i]);
|
||||
|
||||
//transfer m_data to decoded bytes -- when sorted out, can probably send decoded straight to chainback, and save the code
|
||||
// for (int i = 0; i < 12; i++) decoded[i] = m_data[i];
|
||||
|
||||
ec = 0; //unknown if a method exists to returns errors from the convolutional decoder, just rely on CRC check for now
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
void processTSBK(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int tsbkbit[196] = {0}; //tsbk bit array, 196 trellis encoded bits
|
||||
int tsbk_dibit[98] = {0};
|
||||
int tsbkbit[196]; //tsbk bit array, 196 trellis encoded bits
|
||||
int tsbk_dibit[98];
|
||||
|
||||
memset (tsbkbit, 0, sizeof(tsbkbit));
|
||||
memset (tsbk_dibit, 0, sizeof(tsbk_dibit));
|
||||
|
||||
int dibit = 0;
|
||||
uint8_t tsbk_byte[12] = {0}; //12 byte return from bd_bridge (block_deinterleave)
|
||||
unsigned long long int PDU[24] = {0}; //24 byte PDU to send to the tsbk_byte vPDU handler, should be same formats (mostly)
|
||||
int tsbk_decoded_bits[190] = {0}; //decoded bits from tsbk_bytes for sending to crc16_lb_bridge
|
||||
|
||||
uint8_t tsbk_byte[12]; //12 byte return from bd_bridge (block_deinterleave)
|
||||
memset (tsbk_byte, 0, sizeof(tsbk_byte));
|
||||
|
||||
unsigned long long int PDU[24]; //24 byte PDU to send to the tsbk_byte vPDU handler, should be same formats (mostly)
|
||||
memset (PDU, 0, sizeof(PDU));
|
||||
|
||||
int tsbk_decoded_bits[190]; //decoded bits from tsbk_bytes for sending to crc16_lb_bridge
|
||||
memset (tsbk_decoded_bits, 0, sizeof(tsbk_decoded_bits));
|
||||
|
||||
int flushing_bits[196]; //for flushing the trellis state machine
|
||||
memset (flushing_bits, 0, sizeof(flushing_bits));
|
||||
|
||||
int i, j, k, b, x, y;
|
||||
int ec = -2; //error value returned from (block_deinterleave)
|
||||
int err = -2; //error value returned from crc16_lb_bridge
|
||||
@@ -121,8 +68,13 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//test with the nxdn convolutional decoder
|
||||
// ec = block_convolution (tsbkbit, tsbk_byte);
|
||||
//flushing the trellis state machine
|
||||
if (j == 0)
|
||||
{
|
||||
bd_bridge(flushing_bits, tsbk_byte);
|
||||
//reset tsbk_byte afterwards
|
||||
memset (tsbk_byte, 0, sizeof(tsbk_byte));
|
||||
}
|
||||
|
||||
//send tsbkbit to block_deinterleave and return tsbk_byte
|
||||
ec = bd_bridge(tsbkbit, tsbk_byte);
|
||||
@@ -178,7 +130,9 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
||||
//Don't run NET_STS out of this, or will set wrong NAC/CC //&& PDU[1] != 0x49 && PDU[1] != 0x45
|
||||
//0x49 is telephone grant, 0x46 Unit to Unit Channel Answer Request (seems bogus) (mfid 90)
|
||||
// if (MFID < 0x2 && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
|
||||
if ( (MFID < 0x2 || MFID == 0xA4 || MFID == 0x90) && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
|
||||
//running with A4 and 90 causing some false positives when sending to vPDU, issuing bad call grants to nowhere!
|
||||
// if ( (MFID < 0x2 || MFID == 0xA4 || MFID == 0x90) && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
|
||||
if (MFID < 0x2 && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
|
||||
{
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
process_MAC_VPDU(opts, state, 0, PDU);
|
||||
@@ -188,7 +142,7 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
||||
//set our WACN and SYSID here now that we have valid ec and crc/checksum
|
||||
else if (protectbit == 0 && err == 0 && ec == 0 && (tsbk_byte[0] & 0x3F) == 0x3B)
|
||||
{
|
||||
long int wacn = (tsbk_byte[3] << 12) | (tsbk_byte[4] << 4) | (tsbk_byte[5] >> 4);;
|
||||
long int wacn = (tsbk_byte[3] << 12) | (tsbk_byte[4] << 4) | (tsbk_byte[5] >> 4);
|
||||
int sysid = ((tsbk_byte[5] & 0xF) << 8) | tsbk_byte[6];
|
||||
int channel = (tsbk_byte[7] << 8) | tsbk_byte[8];
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
|
||||
@@ -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);
|
||||
|
||||
301
src/p25p2_vpdu.c
301
src/p25p2_vpdu.c
@@ -84,7 +84,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
|
||||
//MFID90 Voice Grants, A3, A4, and A5
|
||||
//MFID90 Voice Grants, A3, A4, and A5 <--I bet A4 here was triggering a phantom call when TSBK sent PDUs here
|
||||
//MFID90 Group Regroup Channel Grant - Implicit
|
||||
if (MAC[1+len_a] == 0xA3 && MAC[2+len_a] == 0x90)
|
||||
{
|
||||
@@ -96,6 +96,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n CHAN [%04X] Group [%d][%04X]", channel, sgroup, sgroup);
|
||||
freq = process_channel_to_freq (opts, state, channel);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X SG: %d;", channel, sgroup);
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
if (state->group_array[i].groupNumber == sgroup)
|
||||
@@ -114,16 +117,27 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// //testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channel >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
@@ -164,6 +178,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n CHAN [%04X] Group [%d][%04X]", channel, sgroup, sgroup);
|
||||
freq = process_channel_to_freq (opts, state, channel);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X SG: %d", channel, sgroup);
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
if (state->group_array[i].groupNumber == sgroup)
|
||||
@@ -183,14 +200,24 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channel >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->use_rigctl == 1)
|
||||
@@ -239,6 +266,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X SG: %d; Ch: %04X SG: %d;", channel1, group1, channel2, group2);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
@@ -284,15 +314,26 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
if (opts->mod_qpsk == 1)
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
@@ -343,6 +384,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN [%04X] Group [%d] Source [%d]", svc, channel, group, source);
|
||||
freq = process_channel_to_freq (opts, state, channel);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X TG: %d;", channel, group);
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
if (state->group_array[i].groupNumber == group)
|
||||
@@ -362,15 +406,26 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channel >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
@@ -403,7 +458,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
|
||||
//Unit-to-Unit Voice Service Channel Grant (UU_V_CH_GRANT), or Grant Update (same format)
|
||||
if (MAC[1+len_a] == 0x44 || MAC[1+len_a] == 0x46)
|
||||
if (MAC[1+len_a] == 0x44 || MAC[1+len_a] == 0x46) //double check these opcodes
|
||||
{
|
||||
int channel = (MAC[2+len_a] << 8) | MAC[3+len_a];
|
||||
int target = (MAC[4+len_a] << 16) | (MAC[5+len_a] << 8) | MAC[6+len_a];
|
||||
@@ -415,6 +470,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n CHAN [%04X] Source [%d] Target [%d]", channel, source, target);
|
||||
freq = process_channel_to_freq (opts, state, channel);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X TGT: %d;", channel, target);
|
||||
|
||||
//Skip tuning private calls if private calls is disabled
|
||||
if (opts->trunk_tune_private_calls == 0) goto SKIPCALL;
|
||||
|
||||
@@ -435,15 +493,26 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channel >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
@@ -497,6 +566,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
freq1t = process_channel_to_freq (opts, state, channelt2);
|
||||
freq1r = process_channel_to_freq (opts, state, channelr2);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X TG: %d; Ch: %04X TG: %d;", channelt1, group1, channelt2, group2);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
@@ -539,14 +611,24 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->use_rigctl == 1)
|
||||
@@ -581,7 +663,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
|
||||
//Group Voice Channel Grant Update Multiple - Implicit
|
||||
if (MAC[1+len_a] == 0x05) //wonder if this is MAC_SIGNAL only? Too long for a TSBK
|
||||
if (MAC[1+len_a] == 0x05)
|
||||
{
|
||||
int so1 = MAC[2+len_a];
|
||||
int channel1 = (MAC[3+len_a] << 8) | MAC[4+len_a];
|
||||
@@ -604,6 +686,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n Channel 3 [%04X] Group 3 [%d][%04X]", channel3, group3, group3);
|
||||
freq3 = process_channel_to_freq (opts, state, channel3);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; Ch: %04X TG: %d;", channel1, group1, channel2, group2, channel3, group3);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
@@ -651,15 +736,26 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
if (opts->mod_qpsk == 1)
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
@@ -710,6 +806,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X TG: %d; Ch: %04X TG: %d;", channel1, group1, channel2, group2);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
@@ -753,15 +852,26 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
if (opts->mod_qpsk == 1)
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
@@ -810,11 +920,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Group [%d][%04X]", svc, channelt, channelr, group, group);
|
||||
freq1 = process_channel_to_freq (opts, state, channelt);
|
||||
freq2 = process_channel_to_freq (opts, state, channelr);
|
||||
if (slot == 0)
|
||||
{
|
||||
state->lasttg = group;
|
||||
}
|
||||
else state->lasttgR = group;
|
||||
|
||||
//don't set the tg here, one multiple grant updates, will mess up the TG value on current call
|
||||
// if (slot == 0)
|
||||
// {
|
||||
// state->lasttg = group;
|
||||
// }
|
||||
// else state->lasttgR = group;
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
@@ -835,15 +947,26 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[channelt >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
@@ -999,18 +1122,31 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
}
|
||||
|
||||
//identifier update VHF/UHF
|
||||
if (MAC[1+len_a] == 0x74)
|
||||
//identifier update VHF/UHF
|
||||
if (MAC[1+len_a] == 0x74)
|
||||
{
|
||||
state->p25_chan_iden = MAC[2+len_a] >> 4;
|
||||
int iden = state->p25_chan_iden;
|
||||
|
||||
state->p25_chan_type[iden] = 1;
|
||||
int bw_vu = (MAC[2+len_a] & 0xF);
|
||||
state->p25_trans_off[iden] = (MAC[3+len_a] << 6) | (MAC[4+len_a] >> 2);
|
||||
state->p25_chan_spac[iden] = ((MAC[4+len_a] & 0x3) << 8) | MAC[5+len_a];
|
||||
state->p25_base_freq[iden] = (MAC[6+len_a] << 24) | (MAC[7+len_a] << 16) | (MAC[8+len_a] << 8) | (MAC[9+len_a] << 0);
|
||||
|
||||
//this is causing more issues -- need a different way to check on this
|
||||
// if (state->p25_chan_spac[iden] == 0x64) //tdma
|
||||
// {
|
||||
// state->p25_chan_type[iden] = 4; //
|
||||
// state->p25_chan_tdma[iden] = 1; //
|
||||
// }
|
||||
// else //fdma
|
||||
// {
|
||||
// state->p25_chan_type[iden] = 1; //
|
||||
// state->p25_chan_tdma[iden] = 0; //
|
||||
// }
|
||||
|
||||
state->p25_chan_type[iden] = 1; //set as old values for now
|
||||
state->p25_chan_tdma[iden] = 0; //set as old values for now
|
||||
|
||||
fprintf (stderr, "\n Identifier Update UHF/VHF\n");
|
||||
fprintf (stderr, " Channel Identifier [%01X] BW [%01X] Transmit Offset [%04X]\n Channel Spacing [%03X] Base Frequency [%08lX] [%09ld]",
|
||||
state->p25_chan_iden, bw_vu, state->p25_trans_off[iden], state->p25_chan_spac[iden], state->p25_base_freq[iden], state->p25_base_freq[iden] * 5);
|
||||
@@ -1023,6 +1159,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
int iden = state->p25_chan_iden;
|
||||
|
||||
state->p25_chan_type[iden] = 1;
|
||||
state->p25_chan_tdma[iden] = 0;
|
||||
int bw = ((MAC[2+len_a] & 0xF) << 5) | ((MAC[3+len_a] & 0xF8) >> 2);
|
||||
state->p25_trans_off[iden] = (MAC[3+len_a] << 6) | (MAC[4+len_a] >> 2);
|
||||
state->p25_chan_spac[iden] = ((MAC[4+len_a] & 0x3) << 8) | MAC[5+len_a];
|
||||
@@ -1038,6 +1175,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
{
|
||||
state->p25_chan_iden = MAC[2+len_a] >> 4;
|
||||
int iden = state->p25_chan_iden;
|
||||
state->p25_chan_tdma[iden] = 1;
|
||||
state->p25_chan_type[iden] = MAC[2+len_a] & 0xF;
|
||||
state->p25_trans_off[iden] = (MAC[3+len_a] << 6) | (MAC[4+len_a] >> 2);
|
||||
state->p25_chan_spac[iden] = ((MAC[4+len_a] & 0x3) << 8) | MAC[5+len_a];
|
||||
@@ -1053,6 +1191,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
{
|
||||
state->p25_chan_iden = MAC[3+len_a] >> 4;
|
||||
int iden = state->p25_chan_iden;
|
||||
state->p25_chan_tdma[iden] = 1;
|
||||
state->p25_chan_type[iden] = MAC[3+len_a] & 0xF;
|
||||
state->p25_trans_off[iden] = (MAC[4+len_a] << 6) | (MAC[5+len_a] >> 2);
|
||||
state->p25_chan_spac[iden] = ((MAC[5+len_a] & 0x3) << 8) | MAC[6+len_a];
|
||||
@@ -1223,7 +1362,25 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
int src = (MAC[5+len_a] << 16) | (MAC[6+len_a] << 8) | MAC[7+len_a];
|
||||
|
||||
fprintf (stderr, "\n VCH %d - TG %d SRC %d ", slot, gr, src);
|
||||
fprintf (stderr, "Group Voice");
|
||||
|
||||
if (svc & 0x80) fprintf (stderr, " Emergency");
|
||||
if (svc & 0x40) fprintf (stderr, " Encrypted");
|
||||
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
{
|
||||
if (svc & 0x20) fprintf (stderr, " Duplex");
|
||||
if (svc & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (svc & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", svc & 0x7); //call priority
|
||||
}
|
||||
|
||||
fprintf (stderr, " Group Voice");
|
||||
|
||||
sprintf (state->call_string[slot], " Group ");
|
||||
if (svc & 0x80) strcat (state->call_string[slot], " Emergency ");
|
||||
else if (svc & 0x40) strcat (state->call_string[slot], " Encrypted ");
|
||||
else strcat (state->call_string[slot], " ");
|
||||
|
||||
if (slot == 0)
|
||||
{
|
||||
@@ -1244,7 +1401,25 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
int src = (MAC[6+len_a] << 16) | (MAC[7+len_a] << 8) | MAC[8+len_a];
|
||||
|
||||
fprintf (stderr, "\n VCH %d - TG %d SRC %d ", slot, gr, src);
|
||||
fprintf (stderr, "Unit to Unit Voice");
|
||||
|
||||
if (svc & 0x80) fprintf (stderr, " Emergency");
|
||||
if (svc & 0x40) fprintf (stderr, " Encrypted");
|
||||
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
{
|
||||
if (svc & 0x20) fprintf (stderr, " Duplex");
|
||||
if (svc & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (svc & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", svc & 0x7); //call priority
|
||||
}
|
||||
|
||||
fprintf (stderr, " Unit to Unit Voice");
|
||||
|
||||
sprintf (state->call_string[slot], " Private ");
|
||||
if (svc & 0x80) strcat (state->call_string[slot], " Emergency ");
|
||||
else if (svc & 0x40) strcat (state->call_string[slot], " Encrypted ");
|
||||
else strcat (state->call_string[slot], " ");
|
||||
|
||||
if (slot == 0)
|
||||
{
|
||||
@@ -1316,17 +1491,21 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (MAC[1+len_a] == 0x7C)
|
||||
{
|
||||
int lra = MAC[2+len_a];
|
||||
int cfva = MAC[3+len_a] >> 4;
|
||||
int lsysid = ((MAC[3+len_a] & 0xF) << 8) | MAC[4+len_a];
|
||||
int rfssid = MAC[5+len_a];
|
||||
int siteid = MAC[6+len_a];
|
||||
int channelt = (MAC[7+len_a] << 8) | MAC[8+len_a];
|
||||
int sysclass = MAC[9+len_a];
|
||||
if (1 == 1) //state->p2_is_lcch == 1
|
||||
{
|
||||
fprintf (stderr, "\n Adjacent Status Broadcast - Abbreviated\n");
|
||||
fprintf (stderr, " LRA [%02X] RFSS[%03d] SYSID [%03X] SITE [%03X] CHAN-T [%04X] SSC [%02X]", lra, rfssid, lsysid, siteid, channelt, sysclass);
|
||||
process_channel_to_freq (opts, state, channelt);
|
||||
}
|
||||
fprintf (stderr, "\n Adjacent Status Broadcast - Abbreviated\n");
|
||||
fprintf (stderr, " LRA [%02X] RFSS[%03d] SYSID [%03X] SITE [%03X] CHAN-T [%04X] SSC [%02X]\n ", lra, rfssid, lsysid, siteid, channelt, sysclass);
|
||||
if (cfva & 0x8) fprintf (stderr, " Conventional");
|
||||
if (cfva & 0x4) fprintf (stderr, " Failure Condition");
|
||||
if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
|
||||
else fprintf (stderr, " Last Known");
|
||||
if (cfva & 0x1) fprintf (stderr, " Valid RFSS Connection Active");
|
||||
process_channel_to_freq (opts, state, channelt);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1334,19 +1513,23 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (MAC[1+len_a] == 0xFC)
|
||||
{
|
||||
int lra = MAC[2+len_a];
|
||||
int cfva = MAC[3+len_a] >> 4;
|
||||
int lsysid = ((MAC[3+len_a] & 0xF) << 8) | MAC[4+len_a];
|
||||
int rfssid = MAC[5+len_a];
|
||||
int siteid = MAC[6+len_a];
|
||||
int channelt = (MAC[7+len_a] << 8) | MAC[8+len_a];
|
||||
int channelr = (MAC[9+len_a] << 8) | MAC[10+len_a];
|
||||
int sysclass = MAC[9+len_a];
|
||||
if (1 == 1) //state->p2_is_lcch == 1
|
||||
{
|
||||
fprintf (stderr, "\n Adjacent Status Broadcast - Extended\n");
|
||||
fprintf (stderr, " LRA [%02X] RFSS[%03d] SYSID [%03X] SITE [%03X] CHAN-T [%04X] CHAN-R [%04X] SSC [%02X]", lra, rfssid, lsysid, siteid, channelt, channelr, sysclass);
|
||||
process_channel_to_freq (opts, state, channelt);
|
||||
process_channel_to_freq (opts, state, channelr);
|
||||
}
|
||||
int sysclass = MAC[11+len_a]; //need to re-check this
|
||||
fprintf (stderr, "\n Adjacent Status Broadcast - Extended\n");
|
||||
fprintf (stderr, " LRA [%02X] RFSS[%03d] SYSID [%03X] SITE [%03X] CHAN-T [%04X] CHAN-R [%04X] SSC [%02X]\n ", lra, rfssid, lsysid, siteid, channelt, channelr, sysclass);
|
||||
if (cfva & 0x8) fprintf (stderr, " Conventional");
|
||||
if (cfva & 0x4) fprintf (stderr, " Failure Condition");
|
||||
if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
|
||||
else fprintf (stderr, " Last Known");
|
||||
if (cfva & 0x1) fprintf (stderr, " Valid RFSS Connection Active");
|
||||
process_channel_to_freq (opts, state, channelt);
|
||||
process_channel_to_freq (opts, state, channelr);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -630,7 +630,7 @@ processX2TDMAvoice (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
if ((eeei == 0) && (aiei == 0))
|
||||
{
|
||||
processP25lcw (opts, state, lcformat, mfid, lcinfo);
|
||||
// processP25lcw (opts, state, lcformat, mfid, lcinfo);
|
||||
}
|
||||
if (opts->p25enc == 1)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user