Exemplo n.º 1
0
def APRSISRXDevice(reactor, client, name=None, filter=None):
    """
    client: an aprs.APRS object (see <https://pypi.python.org/pypi/aprs>)
    name: device label
    filter: filter on incoming data (see <http://www.aprs-is.net/javAPRSFilter.aspx>)
    """
    # pylint: disable=redefined-builtin
    if name is None:
        name = 'APRS-IS ' + filter
    info = TelemetryStore(
    )  # TODO this is wrong, need to be able to output_message.

    def main_callback(line):
        # TODO: This print-both-formats code is duplicated from multimon.py; it should be a utility in this module instead. Also, we should maybe have a try block.
        log.msg(u'APRS: %r' % (line, ))
        message = parse_tnc2(line, time.time())
        log.msg(u'   -> %s' % (message, ))
        parsed = parse_tnc2(line, time.time())
        info.receive(message)

    # client blocks in a loop, so set up a thread
    alive = True

    def threaded_callback(line):
        if not alive:
            raise StopIteration()
        reactor.callFromThread(main_callback, line)

    reactor.callInThread(client.receive,
                         callback=threaded_callback,
                         filter=filter)

    # TODO: Arrange so we can get close() callbacks and set alive=false
    # TODO: Allow the filter to be changed at runtime
    return Device(name=name, components={'aprs-is': info})
Exemplo n.º 2
0
    def __init__(self, devices={}, audio_config=None, features=_stub_features):
        if len(devices) <= 0:
            raise ValueError('Must have at least one RF device')
        
        gr.top_block.__init__(self, "SDR top block")
        self.__running = False  # duplicate of GR state we can't reach, see __start_or_stop
        self.__has_a_useful_receiver = False

        # Configuration
        # TODO: device refactoring: Remove vestigial 'accessories'
        self._sources = {k: d for k, d in devices.iteritems() if d.can_receive()}
        self._accessories = accessories = {k: d for k, d in devices.iteritems() if not d.can_receive()}
        self.source_name = self._sources.keys()[0]  # arbitrary valid initial value
        self.__rx_device_type = Enum({k: v.get_name() or k for (k, v) in self._sources.iteritems()})
        
        # Audio early setup
        self.__audio_manager = AudioManager(  # must be before contexts
            graph=self,
            audio_config=audio_config,
            stereo=features['stereo'])

        # Blocks etc.
        # TODO: device refactoring: remove 'source' concept (which is currently a device)
        # TODO: remove legacy no-underscore names, maybe get rid of self.source
        self.source = None
        self.__monitor_rx_driver = None
        self.monitor = MonitorSink(
            signal_type=SignalType(sample_rate=10000, kind='IQ'),  # dummy value will be updated in _do_connect
            context=Context(self))
        self.monitor.get_interested_cell().subscribe(self.__start_or_stop_later)
        self.__clip_probe = MaxProbe()
        
        # Receiver blocks (multiple, eventually)
        self._receivers = {}
        self._receiver_valid = {}
        
        # collections
        # TODO: No longer necessary to have these non-underscore names
        self.sources = CollectionState(self._sources)
        self.receivers = ReceiverCollection(self._receivers, self)
        self.accessories = CollectionState(accessories)
        self.__telemetry_store = TelemetryStore()
        
        # Flags, other state
        self.__needs_reconnect = [u'initialization']
        self.__in_reconnect = False
        self.receiver_key_counter = 0
        self.receiver_default_state = {}
        self.__cpu_calculator = LazyRateCalculator(lambda: time.clock())
        
        # Initialization
        
        def hookup_vfo_callback(k, d):  # function so as to not close over loop variable
            d.get_vfo_cell().subscribe(lambda: self.__device_vfo_callback(k))
        
        for k, d in devices.iteritems():
            hookup_vfo_callback(k, d)
        
        self._do_connect()
