Esempio n. 1
0
 def set_freq(self, freq):
     if self.frequency == freq:
         return True
     old_freq = self.frequency
     self.frequency = freq
     if not self.demod.set_relative_frequency(
             self.device.offset + self.device.frequency +
             self.device.fractional_corr -
             freq):  # First attempt relative tune
         if self.device.tunable:  # then hard tune if allowed
             self.device.frequency = self.frequency
             self.device.src.set_center_freq(self.frequency +
                                             self.device.offset)
             self.device.fractional_corr = int(
                 (int(round(self.device.ppm)) - self.device.ppm) *
                 (self.device.frequency /
                  1e6))  # Calc frac ppm using new freq
             self.demod.set_relative_frequency(self.device.offset +
                                               self.device.frequency +
                                               self.device.fractional_corr -
                                               freq)
             if self.verbosity >= 9:
                 sys.stderr.write(
                     "%s [%d] Hardware tune: dev_freq(%d), dev_off(%d), dev_frac(%d), tune_freq(%d)\n"
                     % (log_ts.get(), self.msgq_id, self.device.frequency,
                        self.device.offset, self.device.fractional_corr,
                        (self.device.frequency -
                         (self.device.offset + self.device.frequency +
                          self.device.fractional_corr - freq))))
         else:  # otherwise fail and reset to prev freq
             self.demod.set_relative_frequency(self.device.offset +
                                               self.device.frequency +
                                               self.device.fractional_corr -
                                               old_freq)
             self.frequency = old_freq
             if self.verbosity:
                 sys.stderr.write(
                     "%s [%d] Unable to tune %s to frequency %f\n" %
                     (log_ts.get(), self.msgq_id, self.name, (freq / 1e6)))
             return False
     else:
         if self.verbosity >= 9:
             sys.stderr.write(
                 "%s [%d] Relative tune: dev_freq(%d), dev_off(%d), dev_frac(%d), tune_freq(%d)\n"
                 % (log_ts.get(), self.msgq_id, self.device.frequency,
                    self.device.offset, self.device.fractional_corr,
                    (self.device.frequency -
                     (self.device.offset + self.device.frequency +
                      self.device.fractional_corr - freq))))
     if 'fft' in self.sinks:
         self.sinks['fft'][0].set_center_freq(self.device.frequency)
         self.sinks['fft'][0].set_relative_freq(self.device.frequency -
                                                freq)
     if self.verbosity >= 9:
         sys.stderr.write("%s [%d] Tuning to frequency %f\n" %
                          (log_ts.get(), self.msgq_id, (freq / 1e6)))
     self.demod.reset()  # reset gardner-costas tracking loop
     self.decoder.sync_reset()  # reset frame_assembler
     return True
Esempio n. 2
0
 def process_qmsg(self, msg):  # Handle UI requests
     RX_COMMANDS = 'skip lockout hold whitelist reload'.split()
     if msg is None:
         return True
     s = msg.to_string()
     if type(s) is not str and isinstance(s, bytes):
         # should only get here if python3
         s = s.decode()
     if s == 'quit':
         return True
     elif s == 'update':  # UI initiated update request
         self.ui_last_update = time.time()
         self.ui_freq_update()
         if self.trunking is None or self.trunk_rx is None:
             return False
         js = self.trunk_rx.to_json()  # extract data from trunking module
         msg = gr.message().make_from_string(js, -4, 0, 0)
         self.ui_in_q.insert_tail(msg)  # send info back to UI
         self.ui_plot_update()
     elif s == 'toggle_plot':
         if not self.get_interactive():
             sys.stderr.write(
                 "%s Cannot start plots for non-realtime (replay) sessions\n"
                 % log_ts.get())
             return
         plot_type = int(msg.arg1())
         msgq_id = int(msg.arg2())
         self.find_channel(msgq_id).toggle_plot(plot_type)
     elif s == 'adj_tune':
         freq = msg.arg1()
         msgq_id = int(msg.arg2())
         self.find_channel(msgq_id).adj_tune(freq)
     elif s == 'set_debug':
         dbglvl = int(msg.arg1())
         self.set_debug(dbglvl)
     elif s == 'get_config':
         if self.terminal is not None and self.terminal_config is not None:
             self.terminal_config['json_type'] = "terminal_config"
             js = json.dumps(self.terminal_config)
             msg = gr.message().make_from_string(js, -4, 0, 0)
             self.ui_in_q.insert_tail(msg)  # send configuration back to UI
             pass
         else:
             return False
     elif s == 'dump_tgids':
         self.trunk_rx.dump_tgids()
     elif s == 'watchdog':
         if self.ui_last_update > 0 and (
                 time.time() > (self.ui_last_update + self.ui_timeout)):
             self.ui_last_update = 0
             sys.stderr.write("%s UI Timeout\n" % log_ts.get())
             for chan in self.channels:
                 chan.close_plots()
     elif s in RX_COMMANDS:
         if self.trunking is not None and self.trunk_rx is not None:
             self.trunk_rx.ui_command(s, msg.arg1(), msg.arg2())
     return False
