Example #1
0
    def __init__(self,
                 link,
                 device_uid=None,
                 base=DEFAULT_BASE,
                 whitelist=None):
        """
    Traits tab with UI for UDP broadcast of SBP.

    Parameters
    ----------
    link : sbp.client.handler.Handler
      Link for SBP transfer to/from Piksi.
    device_uid : str
      Piksi Device UUID (defaults to None)
    base : str
      HTTP endpoint
    whitelist : [int] | None
      Piksi Device UUID (defaults to None)

    """
        self.link = link
        self.http = HTTPDriver(None, base)
        self.net_link = None
        self.fwd = None
        self.func = None
        # Whitelist used for UDP broadcast view
        self.msgs = OBS_MSGS
        # register a callback when the msg_enum trait changes
        self.on_trait_change(self.update_msgs, 'msg_enum')
        # Whitelist used for Skylark broadcasting
        self.whitelist = whitelist
        self.device_uid = None
        self.python_console_cmds = {'update': self}
Example #2
0
def test_http_test_pass():
    assert is_enabled()
    msg = MsgPrintDep(text='abcd')
    register_uri(GET,
                 BASE_STATION_URI,
                 msg.to_binary(),
                 content_type="application/vnd.swiftnav.broker.v1+sbp2")
    register_uri(PUT,
                 BASE_STATION_URI,
                 '',
                 content_type="application/vnd.swiftnav.broker.v1+sbp2")
    with HTTPDriver(device_uid="Swift22", url=BASE_STATION_URI) as driver:
        assert not driver.read_ok
        assert driver.connect_read()
        assert driver.read_ok
        assert driver.read(size=255) == msg.to_binary()
        with pytest.raises(IOError):
            assert driver.read(size=255)
        assert not driver.read_close()
        assert driver.read_response is None
        assert not driver.read_ok
        with pytest.raises(ValueError):
            driver.read(size=255)
    with HTTPDriver(device_uid="Swift22", url=BASE_STATION_URI) as http:
        with Handler(Framer(http.read, http.write, False)) as link:

            def tester(sbp_msg, **metadata):
                assert sbp_msg.payload == msg.payload

            link.add_callback(SBP_MSG_PRINT_DEP, tester)
            t0 = time.time()
            sleep = 0.1
            while True:
                if time.time() - t0 < sleep:
                    break
Example #3
0
def test_http_test_pass_retry():
    assert is_enabled()
    msg = MsgPrintDep(text='abcd')
    get_responses = [
        Response(body="first response",
                 status=500,
                 content_type="application/vnd.swiftnav.broker.v1+sbp2"),
        Response(body='second and last response',
                 status=200,
                 content_type="application/vnd.swiftnav.broker.v1+sbp2")
    ]
    post_responses = [
        Response(body="",
                 status=500,
                 content_type="application/vnd.swiftnav.broker.v1+sbp2"),
        Response(body='',
                 status=200,
                 content_type="application/vnd.swiftnav.broker.v1+sbp2")
    ]
    register_uri(GET, BASE_STATION_URI, get_responses)
    register_uri(PUT, BASE_STATION_URI, post_responses)
    with HTTPDriver(device_uid="Swift22", url=BASE_STATION_URI) as driver:
        with pytest.raises(ValueError):
            driver.read(size=255)
        assert driver.connect_read()
        assert driver.read(size=255)
Example #4
0
def test_http_test_pass_streaming():
    assert is_enabled()
    msgs = [
        MsgPrintDep(text='foo'),
        MsgPrintDep(text='bar'),
        MsgPrintDep(text='baz')
    ]
    register_uri(GET,
                 BASE_STATION_URI,
                 mock_streaming_msgs([m.to_binary() for m in msgs]),
                 content_type="application/vnd.swiftnav.broker.v1+sbp2",
                 streaming=True)
    register_uri(PUT,
                 BASE_STATION_URI,
                 body='',
                 content_type="application/vnd.swiftnav.broker.v1+sbp2",
                 streaming=True)
    with HTTPDriver(device_uid="Swift22", url=BASE_STATION_URI) as driver:
        assert driver.connect_read()
        assert driver.read_ok
        assert driver.read(size=255) == ''.join([m.to_binary() for m in msgs])
        assert driver.read(size=255) == ''
        assert not driver.read_close()
        assert driver.read_response is None
        assert not driver.read_ok
        with pytest.raises(ValueError):
            driver.read(size=255)
  def __init__(self, link, device_uid=None, base=DEFAULT_BASE, whitelist=None):
    """
    Traits tab with UI for UDP broadcast of SBP.

    Parameters
    ----------
    link : sbp.client.handler.Handler
      Link for SBP transfer to/from Piksi.
    device_uid : str
      Piksi Device UUID (defaults to None)
    base : str
      HTTP endpoint
    whitelist : [int] | None
      Piksi Device UUID (defaults to None)

    """
    self.link = link
    self.http = HTTPDriver(None, base)
    self.net_link = None
    self.fwd = None
    self.func = None
    # Whitelist used for UDP broadcast view
    self.msgs = OBS_MSGS
    # register a callback when the msg_enum trait changes
    self.on_trait_change(self.update_msgs, 'msg_enum')
    # Whitelist used for Skylark broadcasting
    self.whitelist = whitelist
    self.device_uid = None
    self.python_console_cmds = {'update': self}