Exemplo n.º 3
0
class TestAPRSTelemetryStore(unittest.TestCase):
    """
    This is a test of APRSStation's implementation of ITelemetryObject.
    """
    def setUp(self):
        self.clock = Clock()
        self.clock.advance(_dummy_receive_time)
        self.store = TelemetryStore(time_source=self.clock)

    def __receive(self, msg):
        expand_aprs_message(msg, self.store)

    def test_new_station(self):
        self.assertEqual([], self.store.state().keys())
        self.__receive(
            parse_tnc2(
                'N6WKZ-3>APU25N,WB6TMS-3*,N6ZX-3*,WIDE2*:=3746.42N112226.00W# {UIV32N}',
                _dummy_receive_time))
        self.assertEqual(['N6WKZ-3'], self.store.state().keys())

    # TODO: this test makes less sense now that expand_aprs_message is separate
    def test_object_item_report(self):
        self.__receive(
            parse_tnc2(
                'KE6AFE-2>APU25N,WR6ABD*,NCA1:;TFCSCRUZ *160323z3655.94N\12200.92W?70 In 10 Minutes',
                _dummy_receive_time))
        self.assertEqual({'KE6AFE-2', 'TFCSCRUZ '},
                         set(self.store.state().keys()))
        # TODO test value of object

    def test_object_kill(self):
        self.__receive(
            parse_tnc2(
                'KE6AFE-2>APU25N,WR6ABD*,NCA1:;TFCSCRUZ *160323z3655.94N\12200.92W?70 In 10 Minutes',
                _dummy_receive_time))
        self.assertEqual({'KE6AFE-2', 'TFCSCRUZ '},
                         set(self.store.state().keys()))
        self.__receive(
            parse_tnc2('FOO>BAR:;TFCSCRUZ _160323z3655.94N\12200.92W?',
                       _dummy_receive_time))
        self.clock.advance(0)
        self.assertEqual({'FOO', 'KE6AFE-2'}, set(self.store.state().keys()))

    def test_drop_old(self):
        self.__receive(parse_tnc2('FOO>RX:>', _dummy_receive_time))
        self.assertEqual(['FOO'], self.store.state().keys())
        self.clock.advance(1799.5)
        self.__receive(parse_tnc2('BAR>RX:>', _dummy_receive_time + 1799.5))
        self.assertEqual({'BAR', 'FOO'}, set(self.store.state().keys()))
        self.clock.advance(0.5)
        self.__receive(parse_tnc2('BAR>RX:>', _dummy_receive_time + 1800))
        self.assertEqual(['BAR'], self.store.state().keys())
Exemplo n.º 4
0
class TestAPRSTelemetryStore(unittest.TestCase):
    """
    This is a test of APRSStation's implementation of ITelemetryObject.
    """
    
    def setUp(self):
        self.clock = Clock()
        self.clock.advance(_dummy_receive_time)
        self.store = TelemetryStore(time_source=self.clock)
    
    def __receive(self, msg):
        expand_aprs_message(msg, self.store)
    
    def test_new_station(self):
        self.assertEqual([], self.store.state().keys())
        self.__receive(parse_tnc2(
            'N6WKZ-3>APU25N,WB6TMS-3*,N6ZX-3*,WIDE2*:=3746.42N112226.00W# {UIV32N}',
            _dummy_receive_time))
        self.assertEqual(['N6WKZ-3'], self.store.state().keys())

    # TODO: this test makes less sense now that expand_aprs_message is separate
    def test_object_item_report(self):
        self.__receive(parse_tnc2(
            'KE6AFE-2>APU25N,WR6ABD*,NCA1:;TFCSCRUZ *160323z3655.94N\12200.92W?70 In 10 Minutes',
            _dummy_receive_time))
        self.assertEqual({'KE6AFE-2', 'TFCSCRUZ '}, set(self.store.state().keys()))
        # TODO test value of object

    def test_object_kill(self):
        self.__receive(parse_tnc2(
            'KE6AFE-2>APU25N,WR6ABD*,NCA1:;TFCSCRUZ *160323z3655.94N\12200.92W?70 In 10 Minutes',
            _dummy_receive_time))
        self.assertEqual({'KE6AFE-2', 'TFCSCRUZ '}, set(self.store.state().keys()))
        self.__receive(parse_tnc2(
            'FOO>BAR:;TFCSCRUZ _160323z3655.94N\12200.92W?',
            _dummy_receive_time))
        self.clock.advance(0)
        self.assertEqual({'FOO', 'KE6AFE-2'}, set(self.store.state().keys()))

    def test_drop_old(self):
        self.__receive(parse_tnc2('FOO>RX:>', _dummy_receive_time))
        self.assertEqual(['FOO'], self.store.state().keys())
        self.clock.advance(1799.5)
        self.__receive(parse_tnc2('BAR>RX:>', _dummy_receive_time + 1799.5))
        self.assertEqual({'BAR', 'FOO'}, set(self.store.state().keys()))
        self.clock.advance(0.5)
        self.__receive(parse_tnc2('BAR>RX:>', _dummy_receive_time + 1800))
        self.assertEqual(['BAR'], self.store.state().keys())