Esempio n. 3
0
 def enqueue(self, addr, grp, cmd, ts):
     grp_str = "G" if (grp != 0) else "I"
     if self.is_chan(cmd):
         freq = self.get_freq(cmd)
         if self.debug >= 9:
             sys.stderr.write("%s [%d] SMARTNET OSW (0x%04x,%s,0x%03x,%f)\n" % (log_ts.get(), self.msgq_id, addr, grp_str, cmd, freq))
     else:
         freq = 0.0
         if self.debug >= 9:
             sys.stderr.write("%s [%d] SMARTNET OSW (0x%04x,%s,0x%03x)\n" % (log_ts.get(), self.msgq_id, addr, grp_str, cmd))
     self.osw_q.append((addr, (grp != 0), cmd, self.is_chan(cmd), freq, ts))
Esempio n. 4
0
    def load_bl_wl(self):
        self.skiplist = self.control.get_skiplist()
        if 'blacklist' in self.config and self.config['blacklist'] != "":
            sys.stderr.write("%s [%d] reading channel blacklist file: %s\n" % (log_ts.get(), self.msgq_id, self.config['blacklist']))
            self.blacklist = get_int_dict(self.config['blacklist'], self.msgq_id)
        else:
            self.blacklist = self.control.get_blacklist()

        if 'whitelist' in self.config and self.config['whitelist'] != "":
            sys.stderr.write("%s [%d] reading channel whitelist file: %s\n" % (log_ts.get(), self.msgq_id, self.config['whitelist']))
            self.whitelist = get_int_dict(self.config['whitelist'], self.msgq_id)
        else:
            self.whitelist = self.control.get_whitelist()
Esempio n. 5
0
 def error_tracking(self):
     UPDATE_TIME = 3.0
     if self.last_error_update + UPDATE_TIME > time.time() \
         or self.last_change_freq_at + UPDATE_TIME > time.time():
         return
     self.last_error_update = time.time()
     band = self.demod.get_error_band()
     freq_error = self.demod.get_freq_error()
     if band:
         self.error_band += band
     if band or abs(
             freq_error
     ) >= 200:  # avoid hunting by only compensating errors over 200hz
         self.freq_correction += freq_error * 0.15
         do_freq_update = 1
     else:
         do_freq_update = 0
     if self.freq_correction > 600:
         self.freq_correction -= 1200
         self.error_band += 1
     elif self.freq_correction < -600:
         self.freq_correction += 1200
         self.error_band -= 1
     self.tuning_error = self.error_band * 1200 + self.freq_correction
     e = 0
     if self.last_change_freq > 0:
         err_ppm = round(
             (self.tuning_error * 1e6) / float(self.last_change_freq))
         err_hz = -int(self.tuning_error - (err_ppm *
                                            (self.last_change_freq / 1e6)))
     if self.options.verbosity >= 10:
         sys.stderr.write('%s frequency_tracking\t%d\t%d\t%d\t%d\t%d\n' %
                          (log_ts.get(), freq_error, self.error_band,
                           self.tuning_error, err_ppm, err_hz))
     if do_freq_update:
         corrected_ppm = self.options.freq_corr + err_ppm  # compute new device ppm based on starting point plus adjustment
         if corrected_ppm != self.last_set_ppm:
             self.src.set_freq_corr(corrected_ppm)
             self.last_set_ppm = corrected_ppm
             if self.options.verbosity >= 1:
                 sys.stderr.write(
                     '%s Adjusting tuning correction: ppm(%d) ["-q %d"]\n' %
                     (log_ts.get(), corrected_ppm, corrected_ppm))
         self.options.fine_tune = err_hz  # replace existing fine_tune with new correction value
         self.set_freq(self.target_freq)
         if self.options.verbosity >= 2:
             sys.stderr.write(
                 '%s Adjusting tuning: ppm(%d), fine_tune(%d) ["-q %d -d %d"]\n'
                 % (log_ts.get(), corrected_ppm, err_hz, corrected_ppm,
                    err_hz))
Esempio n. 6
0
    def read_tags_file(self, tags_file):
        import csv
        try:
            with open(tags_file, 'r') as csvfile:
                sreader = csv.reader(decomment(csvfile), delimiter='\t', quotechar='"', quoting=csv.QUOTE_ALL)
                for row in sreader:
                    if len(row) < 2:
                        continue
                    try:
                        if ord(row[0][0]) == 0xfeff:
                            row[0] = row[0][1:] # remove UTF8_BOM (Python2 version)
                        if ord(row[0][0]) == 0xef and ord(row[0][1]) == 0xbb and ord(row[0][2]) == 0xbf:
                            row[0] = row[0][3:] # remove UTF8_BOM (Python3 version)
                        tgid = int(row[0])
                        tag = utf_ascii(row[1])
                    except (IndexError, ValueError) as ex:
                        continue
                    if len(row) >= 3:
                        try:
                            prio = int(row[2])
                        except ValueError as ex:
                            prio = TGID_DEFAULT_PRIO
                    else:
                        prio = TGID_DEFAULT_PRIO

                    if tgid not in self.talkgroups:
                        self.add_default_tgid(tgid)
                    self.talkgroups[tgid]['tag'] = tag
                    self.talkgroups[tgid]['prio'] = prio
                    sys.stderr.write("%s [%d] setting tgid(%d), prio(%d), tag(%s)\n" % (log_ts.get(), self.msgq_id, tgid, prio, tag))
        except IOError as ex:
            sys.stderr.write("%s [%d] Error: %s: %s\n" % (log_ts.get(), self.msgq_id, ex.strerror, tags_file))