Example #6
0
def main(args):
    """
    Get configuration, get driver, get logger, and build handler and start it.
    """
    timeout = args.timeout
    log_filename = args.logfilename
    log_dirname = args.log_dirname
    if not log_filename:
        log_filename = logfilename()
    if log_dirname:
        log_filename = os.path.join(log_dirname, log_filename)
    # State for handling a networked base stations.
    channel = args.channel_id
    serial_id = int(args.serial_id) if args.serial_id is not None else None
    base = args.base
    use_broker = args.broker
    # Driver with context
    driver = get_base_args_driver(args)
    with Handler(Framer(driver.read, driver.write, args.verbose)) as link:
        # Logger with context
        with get_logger(args.log, log_filename, args.expand_json) as logger:
            link.add_callback(printer, SBP_MSG_PRINT_DEP)
            link.add_callback(log_printer, SBP_MSG_LOG)
            Forwarder(link, logger).start()
            if use_broker and base and serial_id:
                device_id = get_uuid(channel, serial_id)
                with HTTPDriver(str(device_id), base) as http:
                    with Handler(Framer(http.read, http.write,
                                        args.verbose)) as slink:
                        Forwarder(slink, swriter(link)).start()
                        run(args, link)
            else:
                run(args, link)
Example #7
0
def main(args):
  """
  Get configuration, get driver, get logger, and build handler and start it.
  """
  port = args.port
  baud = args.baud
  timeout = args.timeout
  log_filename = args.log_filename
  append_log_filename = args.append_log_filename
  tags = args.tags
  # State for handling a networked base stations.
  channel = args.channel_id
  serial_id = int(args.serial_id) if args.serial_id is not None else None
  base = args.base
  use_broker = args.broker
  # Driver with context
  with get_driver(args.ftdi, port, baud, args.file) as driver:
    # Handler with context
    with Handler(Framer(driver.read, driver.write, args.verbose)) as link:
      # Logger with context
      with get_logger(args.log, log_filename) as logger:
        with get_append_logger(append_log_filename, tags) as append_logger:
          link.add_callback(printer, SBP_MSG_PRINT_DEP)
          link.add_callback(log_printer, SBP_MSG_LOG)
          Forwarder(link, logger).start()
          Forwarder(link, append_logger).start()
          if use_broker and base and serial_id:
            device_id = get_uuid(channel, serial_id)
            with HTTPDriver(str(device_id), base) as http:
              with Handler(Framer(http.read, http.write, args.verbose)) as slink:
                Forwarder(slink, swriter(link)).start()
                run(args, link)
          else:
            run(args, link)
Example #8
0
def test_http_test_pass():
    assert is_enabled()
    msg = MsgPrintDep(text='abcd')
    register_uri(GET,
                 BASE_STATION_URI,
                 msg.to_binary(),
                 content_type="application/vnd.swiftnav.broker.v1+sbp")
    with HTTPDriver(device_uid="Swift22", url=BASE_STATION_URI) as driver:
        assert driver.read(size=255) == msg.to_binary()
Example #9
0
def test_http_test_fail():
    assert is_enabled()
    msg = MsgPrintDep(text='abcd')
    register_uri(GET,
                 BASE_STATION_URI,
                 msg.to_binary(),
                 content_type="application/vnd.swiftnav.broker.v1+sbp",
                 status=400)
    with HTTPDriver(device_uid="Swift22", url=BASE_STATION_URI) as driver:
        with pytest.raises(RuntimeError) as exc_info:
            driver.read(size=255)
    assert exc_info.value.message.startswith("Request failed! With code 400:")