Exemplo n.º 5
0
 def setUp(self):
     self.clock = Clock()
     self.clock.advance(1000)
     self.store = TelemetryStore(time_source=self.clock)
Exemplo n.º 6
0
class TestTelemetryStore(unittest.TestCase):
    def setUp(self):
        self.clock = Clock()
        self.clock.advance(1000)
        self.store = TelemetryStore(time_source=self.clock)

    def test_new_object(self):
        self.assertEqual([], self.store.state().keys())
        self.store.receive(Msg("foo", 1000))
        self.assertEqual(["foo"], self.store.state().keys())
        obj = self.store.state()["foo"].get()
        self.assertIsInstance(obj, Obj)

    def test_receive_called(self):
        self.store.receive(Msg("foo", 1000, 1))
        obj = self.store.state()["foo"].get()
        self.assertEquals(obj.last_msg, 1)
        self.store.receive(Msg("foo", 1000, 2))
        self.assertEquals(obj.last_msg, 2)

    def test_drop_old(self):
        self.store.receive(Msg("foo", 1000))
        self.assertEqual(["foo"], self.store.state().keys())
        self.clock.advance(1799.5)
        self.store.receive(Msg("bar", 2799.5))
        self.assertEqual({"bar", "foo"}, set(self.store.state().keys()))
        self.clock.advance(0.5)
        self.store.receive(Msg("bar", 2800))
        self.assertEqual(["bar"], self.store.state().keys())

    def test_become_interesting(self):
        self.store.receive(Msg("foo", 1000, "boring"))
        self.assertEqual([], self.store.state().keys())
        self.store.receive(Msg("foo", 1001, "interesting"))
        self.assertEqual(["foo"], self.store.state().keys())
        # 'become boring' is not implemented, so also not tested yet

    def test_drop_old_boring(self):
        """
        Make sure that dropping a boring object doesn't fail.
        """
        self.store.receive(Msg("foo", 1000, "boring"))
        self.assertEqual([], self.store.state().keys())
        self.clock.advance(1800)
        self.store.receive(Msg("bar", 2800, "boring"))
        self.assertEqual([], self.store.state().keys())
Exemplo n.º 7
0
class TestTelemetryStore(unittest.TestCase):
    def setUp(self):
        self.clock = SlightlyBetterClock()
        self.clock.advance(1000)
        self.store = TelemetryStore(time_source=self.clock)
    
    def test_new_object(self):
        self.assertEqual(set(), set(self.store.state().keys()))
        self.store.receive(Msg('foo', 1000))
        self.assertEqual({'foo'}, set(self.store.state().keys()))
        obj = self.store.state()['foo'].get()
        self.assertIsInstance(obj, Obj)
    
    def test_receive_called(self):
        self.store.receive(Msg('foo', 1000, 1))
        obj = self.store.state()['foo'].get()
        self.assertEqual(obj.last_msg, 1)
        self.store.receive(Msg('foo', 1000, 2))
        self.assertEqual(obj.last_msg, 2)
    
    def test_drop_old(self):
        self.store.receive(Msg('foo', 1000))
        self.assertEqual({'foo'}, set(self.store.state().keys()))

        self.clock.advance(1799.5)
        self.store.receive(Msg('bar', 2799.5))
        self.assertEqual({'bar', 'foo'}, set(self.store.state().keys()))

        self.clock.advance(0.5)
        self.assertEqual({'bar'}, set(self.store.state().keys()))

        self.clock.advance(10000)
        self.assertEqual(set(), set(self.store.state().keys()))

        # Expect complete cleanup -- that is, even if a TelemetryStore is created, filled, and thrown away, it will eventually be garbage collected when the objects expire.
        self.assertEqual(set(), set(self.clock.getDelayedCalls()))
    
    def test_become_interesting(self):
        self.store.receive(Msg('foo', 1000, 'boring'))
        self.assertEqual(set(), set(self.store.state().keys()))
        self.store.receive(Msg('foo', 1001, 'interesting'))
        self.assertEqual({'foo'}, set(self.store.state().keys()))
        # 'become boring' is not implemented, so also not tested yet
    
    def test_drop_old_boring(self):
        """
        Make sure that dropping a boring object doesn't fail.
        """
        self.store.receive(Msg('foo', 1000, 'boring'))
        self.assertEqual(set(), set(self.store.state().keys()))
        self.clock.advance(1800)
        self.store.receive(Msg('bar', 2800, 'boring'))
        self.assertEqual(set(), set(self.store.state().keys()))

    def test_expire_in_the_past(self):
        """
        An ITelemetryObject expiring in the past is not an error.
        """
        self.clock.advance(10000)
        self.store.receive(Msg('foo', 0, 'long ago'))
        self.clock.advance(2000)
