aggregate NeedComms {
  arguments {
    DiveInterval = 3 hour
      """
      Elapsed time after most recent surfacing when vehicle will begin to
      ascend to the surface again. The timing is actually based on the
      variable `Universal:time_fix` instead of the variable
      `Universal:platform_communications` because the latter is not toggled
      until the message queue is clear. As a result, there are situations
      where the vehicle might dive for the first half of a yo, then return to
      the surface to continue communications, rendering the communications
      timeout useless. When adjusting this parameter, do not use "set", use
      `assign` in a mission, or set `NeedComms:DiveInterval` from the command
      line.
      """

    WaitForPitchUp = 10 minute
      """
      Extra time to wait for the vehicle to pitch up (avoid truncating a yo).
      """

    SurfacePitch = 20 degree
      """
      Pitch to maintain while ascending
      """

    SurfaceDepthRate = NaN meter_per_second
      """
      Depth rate to maintain while ascending. Set to NaN if using pitch
      """

    SurfaceSpeed = 1 meter_per_second
      """
      Standard speed during surfacing. Don't reduce this too much below 1 m/s
      -- the elevators can stall. (At 0.5 m/s, we have observed evidence of
      stall in the past.)
      """

    GPSTimeout = 7 minute
      """
      Maximum amount of time to spend trying to get each GPS fix.
      """

    CommsTimeout = 30 minute
      """
      Maximum amount of time to spend on the surface trying to communicate
      before giving up, getting another GPS fix, and diving again.
      """
  }

  run when (
    called
    or elapsed Universal:time_fix > DiveInterval + WaitForPitchUp
    or elapsed Universal:time_fix > DiveInterval
    and Universal:platform_pitch_angle > 0 degree
  )

  syslog info "last time_fix was: " + Universal:time_fix~epoch_second

  behavior Guidance:GoToSurface {
    run in progression

    set pitch = SurfacePitch
    set depthRate = SurfaceDepthRate
    set speed = SurfaceSpeed
  }

  readDatum {
    timeout duration=GPSTimeout {
      syslog important "first GPS update timeout"
    }

    Universal:time_fix
  }

  readDatum {
    timeout duration=CommsTimeout

    Universal:platform_communications
  }

  readDatum {
    timeout duration=GPSTimeout {
      syslog important "second GPS update timeout"
    }

    Universal:time_fix
  }
}