Example #10
0
def main(args):
    """
    Get configuration, get driver, get logger, and build handler and start it.
    """
    port = args.port
    baud = args.baud
    timeout = args.timeout
    log_filename = args.logfilename
    log_dirname = args.log_dirname
    if not log_filename:
        log_filename = logfilename()
    if log_dirname:
        log_filename = os.path.join(log_dirname, log_filename)
    append_log_filename = args.append_log_filename
    tags = args.tags
    # State for handling a networked base stations.
    channel = args.channel_id
    serial_id = int(args.serial_id) if args.serial_id is not None else None
    base = args.base
    use_broker = args.broker
    # Driver with context
    if args.tcp:
        try:
            host, port = port.split(':')
            driver = TCPDriver(host, int(port))
        except:  # noqa
            raise Exception('Invalid host and/or port')
    else:
        driver = get_driver(args.ftdi,
                            port,
                            baud,
                            args.file,
                            rtscts=args.rtscts)
        # Handler with context
    with Handler(Framer(driver.read, driver.write, args.verbose)) as link:
        # Logger with context
        with get_logger(args.log, log_filename, args.expand_json) as logger:
            with get_append_logger(append_log_filename, tags) as append_logger:
                link.add_callback(printer, SBP_MSG_PRINT_DEP)
                link.add_callback(log_printer, SBP_MSG_LOG)
                Forwarder(link, logger).start()
                Forwarder(link, append_logger).start()
                if use_broker and base and serial_id:
                    device_id = get_uuid(channel, serial_id)
                    with HTTPDriver(str(device_id), base) as http:
                        with Handler(
                                Framer(http.read, http.write,
                                       args.verbose)) as slink:
                            Forwarder(slink, swriter(link)).start()
                            run(args, link)
                else:
                    run(args, link)
Example #11
0
def test_http_test_pass_streaming():
    assert is_enabled()
    msgs = [
        MsgPrintDep(text='foo'),
        MsgPrintDep(text='bar'),
        MsgPrintDep(text='baz')
    ]
    register_uri(GET,
                 BASE_STATION_URI,
                 mock_streaming_msgs([m.to_binary() for m in msgs]),
                 content_type="application/vnd.swiftnav.broker.v1+sbp",
                 streaming=True)
    with HTTPDriver(device_uid="Swift22", url=BASE_STATION_URI) as driver:
        assert driver.read(size=255) == ''.join([m.to_binary() for m in msgs])
Example #12
0
def test_http_test_fail():
    assert is_enabled()
    msg = MsgPrintDep(text='abcd')
    register_uri(GET,
                 BASE_STATION_URI,
                 msg.to_binary(),
                 content_type="application/vnd.swiftnav.broker.v1+sbp2",
                 status=400)
    register_uri(PUT,
                 BASE_STATION_URI,
                 '',
                 content_type="application/vnd.swiftnav.broker.v1+sbp2",
                 status=400)
    with HTTPDriver(device_uid="Swift22", url=BASE_STATION_URI) as driver:
        assert not driver.connect_read()
        assert not driver.read_ok
        with pytest.raises(IOError):
            driver.read(size=255)