Exemplo n.º 8
0
 def setUp(self):
     self.clock = Clock()
     self.clock.advance(_dummy_receive_time)
     self.store = TelemetryStore(time_source=self.clock)
Exemplo n.º 9
0
 def setUp(self):
     self.clock = Clock()
     self.clock.advance(1000)
     self.store = TelemetryStore(time_source=self.clock)
Exemplo n.º 10
0
class TestTelemetryStore(unittest.TestCase):
    def setUp(self):
        self.clock = Clock()
        self.clock.advance(1000)
        self.store = TelemetryStore(time_source=self.clock)

    def test_new_object(self):
        self.assertEqual([], self.store.state().keys())
        self.store.receive(Msg('foo', 1000))
        self.assertEqual(['foo'], self.store.state().keys())
        obj = self.store.state()['foo'].get()
        self.assertIsInstance(obj, Obj)

    def test_receive_called(self):
        self.store.receive(Msg('foo', 1000, 1))
        obj = self.store.state()['foo'].get()
        self.assertEquals(obj.last_msg, 1)
        self.store.receive(Msg('foo', 1000, 2))
        self.assertEquals(obj.last_msg, 2)

    def test_drop_old(self):
        self.store.receive(Msg('foo', 1000))
        self.assertEqual(['foo'], self.store.state().keys())
        self.clock.advance(1799.5)
        self.store.receive(Msg('bar', 2799.5))
        self.assertEqual({'bar', 'foo'}, set(self.store.state().keys()))
        self.clock.advance(0.5)
        self.store.receive(Msg('bar', 2800))
        self.assertEqual(['bar'], self.store.state().keys())

    def test_become_interesting(self):
        self.store.receive(Msg('foo', 1000, 'boring'))
        self.assertEqual([], self.store.state().keys())
        self.store.receive(Msg('foo', 1001, 'interesting'))
        self.assertEqual(['foo'], self.store.state().keys())
        # 'become boring' is not implemented, so also not tested yet

    def test_drop_old_boring(self):
        """
        Make sure that dropping a boring object doesn't fail.
        """
        self.store.receive(Msg('foo', 1000, 'boring'))
        self.assertEqual([], self.store.state().keys())
        self.clock.advance(1800)
        self.store.receive(Msg('bar', 2800, 'boring'))
        self.assertEqual([], self.store.state().keys())
