diff --git a/op25/gr-op25_repeater/apps/multi_rx.py b/op25/gr-op25_repeater/apps/multi_rx.py index c649510..e017966 100755 --- a/op25/gr-op25_repeater/apps/multi_rx.py +++ b/op25/gr-op25_repeater/apps/multi_rx.py @@ -148,6 +148,14 @@ class channel(object): self.kill_sink = [] + if 'blacklist' in config.keys(): + for g in config['blacklist'].split(','): + self.decoder.insert_blacklist(int(g)) + + if 'whitelist' in config.keys(): + for g in config['whitelist'].split(','): + self.decoder.insert_whitelist(int(g)) + if 'plot' not in config.keys(): return diff --git a/op25/gr-op25_repeater/include/op25_repeater/frame_assembler.h b/op25/gr-op25_repeater/include/op25_repeater/frame_assembler.h index a2d4c89..5e4301c 100644 --- a/op25/gr-op25_repeater/include/op25_repeater/frame_assembler.h +++ b/op25/gr-op25_repeater/include/op25_repeater/frame_assembler.h @@ -51,6 +51,8 @@ namespace gr { virtual void set_xormask(const char*p) {} virtual void set_nac(int nac) {} virtual void set_slotid(int slotid) {} + virtual void insert_whitelist(int grpaddr) {} + virtual void insert_blacklist(int grpaddr) {} }; } // namespace op25_repeater diff --git a/op25/gr-op25_repeater/lib/dmr_const.h b/op25/gr-op25_repeater/lib/dmr_const.h index e26eb82..31196a0 100644 --- a/op25/gr-op25_repeater/lib/dmr_const.h +++ b/op25/gr-op25_repeater/lib/dmr_const.h @@ -21,6 +21,8 @@ #ifndef INCLUDED_OP25_REPEATER_DMR_CONST_H #define INCLUDED_OP25_REPEATER_DMR_CONST_H +#include + static const int hamming_7_4[] = { 0, 11, 22, 29, 39, 44, 49, 58, 69, 78, 83, 88, 98, 105, 116, 127, @@ -843,4 +845,52 @@ static const uint8_t dmr_bs_idle_sync[24] = { static const uint8_t cach_tact_bits[] = {0, 4, 8, 12, 14, 18, 22}; static const uint8_t cach_payload_bits[] = {1,2,3,5,6,7,9,10,11,13,15,16,17,19,20,21,23}; +static const uint16_t _pc[] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}; + +static const uint32_t slookup_16_11[] = {0, 1, 2, 0, 4, 0, 0, 32, 8, 0, 0, 512, 0, 64, 2048, 0, 16, 0, 0, 32768, 0, 1024, 256, 0, 0, 128, 16384, 0, 4096, 0, 0, 8192}; +static const uint32_t masks_16_11[] = {62864, 31432, 15716, 60194, 42721}; +static const uint32_t nmasks_16_11 = 5; + +static const uint32_t slookup_16_7[] = {0, 1, 2, 3, 4, 5, 6, 0, 8, 9, 10, 0, 12, 0, 0, 32832, 16, 17, 18, 0, 20, 0, 0, 0, 24, 0, 0, 0, 0, 0, 16640, 0, 32, 33, 34, 0, 36, 0, 0, 0, 40, 0, 0, 6144, 0, 0, 0, 0, 48, 0, 0, 576, 0, 0, 0, 0, 0, 0, 0, 0, 33280, 0, 0, 0, 64, 65, 66, 0, 68, 0, 0, 32776, 72, 0, 0, 32772, 0, 32770, 32769, 32768, 80, 0, 0, 544, 0, 12288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32784, 96, 0, 0, 528, 0, 1152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32800, 0, 514, 513, 512, 0, 0, 0, 516, 0, 0, 0, 520, 0, 0, 10240, 0, 128, 129, 130, 0, 132, 0, 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 1088, 0, 0, 0, 24576, 33792, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8448, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 1056, 0, 0, 0, 2304, 0, 0, 0, 0, 0, 32896, 0, 0, 0, 0, 0, 0, 0, 18432, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1028, 4352, 0, 1025, 1024, 0, 1026, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 640, 0, 1040, 0, 0, 0, 0, 0, 0, 20480, 0, 0, 0, 256, 257, 258, 0, 260, 0, 0, 5120, 264, 0, 0, 0, 0, 0, 16400, 0, 272, 0, 0, 0, 0, 0, 16392, 0, 0, 0, 16388, 0, 16386, 0, 16384, 16385, 288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8320, 0, 0, 0, 0, 0, 0, 16416, 0, 320, 0, 0, 0, 0, 0, 0, 0, 0, 2176, 0, 0, 0, 0, 0, 33024, 0, 49152, 9216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16448, 0, 0, 0, 4224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16896, 0, 0, 0, 0, 0, 768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 384, 0, 0, 0, 0, 0, 34816, 0, 0, 2112, 0, 0, 0, 0, 0, 0, 0, 4608, 0, 0, 0, 0, 0, 8224, 0, 0, 0, 0, 0, 0, 16512, 0, 0, 0, 4160, 0, 0, 0, 0, 8208, 0, 0, 0, 0, 0, 36864, 0, 0, 0, 0, 0, 8196, 0, 8194, 8193, 8192, 0, 0, 2560, 0, 0, 0, 0, 8200, 0, 2056, 4128, 0, 8704, 0, 0, 0, 2049, 2048, 0, 2050, 0, 2052, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2064, 0, 0, 0, 0, 0, 0, 4098, 0, 4096, 4097, 0, 1280, 4100, 0, 0, 2080, 4104, 0, 0, 0, 0, 0, 0, 0, 4112, 0, 0, 0, 0, 8256, 40960, 0, 0, 17408, 0, 0, 0, 0}; +static const uint32_t masks_16_7[] = {30976, 15488, 40512, 13856, 25104, 51208, 58372, 61954, 44545}; +static const uint32_t nmasks_16_7 = 9; + +static const uint32_t slookup_17_12[] = {0, 1, 2, 0, 4, 32, 0, 2048, 8, 0, 64, 0, 0, 256, 4096, 0, 16, 1024, 0, 0, 128, 0, 0, 0, 0, 0, 512, 65536, 8192, 16384, 0, 32768}; +static const uint32_t masks_17_12[] = {124560, 127816, 63908, 105026, 118049}; +static const uint32_t nmasks_17_12 = 5; + +static inline int64_t _hamming_decode(const uint32_t r_codeword, const int n, const int k, const uint32_t *slookup, const uint32_t *masks, const uint32_t nmasks, const int *encode_tab) { + uint32_t syn = 0; + for (uint32_t i=0; i 0; acc >>= 8) { + sum += _pc[acc & 0xff]; + } + syn = (syn << 1) + (sum & 1); + } + if (syn == 0) + return (r_codeword >> (n - k)); // decode, no error case + uint32_t sl = slookup[syn]; + if (sl == 0) + return -1; // decode failed + uint32_t decoded = (r_codeword ^ sl) >> (n - k); // corrected but not yet trusted result + uint32_t encoded = encode_tab[decoded]; // re-encode and verify codewords match + if ((r_codeword ^ sl) == encoded) + return decoded; // decode OK with 1 error corrected + return -2; // decode verification failed +} + +static inline int64_t hamming_17_12_decode(const uint32_t r_codeword) { + return _hamming_decode(r_codeword, 17, 12, slookup_17_12, masks_17_12, nmasks_17_12, hamming_17_12); +} + +static inline int64_t hamming_16_11_decode(const uint32_t r_codeword) { + return _hamming_decode(r_codeword, 16, 11, slookup_16_11, masks_16_11, nmasks_16_11, hamming_16_11); +} + +static inline int64_t hamming_16_7_decode(const uint32_t r_codeword) { + return _hamming_decode(r_codeword, 16, 7, slookup_16_7, masks_16_7, nmasks_16_7, hamming_16_7); +} + #endif /* INCLUDED_OP25_REPEATER_DMR_CONST_H */ diff --git a/op25/gr-op25_repeater/lib/frame_assembler_impl.cc b/op25/gr-op25_repeater/lib/frame_assembler_impl.cc index 3e073f7..6edf70d 100644 --- a/op25/gr-op25_repeater/lib/frame_assembler_impl.cc +++ b/op25/gr-op25_repeater/lib/frame_assembler_impl.cc @@ -46,6 +46,13 @@ namespace gr { void frame_assembler_impl::set_slotid(int slotid) { } + void frame_assembler_impl::insert_whitelist(int grpaddr) { + d_sync.insert_whitelist(grpaddr); + } + void frame_assembler_impl::insert_blacklist(int grpaddr) { + d_sync.insert_blacklist(grpaddr); + } + frame_assembler::sptr frame_assembler::make(const char* options, int debug, gr::msg_queue::sptr queue) { diff --git a/op25/gr-op25_repeater/lib/frame_assembler_impl.h b/op25/gr-op25_repeater/lib/frame_assembler_impl.h index 63970a6..8cb3389 100644 --- a/op25/gr-op25_repeater/lib/frame_assembler_impl.h +++ b/op25/gr-op25_repeater/lib/frame_assembler_impl.h @@ -50,6 +50,8 @@ namespace gr { void set_xormask(const char*p) ; void set_nac(int nac) ; void set_slotid(int slotid) ; + void insert_whitelist(int grpaddr); + void insert_blacklist(int grpaddr); public: diff --git a/op25/gr-op25_repeater/lib/rx_sync.cc b/op25/gr-op25_repeater/lib/rx_sync.cc index 02478a0..81aa76b 100644 --- a/op25/gr-op25_repeater/lib/rx_sync.cc +++ b/op25/gr-op25_repeater/lib/rx_sync.cc @@ -132,12 +132,104 @@ void rx_sync::ysf_sync(const uint8_t dibitbuf[], bool& ysf_fullrate, bool& unmut fprintf(stderr, "ysf_sync: muting audio: dt: %d, rc: %d\n", d_shift_reg, rc); } +static int decode_embedded(uint8_t result_lc[72], const uint8_t src[32*4], int srclen) { +// return code < 0 indicates decode failure + static const int lengths[] = {11, 11, 10, 10, 10, 10, 10}; + int s_index = 0; + uint8_t decode[16*8]; + uint8_t decode_lc[72+5]; + int srcp = 0; + if (srclen != 32*4) + return -4; + for (int i=0; i<16; i++) { + for (int j=0; j<8; j++){ + decode[i+16*j] = src[srcp++]; + } + } + for (int i=0; i<7; i++) { + int v = load_i(&decode[16*i], 16); + int rc = hamming_16_11_decode(v); + if (rc < 0) + return rc; + store_i(rc, &decode_lc[11*i], 11); + memcpy(&result_lc[s_index], &decode_lc[11*i], lengths[i]); + s_index += lengths[i]; + } + uint16_t r_csum = 0; + for (int i=0; i<5; i++) { + r_csum <<= 1; + r_csum |= decode_lc[(i+2)*11+10] & 1; + } + uint16_t c_csum = 0; + for (int i=0; i<9; i++) { + c_csum += load_i(&result_lc[i*8], 8); + } + c_csum = c_csum % 31; + if (r_csum != c_csum) + return -3; + return 0; // OK return +} + +static void init_xlist(int * lp) { + for (int i=0; i < XLIST_SIZE; i++) { + lp[i] = -1; + } +} + +static bool find_xlist(const int grp, const int * lp) { + for (int i=0; i < XLIST_SIZE; i++) { + if (lp[i] == grp && grp > 0) + return true; + } + return false; +} + +static bool add_xlist(const int grp, int * lp) { +// returns false if failed (grp bad, dup or list full), otherwise true + for (int i=0; i < XLIST_SIZE; i++) { + if (lp[i] == grp || grp < 1) + return false; // dup or group invalid + if (lp[i] == -1) { + lp[i] = grp; + return true; + } + } + return false; +} + +static int count_xlist(const int * lp) { + int res=0; + for (int i=0; i < XLIST_SIZE; i++) { + if (lp[i] > 0) + res += 1; + } + return res; +} + +void rx_sync::insert_whitelist(int grpaddr) { + bool rc = add_xlist(grpaddr, d_whitelist); + if (rc == false) + fprintf(stderr, "insert_whitelist failed for grp=%d- dup or list full\n", grpaddr); + else if (d_debug) + fprintf(stderr, "insert_whitelist complete for grp=%d\n", grpaddr); +} + +void rx_sync::insert_blacklist(int grpaddr) { + bool rc = add_xlist(grpaddr, d_blacklist); + if (rc == false) + fprintf(stderr, "insert_blacklist failed for grp=%d- dup or list full\n", grpaddr); + else if (d_debug) + fprintf(stderr, "insert_blacklist complete for grp=%d\n", grpaddr); +} + void rx_sync::dmr_sync(const uint8_t bitbuf[], int& current_slot, bool& unmute) { static const int slot_ids[] = {0, 1, 0, 0, 1, 1, 0, 1}; + static const uint32_t BURST_SZ = 32; // embedded burst size (bits) int tact; int chan; int fstype; uint8_t tactbuf[sizeof(cach_tact_bits)]; + uint8_t lc72[72]; for (size_t i=0; i 0) + d_groupid_valid[current_slot] -= 1; + uint64_t sync = load_reg64(bitbuf + (MODE_DATA[RX_TYPE_DMR].sync_offset << 1), MODE_DATA[RX_TYPE_DMR].sync_len); if (check_frame_sync(DMR_VOICE_SYNC_MAGIC ^ sync, d_threshold, MODE_DATA[RX_TYPE_DMR].sync_len)) fstype = 1; @@ -157,17 +252,83 @@ void rx_sync::dmr_sync(const uint8_t bitbuf[], int& current_slot, bool& unmute) d_expires = d_symbol_count + MODE_DATA[d_current_type].expiration; if (fstype == 1) { if (!d_unmute_until[current_slot] && d_debug > 5) - fprintf(stderr, "unmute slot %d\n", current_slot); + fprintf(stderr, "%d unmute slot %d\n", d_symbol_count, current_slot); d_unmute_until[current_slot] = d_symbol_count + MODE_DATA[d_current_type].expiration; } else if (fstype == 2) { if (d_unmute_until[current_slot] && d_debug > 5) - fprintf(stderr, "mute slot %d\n", current_slot); + fprintf(stderr, "%d mute slot %d\n", d_symbol_count, current_slot); d_unmute_until[current_slot] = 0; } if (d_unmute_until[current_slot] <= d_symbol_count) { d_unmute_until[current_slot] = 0; } unmute = d_unmute_until[current_slot] > 0; + if (fstype == 0) { + uint16_t emb = (load_i(bitbuf+132, 8) << 8) + load_i(bitbuf+172, 8); + int emb_decode = hamming_16_7_decode(emb); + if (emb_decode >= 0) { + uint8_t cc = emb_decode >> 3; + uint8_t pi = (emb_decode >> 2) & 1; + uint8_t lcss = emb_decode & 3; + switch (lcss) { + case 0: + break; + case 1: + memcpy(d_burstb[current_slot], bitbuf+140, BURST_SZ); + d_burstl[current_slot] = BURST_SZ; + break; + case 2: + if (d_burstl[current_slot] && d_burstl[current_slot]+BURST_SZ <= sizeof(d_burstb)) { + memcpy(d_burstb[current_slot] + d_burstl[current_slot], bitbuf+140, BURST_SZ); + d_burstl[current_slot] += BURST_SZ; + int rc = decode_embedded(lc72, d_burstb[current_slot], d_burstl[current_slot]); + if (rc >= 0) { + int opcode = load_i(lc72+2, 6); + if (opcode == 0) { // group voice channel user + int grpaddr = load_i(lc72+24, 24); + if (grpaddr > 0) { + d_groupid[current_slot] = grpaddr; + d_groupid_valid[current_slot] = 20; + } + } + } else { + if (d_debug) + fprintf(stderr, "decode_embedded failed, code %d\n", rc); + } + } + d_burstl[current_slot] = 0; + break; + case 3: + if (d_burstl[current_slot] && d_burstl[current_slot]+BURST_SZ <= sizeof(d_burstb)) { + memcpy(d_burstb[current_slot] + d_burstl[current_slot], bitbuf+140, BURST_SZ); + d_burstl[current_slot] += BURST_SZ; + } else { + d_burstl[current_slot] = 0; + } + break; + } + } else { + d_burstl[current_slot] = 0; + } + } + if (unmute && d_groupid_valid[current_slot] > 0) { + if (count_xlist(d_whitelist) > 0 && !find_xlist(d_groupid[current_slot], d_whitelist)) { + if (d_debug) + fprintf(stderr, "%d group %d not in whitelist, muting slot %d\n", d_symbol_count, d_groupid[current_slot], current_slot); + unmute = 0; + if (d_unmute_until[current_slot] && d_debug > 5) + fprintf(stderr, "%d mute slot %d\n", d_symbol_count, current_slot); + d_unmute_until[current_slot] = 0; + } + if (count_xlist(d_blacklist) > 0 && find_xlist(d_groupid[current_slot], d_blacklist)) { + if (d_debug) + fprintf(stderr, "group %d in blacklist, muting slot %d\n", d_groupid[current_slot], current_slot); + unmute = 0; + if (d_unmute_until[current_slot] && d_debug > 5) + fprintf(stderr, "%d mute slot %d\n", d_symbol_count, current_slot); + d_unmute_until[current_slot] = 0; + } + } } rx_sync::rx_sync(const char * options, int debug) : // constructor @@ -184,6 +345,14 @@ rx_sync::rx_sync(const char * options, int debug) : // constructor mbe_initMbeParms (&cur_mp[0], &prev_mp[0], &enh_mp[0]); mbe_initMbeParms (&cur_mp[1], &prev_mp[1], &enh_mp[1]); sync_reset(); + d_burstl[0] = 0; + d_burstl[1] = 0; + init_xlist(d_whitelist); + init_xlist(d_blacklist); + d_groupid[0] = 0; + d_groupid_valid[0] = 0; + d_groupid[1] = 0; + d_groupid_valid[1] = 0; } rx_sync::~rx_sync() // destructor diff --git a/op25/gr-op25_repeater/lib/rx_sync.h b/op25/gr-op25_repeater/lib/rx_sync.h index 7ab2922..e5b1737 100644 --- a/op25/gr-op25_repeater/lib/rx_sync.h +++ b/op25/gr-op25_repeater/lib/rx_sync.h @@ -88,12 +88,16 @@ enum codeword_types { CODEWORD_NXDN_EHR }; +#define XLIST_SIZE 256 + class rx_sync { public: void rx_sym(const uint8_t sym); void sync_reset(void); rx_sync(const char * options, int debug); ~rx_sync(); + void insert_whitelist(int grpaddr); + void insert_blacklist(int grpaddr); private: void cbuf_insert(const uint8_t c); void dmr_sync(const uint8_t bitbuf[], int& current_slot, bool& unmute); @@ -122,6 +126,12 @@ private: bool d_stereo; int d_debug; op25_audio d_audio; + uint8_t d_burstb[2][32*4]; + int d_burstl[2]; // in units of bits + int d_groupid[2]; + unsigned int d_groupid_valid[2]; + int d_whitelist[XLIST_SIZE]; + int d_blacklist[XLIST_SIZE]; }; } // end namespace op25_repeater