Example #13
0
class SbpRelayView(HasTraits):
  """
  UDP Relay view- Class allows user to specify port, IP address, and message set
  to relay over UDP
  """
  running = Bool(False)
  configured = Bool(False)
  broadcasting = Bool(False)
  msg_enum = Enum('Observations', 'All')
  ip_ad = String(DEFAULT_UDP_ADDRESS)
  port = Int(DEFAULT_UDP_PORT)
  information = String('UDP Streaming\n\nBroadcast SBP information received by'
    ' the console to other machines or processes over UDP. With the \'Observations\''
    ' radio button selected, the console will broadcast the necessary information'
    ' for a rover Piksi to acheive an RTK solution.'
    '\n\nThis can be used to stream observations to a remote Piksi through'
    ' aircraft telemetry via ground control software such as MAVProxy or'
    ' Mission Planner.')
  http_information = String('Skylark - Experimental Piksi Networking\n\n'
                            "Skylark is Swift Navigation's Internet service for connecting Piksi receivers without the use of a radio. To receive GPS observations from the closest nearby Piksi base station (within 5km), click Connect to Skylark.\n\n")
  start = Button(label='Start', toggle=True, width=32)
  stop = Button(label='Stop', toggle=True, width=32)
  connected_rover = Bool(False)
  connect_rover = Button(label='Connect to Skylark', toggle=True, width=32)
  disconnect_rover = Button(label='Disconnect from Skylark', toggle=True, width=32)
  base_pragma = String()
  rover_pragma = String()
  toggle=True
  view = View(
           VGroup(
             spring,
             HGroup(
               VGroup(
                 Item('running', show_label=True, style='readonly', visible_when='running'),
                 Item('msg_enum', label="Messages to broadcast",
                      style='custom', enabled_when='not running'),
                 Item('ip_ad', label='IP Address', enabled_when='not running'),
                 Item('port', label="Port", enabled_when='not running'),
                 HGroup(
                   spring,
                   UItem('start', enabled_when='not running', show_label=False),
                   UItem('stop', enabled_when='running', show_label=False),
                   spring)),
               VGroup(
                 Item('information', label="Notes", height=10,
                      editor=MultilineTextEditor(TextEditor(multi_line=True)), style='readonly',
                      show_label=False, resizable=True, padding=15),
                 spring,
               ),
             ),
             spring,
             HGroup(
               VGroup(
                 HGroup(
                   spring,
                   UItem('connect_rover', enabled_when='not connected_rover', show_label=False),
                   UItem('disconnect_rover', enabled_when='connected_rover', show_label=False),
                   spring),
                 HGroup(spring,
                        Item('base_pragma',  label='Base option '),
                        spring),
                 HGroup(spring,
                        Item('rover_pragma', label='Rover option'),
                        spring),),
               VGroup(
                 Item('http_information', label="Notes", height=10,
                      editor=MultilineTextEditor(TextEditor(multi_line=True)), style='readonly',
                      show_label=False, resizable=True, padding=15),
                 spring,
               ),
             ),
             spring
           )
  )

  def __init__(self, link, device_uid=None, base=DEFAULT_BASE, whitelist=None):
    """
    Traits tab with UI for UDP broadcast of SBP.

    Parameters
    ----------
    link : sbp.client.handler.Handler
      Link for SBP transfer to/from Piksi.
    device_uid : str
      Piksi Device UUID (defaults to None)
    base : str
      HTTP endpoint
    whitelist : [int] | None
      Piksi Device UUID (defaults to None)

    """
    self.link = link
    self.http = HTTPDriver(None, base)
    self.net_link = None
    self.fwd = None
    self.func = None
    # Whitelist used for UDP broadcast view
    self.msgs = OBS_MSGS
    # register a callback when the msg_enum trait changes
    self.on_trait_change(self.update_msgs, 'msg_enum')
    # Whitelist used for Skylark broadcasting
    self.whitelist = whitelist
    self.device_uid = None
    self.python_console_cmds = {'update': self}

  def update_msgs(self):
    """Updates the instance variable msgs which store the msgs that we
    will send over UDP.

    """
    if self.msg_enum == 'Observations':
      self.msgs = OBS_MSGS
    elif self.msg_enum == 'All':
      self.msgs = [None]
    else:
      raise NotImplementedError

  def set_route(self, serial_id, channel=CHANNEL_UUID):
    """Sets serial_id hash for HTTP headers.

    Parameters
    ----------
    serial_id : int
      Piksi device ID
    channel : str
      UUID namespace for device UUID

    """
    device_uid = str(get_uuid(channel, serial_id))
    self.device_uid = device_uid
    if self.http:
      self.http.device_uid = device_uid

  def _prompt_networking_error(self, text):
    """Nonblocking prompt for a networking error.

    Parameters
    ----------
    text : str
      Helpful error message for the user

    """
    prompt = CallbackPrompt(title="Networking Error", actions=[close_button])
    prompt.text = text
    prompt.run(block=False)

  def _prompt_setting_error(self, text):
    """Nonblocking prompt for a device setting error.

    Parameters
    ----------
    text : str
      Helpful error message for the user

    """
    prompt = CallbackPrompt(title="Setting Error", actions=[close_button])
    prompt.text = text
    prompt.run(block=False)

  def _retry_read(self):
    """Retry read connections. Intended to be called by
    _connect_rover_fired.

    """
    i = 0
    repeats = 5
    _rover_pragma = self.rover_pragma
    while self.http and not self.http.connect_read(pragma=_rover_pragma):
      print "Attempting to read observation from Skylark..."
      time.sleep(0.1)
      i += 1
      if i >= repeats:
        msg = ("\nUnable to receive observations from Skylark!\n\n"
               "Please check that:\n"
               " - you have a network connection\n"
               " - your Piksi has a single-point position\n"
               " - a Skylark-connected Piksi receiver \n   is nearby (within 5km)")
        self._prompt_networking_error(msg)
        self.http.read_close()
        return
    print "Connected as a rover!"
    with Handler(Framer(self.http.read, self.http.write)) as net_link:
      self.net_link = net_link
      self.fwd = Forwarder(net_link, swriter(self.link))
      self.fwd.start()
      while True:
        time.sleep(1)
        if not net_link.is_alive():
          sys.stderr.write("Network observation stream disconnected!")
          break

  def _connect_rover_fired(self):
    """Handle callback for HTTP rover connections.

    """
    if not self.device_uid:
      msg = "\nDevice ID not found!\n\nConnection requires a valid Piksi device ID."
      self._prompt_setting_error(msg)
      return
    if not self.http:
      self._prompt_networking_error("\nNetworking disabled!")
      return
    try:
      _base_pragma = self.base_pragma
      if not self.http.connect_write(self.link, self.whitelist, pragma=_base_pragma):
        msg = ("\nUnable to connect to Skylark!\n\n"
               "Please check that you have a network connection.")
        self._prompt_networking_error(msg)
        self.http.close()
        self.connected_rover = False
        return
      self.connected_rover = True
      print "Connected as a base station!"
      executor = ThreadPoolExecutor(max_workers=2)
      executor.submit(self._retry_read)
    except:
      self.connected_rover = False
      import traceback
      print traceback.format_exc()

  def _disconnect_rover_fired(self):
    """Handle callback for HTTP rover disconnects.

    """
    if not self.device_uid:
      msg = "\nDevice ID not found!\n\nConnection requires a valid Piksi device ID."
      self._prompt_setting_error(msg)
      return
    if not self.http:
      self._prompt_networking_error("\nNetworking disabled!")
      return
    try:
      if self.connected_rover:
        self.http.close()
        self.connected_rover = False
        if self.fwd and self.net_link:
          self.net_link.stop()
    except:
      self.connected_rover = False
      import traceback
      print traceback.format_exc()

  def _start_fired(self):
    """Handle start udp broadcast button. Registers callbacks on
    self.link for each of the self.msgs If self.msgs is None, it
    registers one generic callback for all messages.

    """
    self.running = True
    try:
      self.func = UdpLogger(self.ip_ad, self.port)
      self.link.add_callback(self.func, self.msgs)
    except:
      import traceback
      print traceback.format_exc()

  def _stop_fired(self):
    """Handle the stop udp broadcast button. It uses the self.funcs and
    self.msgs to remove the callbacks that were registered when the
    start button was pressed.

    """
    try:
      self.link.remove_callback(self.func, self.msgs)
      self.func.__exit__()
      self.func = None
      self.running = False
    except:
      import traceback
      print traceback.format_exc()