Exemplo n.º 11
0
class TestTelemetryStore(unittest.TestCase):
    def setUp(self):
        self.clock = SlightlyBetterClock()
        self.clock.advance(1000)
        self.store = TelemetryStore(time_source=self.clock)

    def test_new_object(self):
        self.assertEqual([], self.store.state().keys())
        self.store.receive(Msg('foo', 1000))
        self.assertEqual(['foo'], self.store.state().keys())
        obj = self.store.state()['foo'].get()
        self.assertIsInstance(obj, Obj)

    def test_receive_called(self):
        self.store.receive(Msg('foo', 1000, 1))
        obj = self.store.state()['foo'].get()
        self.assertEquals(obj.last_msg, 1)
        self.store.receive(Msg('foo', 1000, 2))
        self.assertEquals(obj.last_msg, 2)

    def test_drop_old(self):
        self.store.receive(Msg('foo', 1000))
        self.assertEqual(['foo'], self.store.state().keys())

        self.clock.advance(1799.5)
        self.store.receive(Msg('bar', 2799.5))
        self.assertEqual({'bar', 'foo'}, set(self.store.state().keys()))

        self.clock.advance(0.5)
        self.assertEqual({'bar'}, set(self.store.state().keys()))

        self.clock.advance(10000)
        self.assertEqual([], self.store.state().keys())

        # Expect complete cleanup -- that is, even if a TelemetryStore is created, filled, and thrown away, it will eventually be garbage collected when the objects expire.
        self.assertEqual([], self.clock.getDelayedCalls())

    def test_become_interesting(self):
        self.store.receive(Msg('foo', 1000, 'boring'))
        self.assertEqual([], self.store.state().keys())
        self.store.receive(Msg('foo', 1001, 'interesting'))
        self.assertEqual(['foo'], self.store.state().keys())
        # 'become boring' is not implemented, so also not tested yet

    def test_drop_old_boring(self):
        """
        Make sure that dropping a boring object doesn't fail.
        """
        self.store.receive(Msg('foo', 1000, 'boring'))
        self.assertEqual([], self.store.state().keys())
        self.clock.advance(1800)
        self.store.receive(Msg('bar', 2800, 'boring'))
        self.assertEqual([], self.store.state().keys())

    def test_expire_in_the_past(self):
        """
        An ITelemetryObject expiring in the past is not an error.
        """
        self.clock.advance(10000)
        self.store.receive(Msg('foo', 0, 'long ago'))
        self.clock.advance(2000)
Exemplo n.º 12
0
 def setUp(self):
     self.clock = Clock()
     self.clock.advance(_dummy_receive_time)
     self.store = TelemetryStore(time_source=self.clock)
Exemplo n.º 13
0
    def __init__(self, devices={}, audio_config=None, features=_STUB_FEATURES):
        # pylint: disable=dangerous-default-value
        if len(devices) <= 0:
            raise ValueError(
                'Must be configured with at least one RF device! (This should normally be caught by the configuration validator.)'
            )

        gr.top_block.__init__(self, type(self).__name__)
        self.__running = False  # duplicate of GR state we can't reach, see __start_or_stop
        self.__has_a_useful_receiver = False

        # Configuration
        # TODO: device refactoring: Remove vestigial 'accessories'
        self._sources = CellDict(
            {k: d
             for k, d in six.iteritems(devices) if d.can_receive()})
        self._accessories = accessories = {
            k: d
            for k, d in six.iteritems(devices) if not d.can_receive()
        }
        for key in self._sources:
            # arbitrary valid initial value
            self.source_name = key
            break
        self.__rx_device_type = EnumT(
            {k: v.get_name() or k
             for (k, v) in six.iteritems(self._sources)})

        # Audio early setup
        self.__audio_manager = AudioManager(  # must be before contexts
            graph=self,
            audio_config=audio_config,
            stereo=features['stereo'])

        # Blocks etc.
        # TODO: device refactoring: remove 'source' concept (which is currently a device)
        # TODO: remove legacy no-underscore names, maybe get rid of self.source
        self.source = None
        self.__monitor_rx_driver = None
        self.monitor = MonitorSink(
            signal_type=SignalType(
                sample_rate=10000,
                kind='IQ'),  # dummy value will be updated in _do_connect
            context=Context(self))
        self.monitor.get_interested_cell().subscribe2(
            self.__start_or_stop_later, the_subscription_context)
        self.__clip_probe = MaxProbe()

        # Receiver blocks (multiple, eventually)
        self._receivers = CellDict(dynamic=True)
        self._receiver_valid = {}

        # collections
        # TODO: No longer necessary to have these non-underscore names
        self.sources = CollectionState(CellDict(self._sources))
        self.receivers = ReceiverCollection(self._receivers, self)
        self.accessories = CollectionState(CellDict(accessories))
        self.__telemetry_store = TelemetryStore()

        # Flags, other state
        self.__needs_reconnect = [u'initialization']
        self.__in_reconnect = False
        self.receiver_key_counter = 0
        self.receiver_default_state = {}

        # Initialization

        def hookup_vfo_callback(
                k, d):  # function so as to not close over loop variable
            d.get_vfo_cell().subscribe2(
                lambda value: self.__device_vfo_callback(k),
                the_subscription_context)

        for k, d in six.iteritems(devices):
            hookup_vfo_callback(k, d)

        device_context = DeviceContext(self.__telemetry_store.receive)
        for device in six.itervalues(devices):
            device.attach_context(device_context)

        self._do_connect()