Esempio n. 7
0
    def __init__(self, name, config):

        gr.hier_block2.__init__(
            self,
            "op25_wavsrc_f",
            gr.io_signature(0, 0, 0),  # Input signature
            gr.io_signature(1, 1, gr.sizeof_float))  # Output signature

        self.config = config
        self.name = name
        self.freq = 0

        # load config
        self.wav_file = str(from_dict(config, 'wav_file', ""))
        self.wav_size = int(from_dict(config, 'wav_size', 1))
        self.wav_gain = float(from_dict(config, 'wav_gain', 1.0))

        # Create the source block
        self.wavsrc = blocks.wavfile_source(self.wav_file)
        self.rate = self.wavsrc.sample_rate()
        self.size = self.wavsrc.bits_per_sample()
        self.chans = self.wavsrc.channels()

        sys.stderr.write(
            "%s [%s] Enabling WAV file source: rate=%d, bit=%d, channels=%d\n"
            % (log_ts.get(), name, self.rate, self.size, self.chans))

        # Create the throttle to set playback rate
        self.throttle = blocks.throttle(gr.sizeof_float, self.rate)

        # Gain
        self.gain = blocks.multiply_const_ff(self.wav_gain)

        # Connect src and throttle
        self.connect(self.wavsrc, self.throttle, self.gain, self)
Esempio n. 8
0
    def expire_talkgroup(self,
                         tgid=None,
                         update_meta=True,
                         reason="unk",
                         auto_hold=True):
        expire_time = time.time()
        self.nbfm_ctrl(self.msgq_id, False)  # disable nbfm
        self.slot_set({'tuner': self.msgq_id, 'slot': 4})  # disable p25cai
        if self.current_tgid is None:
            return

        self.talkgroups[self.current_tgid]['receiver'] = None
        self.talkgroups[self.current_tgid]['srcaddr'] = 0
        self.talkgroups[self.current_tgid]['release_time'] = expire_time
        if self.debug > 1:
            sys.stderr.write(
                "%s [%d] releasing:  tg(%d), freq(%f), reason(%s)\n" %
                (log_ts.get(), self.msgq_id, self.current_tgid,
                 (self.tuned_frequency / 1e6), reason))
        if auto_hold:
            self.hold_tgid = self.current_tgid
            self.hold_until = expire_time + TGID_HOLD_TIME
        self.current_tgid = None

        if update_meta:
            meta_update(self.meta_q)
Esempio n. 9
0
 def post_init(self):
     if self.debug >= 1:
         sys.stderr.write("%s [%d] Initializing DMR receiver\n" % (log_ts.get(), self.msgq_id))
     if self.msgq_id == 0:
         self.tune_next_chan(msgq_id=0, chan=0, slot=0)
     else:
         self.tune_next_chan(msgq_id=1, chan=0, slot=4)
Esempio n. 10
0
    def configure_p25_tdma(self, params):
        set_tdma = False
        if 'tdma' in params and params['tdma'] is not None:
            set_tdma = True
            self.decoder.set_slotid(params['tdma'])
        if set_tdma == self.tdma_state:
            return
        self.tdma_state = set_tdma
        if set_tdma:
            hash = '%x%x%x' % (params['nac'], params['sysid'], params['wacn'])
            if hash not in self.xor_cache:
                self.xor_cache[hash] = lfsr.p25p2_lfsr(
                    params['nac'], params['sysid'], params['wacn']).xor_chars
                if self.verbosity >= 5:
                    sys.stderr.write(
                        "%s [%d] Caching TDMA xor mask for NAC: 0x%x, SYSID: 0x%x, WACN: 0x%x\n"
                        % (log_ts.get(), self.msgq_id, params['nac'],
                           params['sysid'], params['wacn']))
            self.decoder.set_xormask(self.xor_cache[hash])
            rate = 6000
        else:
            rate = self.config['symbol_rate']

        self.symbol_rate = rate
        self.demod.set_omega(rate)
        if 'eye' in self.sinks:
            self.sinks['eye'][0].set_sps(self.config['if_rate'] / rate)