Example #14
0
            traceback.print_exc()


# Make sure that SIGINT (i.e. Ctrl-C from command line) actually stops the
# application event loop (otherwise Qt swallows KeyboardInterrupt exceptions)
signal.signal(signal.SIGINT, signal.SIG_DFL)

# Passing only a base station argument, we just want to display the
# base station data in the console. Otherwise, continue, assuming a
# rover connected to the serial port.
if port is None and base is None:
    sys.stderr.write("ERROR: No data source specified!")
    sys.exit(1)
if port is None and base and use_broker:
    device_id = get_uuid(channel, serial_id)
    with HTTPDriver(str(device_id), base) as http_driver:
        with sbpc.Handler(sbpc.Framer(http_driver.read, None,
                                      args.verbose)) as link:
            if os.path.isdir(log_filename):
                log_filename = os.path.join(log_filename, s.LOG_FILENAME)
            with s.get_logger(args.log, log_filename) as logger:
                link.add_callback(logger)
                log_filter = DEFAULT_LOG_LEVEL_FILTER
                if args.initloglevel[0]:
                    log_filter = args.initloglevel[0]
                SwiftConsole(link, args.update, log_filter,
                             True).configure_traits()
    try:
        os._exit(0)
    except:
        pass
Example #15
0
  def connect(self, link, read_config):
    """Retry read connections. Intended to be called when thread started
    Only shared resource here is the self.link
    Parameters
    ----------
    link : SbpHandler
    read_config :  SkylarkConsoleConnectConfig object 
    
    Returns
    ----------
    ret : int
       0 if exited normally by thread stopping
      -1 if unable to connect as base station
      -2 if unable to connect as rover
      -3 if we lost our net connection to skylark (we restart in this case unless stopped)

    """
    assert isinstance(read_config, SkylarkConsoleConnectConfig)
    self._connect_time = time.time()
    if self.verbose:
      print(("SkylarkWatchdogThread connection attempted at time {0} with parameters {1}".format(
                 self.get_connect_time(), read_config))) 
    i = 0
    repeats = 5
    http = HTTPDriver(device_uid=read_config.base_uuid, url=read_config.skylark_url)
    if not http.connect_write(link, read_config.whitelist, pragma=read_config.base_pragma):
        msg = ("\nUnable to connect to Skylark!\n\n" + 
               "Please check that you have a network connection.")
        self._prompt_networking_error(msg)
        http.close()
        self.stop()
        return -1 # unable to connect as base
    time.sleep(1)

    # If we get here, we were able to connect as a base
    print("Attempting to read observation from Skylark...")
    while (not self.stopped() and http 
           and not http.connect_read(device_uid=read_config.rover_uuid, pragma=read_config.rover_pragma)):
      time.sleep(0.1)
      i += 1
      if i >= repeats:
        msg = ("\nUnable to receive observations from Skylark!\n\n"
               "Please check that:\n"
               " - you have a network connection\n"
               " - your Piksi has a single-point position\n"
               " - a Skylark-connected Piksi receiver \n   is nearby (within 5km)")
        self._prompt_networking_error(msg)
        http.close()
        self.stop()
        return -2 # Unable to connect as rover

    # If we get here, we were able to connect as rover
    print("Connected as a rover!")
    with Handler(Framer(http.read, http.write)) as net_link:
      fwd = Forwarder(net_link, swriter(link))
      if self.verbose:
        print("Starting forwarder")
      fwd.start()
      # now we sleep until we stop the thread or our http handler dies
      while not self.stopped() and net_link.is_alive():
          time.sleep(0.1)

    # when we leave this loop, we are no longer connected to skylark so the fwd should be stopped
    if self.verbose:
      print("Stopping forwarder")
    fwd.stop()
    if self.verbose:
      print("Stopping HTTPDriver")
    http.close() 
    # now manage the return code
    if self.stopped():
      return 0 # If we stop from the event, it it intended and we return 0
    else:
      return -3 # Lost connection
Example #16
0
class SbpRelayView(HasTraits):
    """
  UDP Relay view- Class allows user to specify port, IP address, and message set
  to relay over UDP
  """
    running = Bool(False)
    configured = Bool(False)
    broadcasting = Bool(False)
    msg_enum = Enum('Observations', 'All')
    ip_ad = String(DEFAULT_UDP_ADDRESS)
    port = Int(DEFAULT_UDP_PORT)
    information = String(
        'UDP Streaming\n\nBroadcast SBP information received by'
        ' the console to other machines or processes over UDP. With the \'Observations\''
        ' radio button selected, the console will broadcast the necessary information'
        ' for a rover Piksi to acheive an RTK solution.'
        '\n\nThis can be used to stream observations to a remote Piksi through'
        ' aircraft telemetry via ground control software such as MAVProxy or'
        ' Mission Planner.')
    http_information = String(
        'Skylark - Experimental Piksi Networking\n\n'
        "Skylark is Swift Navigation's Internet service for connecting Piksi receivers without the use of a radio. To receive GPS observations from the closest nearby Piksi base station (within 5km), click Connect to Skylark.\n\n"
    )
    start = Button(label='Start', toggle=True, width=32)
    stop = Button(label='Stop', toggle=True, width=32)
    connected_rover = Bool(False)
    connect_rover = Button(label='Connect to Skylark', toggle=True, width=32)
    disconnect_rover = Button(label='Disconnect from Skylark',
                              toggle=True,
                              width=32)
    base_pragma = String()
    rover_pragma = String()
    base_device_uid = String()
    rover_device_uid = String()
    toggle = True
    view = View(
        VGroup(
            spring,
            HGroup(
                VGroup(
                    Item('running',
                         show_label=True,
                         style='readonly',
                         visible_when='running'),
                    Item('msg_enum',
                         label="Messages to broadcast",
                         style='custom',
                         enabled_when='not running'),
                    Item('ip_ad',
                         label='IP Address',
                         enabled_when='not running'),
                    Item('port', label="Port", enabled_when='not running'),
                    HGroup(
                        spring,
                        UItem('start',
                              enabled_when='not running',
                              show_label=False),
                        UItem('stop', enabled_when='running',
                              show_label=False), spring)),
                VGroup(
                    Item('information',
                         label="Notes",
                         height=10,
                         editor=MultilineTextEditor(
                             TextEditor(multi_line=True)),
                         style='readonly',
                         show_label=False,
                         resizable=True,
                         padding=15),
                    spring,
                ),
            ), spring,
            HGroup(
                VGroup(
                    HGroup(
                        spring,
                        UItem('connect_rover',
                              enabled_when='not connected_rover',
                              show_label=False),
                        UItem('disconnect_rover',
                              enabled_when='connected_rover',
                              show_label=False), spring),
                    HGroup(spring, Item('base_pragma', label='Base option '),
                           Item('base_device_uid', label='Base device '),
                           spring),
                    HGroup(spring, Item('rover_pragma', label='Rover option'),
                           Item('rover_device_uid', label='Rover device'),
                           spring),
                ),
                VGroup(
                    Item('http_information',
                         label="Notes",
                         height=10,
                         editor=MultilineTextEditor(
                             TextEditor(multi_line=True)),
                         style='readonly',
                         show_label=False,
                         resizable=True,
                         padding=15),
                    spring,
                ),
            ), spring))

    def __init__(self,
                 link,
                 device_uid=None,
                 base=DEFAULT_BASE,
                 whitelist=None):
        """
    Traits tab with UI for UDP broadcast of SBP.

    Parameters
    ----------
    link : sbp.client.handler.Handler
      Link for SBP transfer to/from Piksi.
    device_uid : str
      Piksi Device UUID (defaults to None)
    base : str
      HTTP endpoint
    whitelist : [int] | None
      Piksi Device UUID (defaults to None)

    """
        self.link = link
        self.http = HTTPDriver(None, base)
        self.net_link = None
        self.fwd = None
        self.func = None
        # Whitelist used for UDP broadcast view
        self.msgs = OBS_MSGS
        # register a callback when the msg_enum trait changes
        self.on_trait_change(self.update_msgs, 'msg_enum')
        # Whitelist used for Skylark broadcasting
        self.whitelist = whitelist
        self.device_uid = None
        self.python_console_cmds = {'update': self}

    def update_msgs(self):
        """Updates the instance variable msgs which store the msgs that we
    will send over UDP.

    """
        if self.msg_enum == 'Observations':
            self.msgs = OBS_MSGS
        elif self.msg_enum == 'All':
            self.msgs = [None]
        else:
            raise NotImplementedError

    def set_route(self, serial_id, channel=CHANNEL_UUID):
        """Sets serial_id hash for HTTP headers.

    Parameters
    ----------
    serial_id : int
      Piksi device ID
    channel : str
      UUID namespace for device UUID

    """
        device_uid = str(get_uuid(channel, serial_id))
        self.device_uid = device_uid
        if self.http:
            self.http.device_uid = device_uid

    def _prompt_networking_error(self, text):
        """Nonblocking prompt for a networking error.

    Parameters
    ----------
    text : str
      Helpful error message for the user

    """
        prompt = CallbackPrompt(title="Networking Error",
                                actions=[close_button])
        prompt.text = text
        prompt.run(block=False)

    def _prompt_setting_error(self, text):
        """Nonblocking prompt for a device setting error.

    Parameters
    ----------
    text : str
      Helpful error message for the user

    """
        prompt = CallbackPrompt(title="Setting Error", actions=[close_button])
        prompt.text = text
        prompt.run(block=False)

    def _retry_read(self):
        """Retry read connections. Intended to be called by
    _connect_rover_fired.

    """
        i = 0
        repeats = 5
        _rover_pragma = self.rover_pragma
        _rover_device_uid = self.rover_device_uid or self.device_uid
        while self.http and not self.http.connect_read(
                device_uid=_rover_device_uid, pragma=_rover_pragma):
            print "Attempting to read observation from Skylark..."
            time.sleep(0.1)
            i += 1
            if i >= repeats:
                msg = (
                    "\nUnable to receive observations from Skylark!\n\n"
                    "Please check that:\n"
                    " - you have a network connection\n"
                    " - your Piksi has a single-point position\n"
                    " - a Skylark-connected Piksi receiver \n   is nearby (within 5km)"
                )
                self._prompt_networking_error(msg)
                self.http.read_close()
                return
        print "Connected as a rover!"
        with Handler(Framer(self.http.read, self.http.write)) as net_link:
            self.net_link = net_link
            self.fwd = Forwarder(net_link, swriter(self.link))
            self.fwd.start()
            while True:
                time.sleep(1)
                if not net_link.is_alive():
                    sys.stderr.write(
                        "Network observation stream disconnected!")
                    break
        # Unless the user has initiated a reconnection, assume here that the rover
        # still wants to be connected, so if we break out of the handler loop,
        # cleanup rover connection and try reconnecting.
        if self.connected_rover:
            sys.stderr.write("Going for a networking reconnection!")
            self._disconnect_rover_fired()
            self._connect_rover_fired()

    def _connect_rover_fired(self):
        """Handle callback for HTTP rover connections.

    """
        if not self.device_uid:
            msg = "\nDevice ID not found!\n\nConnection requires a valid Piksi device ID."
            self._prompt_setting_error(msg)
            return
        if not self.http:
            self._prompt_networking_error("\nNetworking disabled!")
            return
        try:
            _base_pragma = self.base_pragma
            _base_device_uid = self.base_device_uid or self.device_uid
            if not self.http.connect_write(self.link,
                                           self.whitelist,
                                           device_uid=_base_device_uid,
                                           pragma=_base_pragma):
                msg = ("\nUnable to connect to Skylark!\n\n"
                       "Please check that you have a network connection.")
                self._prompt_networking_error(msg)
                self.http.close()
                self.connected_rover = False
                return
            self.connected_rover = True
            print "Connected as a base station!"
            executor = ThreadPoolExecutor(max_workers=2)
            executor.submit(self._retry_read)
        except:
            self.connected_rover = False
            import traceback
            print traceback.format_exc()

    def _disconnect_rover_fired(self):
        """Handle callback for HTTP rover disconnects.

    """
        if not self.device_uid:
            msg = "\nDevice ID not found!\n\nConnection requires a valid Piksi device ID."
            self._prompt_setting_error(msg)
            return
        if not self.http:
            self._prompt_networking_error("\nNetworking disabled!")
            return
        try:
            if self.connected_rover:
                self.http.close()
                self.connected_rover = False
                if self.fwd and self.net_link:
                    self.net_link.stop()
        except:
            self.connected_rover = False
            import traceback
            print traceback.format_exc()

    def _start_fired(self):
        """Handle start udp broadcast button. Registers callbacks on
    self.link for each of the self.msgs If self.msgs is None, it
    registers one generic callback for all messages.

    """
        self.running = True
        try:
            self.func = UdpLogger(self.ip_ad, self.port)
            self.link.add_callback(self.func, self.msgs)
        except:
            import traceback
            print traceback.format_exc()

    def _stop_fired(self):
        """Handle the stop udp broadcast button. It uses the self.funcs and
    self.msgs to remove the callbacks that were registered when the
    start button was pressed.

    """
        try:
            self.link.remove_callback(self.func, self.msgs)
            self.func.__exit__()
            self.func = None
            self.running = False
        except:
            import traceback
            print traceback.format_exc()