Esempio n. 11
0
    def read_tags_file(self, tags_file):
        import csv
        try:
            with open(tags_file, 'r') as csvfile:
                sreader = csv.reader(csvfile, delimiter='\t', quotechar='"', quoting=csv.QUOTE_ALL)
                for row in sreader:
                    try:
                        tgid = int(row[0])
                        tag = utf_ascii(row[1])
                    except (IndexError, ValueError) as ex:
                        continue
                    if len(row) >= 3:
                        try:
                            prio = int(row[2])
                        except ValueError as ex:
                            prio = TGID_DEFAULT_PRIO
                    else:
                        prio = TGID_DEFAULT_PRIO

                    if tgid not in self.talkgroups:
                        self.add_default_tgid(tgid)
                    self.talkgroups[tgid]['tag'] = tag
                    self.talkgroups[tgid]['prio'] = prio
                    sys.stderr.write("%s [%d] setting tgid(%d), prio(%d), tag(%s)\n" % (log_ts.get(), self.msgq_id, tgid, prio, tag))
        except IOError as ex:
            sys.stderr.write("%s [%d] Error: %s: %s\n" % (log_ts.get(), self.msgq_id, ex.strerror, tags_file))
Esempio n. 12
0
    def change_freq(self, params):
        tuner = params['tuner']
        if (tuner < 0) or (tuner > len(self.channels)):
            if self.verbosity:
                sys.stderr.write("%s No %s channel available for tuning\n" % (log_ts.get(), params['tuner']))
            return False

        chan = self.channels[tuner]
        if 'sigtype' in params and params['sigtype'] == "P25": # P25 specific config
            chan.configure_p25_tdma(params)

        if not chan.set_freq(params['freq']):
            chan.set_slot(0)
            return False

        if 'slot' in params:
            chan.set_slot(params['slot'])

        if 'chan' in params:
            self.trunk_rx.receivers[tuner].current_chan = params['chan']

        if 'state' in params:
            self.trunk_rx.receivers[tuner].current_state = params['state']

        if 'type' in params:
            self.trunk_rx.receivers[tuner].current_type = params['type']

        if 'time' in params:
            self.trunk_rx.receivers[tuner].tune_time = params['time']

        return True