Example #17
0
    def connect(self, link, read_config):
        """Retry read connections. Intended to be called when thread started
        Only shared resource here is the self.link
        Parameters
        ----------
        link : SbpHandler
        read_config :  HttpConsoleConnectConfig object

        Returns
        ----------
        ret : int
           0 if exited normally by thread stopping
          -1 if unable to connect as base station
          -2 if unable to connect as rover
          -3 if we lost our network connection (we restart in this case unless stopped)

        """
        assert isinstance(read_config, HttpConsoleConnectConfig)
        self._connect_time = time.time()
        if self.verbose:
            print(
                "HttpWatchdogThread connection attempted at time {0} with parameters {1}".
                format(self.get_connect_time(), read_config))
        i = 0
        repeats = 5
        http = HTTPDriver(
            device_uid=read_config.base_uuid, url=read_config.url)
        if not http.connect_write(
                link, read_config.whitelist, pragma=read_config.base_pragma):
            msg = ("\nUnable to connect!\n\n" +
                   "Please check that you have a network connection.")
            self._prompt_networking_error(msg)
            http.close()
            self.stop()
            return -1  # unable to connect as base
        time.sleep(1)

        # If we get here, we were able to connect as a base
        print("Attempting to read observations ...")
        while (not self.stopped() and http and not http.connect_read(
                device_uid=read_config.rover_uuid,
                pragma=read_config.rover_pragma)):
            time.sleep(0.1)
            i += 1
            if i >= repeats:
                msg = ("\nUnable to receive observations!\n\n"
                       "Please check that:\n"
                       " - you have a network connection\n"
                       " - your Piksi has a single-point position\n"
                       " - your Piksi has sent its settings to the console")
                self._prompt_networking_error(msg)
                http.close()
                self.stop()
                return -2  # Unable to connect as rover

        # If we get here, we were able to connect as rover
        print("Connected as a rover!")
        with Handler(Framer(http.read, http.write)) as net_link:
            fwd = Forwarder(net_link, swriter(link))
            if self.verbose:
                print("Starting forwarder")
            fwd.start()
            # now we sleep until we stop the thread or our http handler dies
            while not self.stopped() and net_link.is_alive():
                time.sleep(0.1)

        # when we leave this loop, we are no longer connected so the fwd should be stopped
        if self.verbose:
            print("Stopping forwarder")
        fwd.stop()
        if self.verbose:
            print("Stopping HTTPDriver")
        http.close()
        # now manage the return code
        if self.stopped():
            return 0  # If we stop from the event, it it intended and we return 0
        else:
            return -3  # Lost connection