Esempio n. 13
0
    def __init__(self, name, config):

        gr.hier_block2.__init__(self, "op25_iqsrc_c",
                                gr.io_signature(0, 0, 0),                    # Input signature
                                gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature

        self.config = config
        self.name = name
        self.is_dsd_file = False
        self.freq = 0
        self.ts = 0

        sys.stderr.write("%s [%s] Enabling IQ file source\n" % (log_ts.get(), name))

        # load config
        self.iq_file = str(from_dict(config, 'iq_file', ""))
        self.iq_seek = int(from_dict(config, 'iq_seek', 0))
        self.iq_size = int(from_dict(config, 'iq_size', 1))
        self.iq_signed  = bool(from_dict(config, 'iq_signed', False))
        self.rate = int(from_dict(config, 'rate', 2400000))

        # Create the source block
        self.iqsrc = op25_repeater.iqfile_source(self.iq_size, self.iq_file, self.iq_signed, self.iq_seek, 0)
        if self.iqsrc.is_dsd():
            self.is_dsd_file = True
            self.rate = self.iqsrc.get_dsd_rate()
            self.freq = self.iqsrc.get_dsd_freq()
            self.ts = self.iqsrc.get_dsd_ts()

        # Create the throttle to set playback rate
        self.throttle = blocks.throttle(gr.sizeof_gr_complex, self.rate)

        # Connect src and throttle
        self.connect(self.iqsrc, self.throttle, self)            
Esempio n. 14
0
    def update_voice_frequency(self,
                               float_freq,
                               tgid=None,
                               srcaddr=-1,
                               mode=-1,
                               ts=time.time()):
        if not float_freq:  # e.g., channel identifier not yet known
            return False

        frequency = int(float_freq *
                        1e6)  # use integer not float as dictionary keys

        rc = self.update_talkgroups(frequency, tgid, srcaddr, mode, ts)

        base_tgid = tgid & 0xfff0
        tgid_stat = tgid & 0x000f
        if frequency not in self.voice_frequencies:
            self.voice_frequencies[frequency] = {'counter': 0}
            sorted_freqs = collections.OrderedDict(
                sorted(self.voice_frequencies.items()))
            self.voice_frequencies = sorted_freqs
            if self.debug >= 5:
                sys.stderr.write('%s [%d] new freq=%f\n' %
                                 (log_ts.get(), self.msgq_id,
                                  (frequency / 1e6)))

        if 'tgid' not in self.voice_frequencies[frequency]:
            self.voice_frequencies[frequency]['tgid'] = [None]
        self.voice_frequencies[frequency]['tgid'] = base_tgid
        self.voice_frequencies[frequency]['counter'] += 1
        self.voice_frequencies[frequency]['time'] = time.time()
        return rc
Esempio n. 15
0
def get_int_dict(s, _id=0):  # used to read blacklist/whitelist files
    d = {}
    try:
        with open(s, "r") as f:
            for v in f:
                v = v.split("\t", 1)  # split on tab
                try:
                    v0 = int(
                        v[0])  # first parameter is tgid or start of tgid range
                    v1 = v0
                    if (len(v) > 1) and (
                            int(v[1]) > v0
                    ):  # second parameter if present is end of tgid range
                        v1 = int(v[1])

                    for tg in range(v0, (v1 + 1)):
                        if tg not in d:  # is this a new tg?
                            d[tg] = [
                            ]  # if so, add to dict (key only, value null)
                            sys.stderr.write(
                                '%s [%s] added talkgroup %d from %s\n' %
                                (log_ts.get(), _id, tg, s))

                except (IndexError, ValueError) as ex:
                    continue
        f.close()
    except (IOError) as ex:
        sys.stderr.write("%s: %s\n" % (ex.strerror, s))

    return dict.fromkeys(d)
Esempio n. 16
0
    def write(self, pcm_data):
        datalen = len(pcm_data)
        n_frames = c_ulong(datalen / self.framesize)
        c_data = c_char_p(pcm_data)
        ret = 0

        if (self.c_pcm.value == None):
            sys.stderr.write("PCM device is closed\n")
            return -1

        ret = self.libasound.snd_pcm_writei(self.c_pcm, cast(c_data, POINTER(c_void_p)), n_frames)
        if (ret < 0):
            if (ret == -errno.EPIPE): # underrun
                if (LOG_AUDIO_XRUNS):
                    sys.stderr.write("%s PCM underrun\n" % log_ts.get())
                ret = self.libasound.snd_pcm_recover(self.c_pcm, ret, 1)
                if (ret >= 0):
                    ret = self.libasound.snd_pcm_writei(self.c_pcm, cast(c_data, POINTER(c_void_p)), n_frames)
                else:
                    ret = self.libasound.snd_pcm_prepare(self.c_pcm)
                    ret = self.libasound.snd_pcm_writei(self.c_pcm, cast(c_data, POINTER(c_void_p)), n_frames)
            elif (ret == -errno.ESTRPIPE): # suspended
                while True:
                    ret = self.libasound.snd_pcm_resume(self.c_pcm)
                    if (ret != -errno.EAGAIN):
                        break
                    time.sleep(1)
                if (ret < 0):
                    ret = self.libasound.snd_pcm_prepare(self.c_pcm)
            elif (ret < 0): # other error
                ret = self.libasound.snd_pcm_prepare(self.c_pcm)

        return ret
Esempio n. 17
0
    def process_qmsg(self, msg, curr_time):
        rc = False
        m_type = ctypes.c_int16(msg.type() & 0xffff).value
        m_rxid = int(msg.arg1()) >> 1
        m_ts = float(msg.arg2())

        if (m_type == -1):  # Voice Channel Timeout
            pass
        elif (m_type == -4
              ):  # P25 sync established (indicates this is a digital channel)
            if self.current_tgid is not None:
                if self.debug >= 9:
                    sys.stderr.write(
                        "%s [%d] digital sync detected:  tg(%d), freq(%f), mode(%d)\n"
                        % (log_ts.get(), self.msgq_id, self.current_tgid,
                           (self.tuned_frequency / 1e6),
                           self.talkgroups[self.current_tgid]['mode']))
                self.nbfm_ctrl(self.msgq_id, False)  # disable nbfm
                self.talkgroups[
                    self.current_tgid]['mode'] = 1  # set mode to digital
        elif (m_type == 3
              ):  # DUID-3  (call termination without channel release)
            pass
        elif (m_type == 15):  # DUID-15 (call termination with channel release)
            self.expire_talkgroup(reason="duid15")
            rc = True
        return rc
Esempio n. 18
0
    def process_qmsg(self, msg, curr_time):
        m_proto = ctypes.c_int16(msg.type(
        ) >> 16).value  # upper 16 bits of msg.type() is signed protocol
        if m_proto != 2:  # Smartnet m_proto=2
            return False

        m_type = ctypes.c_int16(msg.type() & 0xffff).value
        m_rxid = int(msg.arg1()) >> 1
        m_ts = float(msg.arg2())

        if (m_type == -1):  # Control Channel Timeout
            if self.debug > 10:
                sys.stderr.write("%s [%d] control channel timeout\n" %
                                 (log_ts.get(), self.msgq_id))
            self.cc_retries += 1
            if self.cc_retries >= CC_TIMEOUT_RETRIES:
                self.tune_next_cc()

        elif (m_type == 0):  # OSW Receieved
            s = msg.to_string()

            osw_addr = (ord(s[0]) << 8) + ord(s[1])
            osw_grp = ord(s[2])
            osw_cmd = (ord(s[3]) << 8) + ord(s[4])
            self.enqueue(osw_addr, osw_grp, osw_cmd, m_ts)
            self.stats['osw_count'] += 1
            self.last_osw = m_ts

        rc = False
        rc |= self.process_osws()
        rc |= self.expire_talkgroups(curr_time)
        return rc
Esempio n. 19
0
 def load_json(self, metacfg):
     try:
         with open(metacfg) as json_file:
             self.cfg = json.load(json_file)
     except (ValueError, KeyError):
         sys.stderr.write(
             "%s meta_server::load_json(): Error reading metadata config file: %s\n"
             % (log_ts.get(), metacfg))
Esempio n. 20
0
 def skiplist_update(self, start_time):
     expired_tgs = [tg for tg in list(self.skiplist.keys())
                         if self.skiplist[tg] is not None
                         and self.skiplist[tg] < start_time]
     for tg in expired_tgs:
         self.skiplist.pop(tg)
         if self.debug > 1:
             sys.stderr.write("%s [%d] removing expired skiplist: tg(%d)\n" % (log_ts.get(), self.msgq_id, tg));
Esempio n. 21
0
    def __init__(self, debug=0, frequency_set=None, nac_set=None, slot_set=None, nbfm_ctrl=None, chans={}):
        self.frequency_set = frequency_set
        self.slot_set = slot_set
        self.nac_set = nac_set
        self.debug = debug
        self.receivers = {}

        self.chans = {}
        for _chan in chans:
            if not 'lcn' in _chan:
                sys.stderr.write("%s Trunking chan[%d] has no lcn defined\n" % (log_ts.get(), chans.index(_chan)))
                continue
            self.chans[_chan['lcn']] = dmr_chan(debug, _chan['lcn'], get_frequency(from_dict(_chan, 'frequency', 0.0)))
            sys.stderr.write("%s Configuring channel lcn(%d), freq(%f), cc(%d)\n" % (log_ts.get(), _chan['lcn'], get_frequency(from_dict(_chan, 'frequency', 0.0))/1e6, int(from_dict(_chan, 'cc', 0))))
        if len(self.chans) == 0:
            sys.stderr.write("%s Trunking has no valid chans, aborting\n" % (log_ts.get()))
            exit(1)
Esempio n. 22
0
 def configure_channels(self, config):
     self.channels = []
     for cfg in config:
         dev = self.find_device(cfg)
         if (dev is None) and 'frequency' in cfg:
             sys.stderr.write("* * * Frequency %d not within spectrum band of any device - ignoring!\n" % cfg['frequency'])
             continue
         elif dev is None:
             sys.stderr.write("* * * Channel '%s' not attached to any device - ignoring!\n" % cfg['name'])
             continue
         elif dev.tunable:
             for ch in self.channels:
                 if ch.device == dev:
                     sys.stderr.write("* * * Channel '%s' cannot share a tunable device - ignoring!\n" % cfg['name'])
                     dev = None
                     break
             if dev == None:
                 continue    
         meta_s, meta_q = None, None
         if self.metadata is not None and 'meta_stream_name' in cfg and cfg['meta_stream_name'] != "" and cfg['meta_stream_name'] in self.meta_streams:
             meta_s, meta_q = self.meta_streams[cfg['meta_stream_name']]
         if self.trunking is not None:
             msgq_id = len(self.channels)
             chan = channel(cfg, dev, self.verbosity, msgq_id, self.rx_q, self)
             self.channels.append(chan)
             self.trunk_rx.add_receiver(msgq_id, config=cfg, meta_q=meta_q, freq=chan.frequency)
         else:
             msgq_id = -1 - len(self.channels)
             chan = channel(cfg, dev, self.verbosity, msgq_id, self.rx_q, self)
             self.channels.append(chan)
         if ("raw_input" in cfg) and (cfg['raw_input'] != ""):
             sys.stderr.write("%s Reading raw symbols from file: %s\n" % (log_ts.get(), cfg['raw_input']))
             chan.raw_file = blocks.file_source(gr.sizeof_char, str(cfg['raw_input']), False)
             if ("raw_seek" in cfg) and (cfg['raw_seek'] != 0):
                 chan.raw_file.seek(int(cfg['raw_seek']) * 4800, 0)
             chan.throttle = blocks.throttle(gr.sizeof_char, chan.symbol_rate)
             chan.throttle.set_max_noutput_items(chan.symbol_rate/50);
             self.connect(chan.raw_file, chan.throttle)
             self.connect(chan.throttle, chan.decoder)
             self.set_interactive(False) # this is non-interactive 'replay' session 
         else:
             self.connect(dev.src, chan.demod, chan.decoder)
             if ("raw_output" in cfg) and (cfg['raw_output'] != ""):
                 sys.stderr.write("%s Saving raw symbols to file: %s\n" % (log_ts.get(), cfg['raw_output']))
                 chan.raw_sink = blocks.file_sink(gr.sizeof_char, str(cfg['raw_output']))
                 self.connect(chan.demod, chan.raw_sink)
Esempio n. 23
0
 def add_skiplist(self, tgid, end_time=None):
     if not tgid or (tgid <= 0) or (tgid > 65534):
         if self.debug > 1:
             sys.stderr.write(
                 "%s [%d] skiplist tgid(%d) out of range (1-65534)\n" %
                 (log_ts.get(), self.msgq_id, tgid))
         return
     if tgid in self.skiplist:
         return
     self.skiplist[tgid] = end_time
     if self.debug > 1:
         sys.stderr.write("%s [%d] skiplisting: tgid(%d)\n" %
                          (log_ts.get(), self.msgq_id, tgid))
     if self.current_tgid and self.current_tgid in self.skiplist:
         self.expire_talkgroup(reason="skiplisted")
         self.hold_mode = False
         self.hold_tgid = None
         self.hold_until = time.time()
Esempio n. 24
0
 def post_init(self):
     if self.debug >= 1:
         sys.stderr.write("%s [%d] Initializing voice channel\n" % (log_ts.get(), self.msgq_id))
     self.slot_set({'tuner': self.msgq_id,'slot': 4})     # disable voice
     if self.control is not None:
         self.talkgroups = self.control.get_talkgroups()
     self.load_bl_wl()
     self.tgid_hold_time = float(from_dict(self.control.config, 'tgid_hold_time', TGID_HOLD_TIME))
     meta_update(self.meta_q)
Esempio n. 25
0
    def post_init(self):
        if self.msgq_id < 0:
            sys.stderr.write("%f Smartnet system has no channel assigned!\n" %
                             (time.time()))
            return

        if self.debug >= 1:
            sys.stderr.write("%s [%d] Initializing Smartnet system\n" %
                             (log_ts.get(), self.msgq_id))

        if 'tgid_tags_file' in self.config and self.config[
                'tgid_tags_file'] != "":
            sys.stderr.write(
                "%s [%d] reading system tgid_tags_file: %s\n" %
                (log_ts.get(), self.msgq_id, self.config['tgid_tags_file']))
            self.read_tags_file(self.config['tgid_tags_file'])

        if 'blacklist' in self.config and self.config['blacklist'] != "":
            sys.stderr.write(
                "%s [%d] reading system blacklist file: %s\n" %
                (log_ts.get(), self.msgq_id, self.config['blacklist']))
            self.blacklist = get_int_dict(self.config['blacklist'],
                                          self.msgq_id)

        if 'whitelist' in self.config and self.config['whitelist'] != "":
            sys.stderr.write(
                "%s [%d] reading system whitelist file: %s\n" %
                (log_ts.get(), self.msgq_id, self.config['whitelist']))
            self.whitelist = get_int_dict(self.config['whitelist'],
                                          self.msgq_id)

        cc_list = from_dict(self.config, 'control_channel_list', "")
        if cc_list == "":
            sys.stderr.write(
                "Aborting. Smartnet Trunking 'control_channel_list' parameter is empty or not found\n"
            )
            sys.exit(1)

        for f in cc_list.split(','):
            self.cc_list.append(get_frequency(f))

        self.tune_next_cc()
Esempio n. 26
0
 def add_whitelist(self, tgid):
     if not tgid or (tgid <= 0) or (tgid > 65534):
         if self.debug > 0:
             sys.stderr.write("%s [%d] whitelist tgid(%d) out of range (1-65534)\n" % (log_ts.get(), self.msgq_id, tgid))
         return
     if self.blacklist and tgid in self.blacklist:
         self.blacklist.pop(tgid)
         if self.debug > 1:
             sys.stderr.write("%s [%d] de-blacklisting tgid(%d)\n" % (log_ts.get(), self.msgq_id, tgid))
     if self.whitelist is None:
         self.whitelist = {}
     if tgid in self.whitelist:
         return
     self.whitelist[tgid] = None
     if self.debug > 1:
         sys.stderr.write("%s [%d] whitelisting tgid(%d)\n" % (log_ts.get(), self.msgq_id, tgid))
     if self.current_tgid and self.current_tgid not in self.whitelist:
         self.expire_talkgroup(reason = "not whitelisted")
         self.hold_mode = False
         self.hold_tgid = None
         self.hold_until = time.time()
Esempio n. 27
0
    def get_freq(self, cmd):  # Convert 'cmd' into band-dependent frequency
        freq = 0.0
        bandplan = from_dict(self.config, 'bandplan', "800_reband")
        band = bandplan[:3]
        subtype = bandplan[3:len(bandplan)].lower().lstrip("_-:")

        if band == "800":
            if cmd <= 0x2CF:
                if subtype == "reband":  # REBAND
                    if cmd < 0x1b8:
                        freq = 851.0125 + (0.025 * cmd)
                    if cmd >= 0x1B8 and cmd <= 0x22F:
                        freq = 851.0250 + (0.025 * (cmd - 0x1B8))
                elif subtype == "splinter" and cmd <= 0x257:  # SPLINTER site
                    freq = 851.0 + (0.025 * cmd)
                else:
                    freq = 851.0125 + (0.025 * cmd)  # STANDARD site
            elif cmd <= 0x2f7:
                freq = 866.0000 + (0.025 * (cmd - 0x2D0))
            elif cmd >= 0x32F and cmd <= 0x33F:
                freq = 867.0000 + (0.025 * (cmd - 0x32F))
            elif cmd == 0x3BE:
                freq = 868.9750
            elif cmd >= 0x3C1 and cmd <= 0x3FE:
                freq = 867.4250 + (0.025 * (cmd - 0x3C1))

        elif band == "900":
            freq = 935.0125 + (0.0125 * cmd)

        elif band == "400":
            bp_spacing = float(from_dict(self.config, 'bp_spacing', "0.025"))
            bp_base_offset = int(from_dict(self.config, 'bp_base_offset', 380))
            bp_mid_offset = int(from_dict(self.config, 'bp_mid_offset', 760))
            bp_high_offset = int(from_dict(self.config, 'bp_high_offset', 760))
            bp_base = float(from_dict(self.config, 'bp_base', "0.0"))
            bp_mid = float(from_dict(self.config, 'bp_mid', "0.0"))
            bp_high = float(from_dict(self.config, 'bp_high', "0.0"))

            if (cmd >= bp_base_offset) and (cmd < bp_mid_offset):
                freq = bp_base + (bp_spacing * (cmd - bp_base_offset))
            elif (cmd >= bp_mid_offset) and (cmd < bp_high_offset):
                freq = bp_mid + (bp_spacing * (cmd - bp_mid_offset))
            elif (cmd >= bp_high_offset) and (cmd < 760):
                freq = bp_high + (bp_spacing * (cmd - bp_high_offset))
            else:
                if self.debug >= 5:
                    sys.stderr.write(
                        "%s [%d] SMARTNET OSW freq cmd: %d out of range\n" %
                        (log_ts.get(), self.msgq_id, cmd))
        return round(
            freq, 5
        )  # round to 5 decimal places to eliminate accumulated floating point errors
Esempio n. 28
0
    def open(self, hwdevice):
        self.out = c_void_p(
            self.libpa.pa_simple_new(None, "OP25".encode("ascii"),
                                     PA_STREAM_PLAYBACK, None,
                                     "OP25 Playback".encode('ascii'),
                                     byref(self.ss), None, None,
                                     byref(self.error)))

        if not self.out:
            sys.stderr.write("%s Could not open PulseAudio stream: %s\n" %
                             (log_ts.get(), self.libpa.strerror(self.error)))

        return self.error.value
Esempio n. 29
0
    def expire_talkgroups(self, curr_time):
        if curr_time < self.last_expiry_check + EXPIRY_TIMER:
            return False

        rc = False
        self.last_expiry_check = curr_time
        for tgid in self.talkgroups:
            if (self.talkgroups[tgid]['receiver'] is not None) and (curr_time >= self.talkgroups[tgid]['time'] + TGID_EXPIRY_TIME):
                if self.debug > 1:
                    sys.stderr.write("%s [%d] expiring tg(%d), freq(%f)\n" % (log_ts.get(), self.msgq_id, tgid, (self.talkgroups[tgid]['frequency']/1e6)))
                self.talkgroups[tgid]['receiver'].expire_talkgroup(reason="expiry")
                rc = True
        return rc
Esempio n. 30
0
    def __init__(self, dest, debug, input_rate, deviation, squelch, gain,
                 msgq_id, msg_q):

        gr.hier_block2.__init__(
            self,
            "op25_nbfm_c",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature(0, 0, 0))  # Output signature

        self.debug = debug
        self.msgq_id = msgq_id

        # 'switch' enables the analog decoding to be turned on/off
        self.switch = blocks.copy(gr.sizeof_gr_complex)
        self.switch.set_enabled(False)

        # power squelch
        self.squelch = analog.simple_squelch_cc(squelch, gain)

        # quadrature demod
        fm_demod_gain = input_rate / (4 * pi * deviation)
        self.fm_demod = analog.quadrature_demod_cf(fm_demod_gain)

        # fm deemphasis
        self.deemph = analog.fm_deemph(input_rate, 0.00075)

        # decimate and filter
        audio_decim = input_rate // _PCM_RATE
        lpf_taps = filter.firdes.low_pass(
            1.0,  # gain
            input_rate,  # sampling rate
            3000.0,  # Audio high cutoff (remove aliasing)
            200.0,  # transition
            filter.firdes.WIN_HAMMING)  # filter type
        hpf_taps = filter.firdes.high_pass(
            1.0,  # gain
            _PCM_RATE,  # sampling rate
            200.0,  # Audio low cutoff  (remove sub-audio signaling)
            10.0,  # Sharp transition band
            filter.firdes.WIN_HAMMING)  # filter type
        self.lp_filter = filter.fir_filter_fff(audio_decim, lpf_taps)
        self.hp_filter = filter.fir_filter_fff(1, hpf_taps)

        # analog_udp block converts +/-1.0 float samples to S16LE PCM and sends over UDP
        self.analog_udp = op25_repeater.analog_udp(dest, debug, msgq_id, msg_q)

        self.connect(self, self.switch, self.squelch, self.fm_demod,
                     self.deemph, self.lp_filter, self.hp_filter,
                     self.analog_udp)
        sys.stderr.write("%s [%d] Enabling nbfm analog audio\n" %
                         (log_ts.get(), msgq_id))