Exemple #1
0
def thermald_thread():
  health_timeout = int(1000 * 2.5 * DT_TRML)  # 2.5x the expected health frequency

  # now loop
  thermal_sock = messaging.pub_sock('thermal')
  health_sock = messaging.sub_sock('health', timeout=health_timeout)
  location_sock = messaging.sub_sock('gpsLocation')

  fan_speed = 0
  count = 0

  startup_conditions = {
    "ignition": False,
  }
  startup_conditions_prev = startup_conditions.copy()

  off_ts = None
  started_ts = None
  started_seen = False
  thermal_status = ThermalStatus.green
  usb_power = True
  current_branch = get_git_branch()

  network_type = NetworkType.none
  network_strength = NetworkStrength.unknown

  current_filter = FirstOrderFilter(0., CURRENT_TAU, DT_TRML)
  cpu_temp_filter = FirstOrderFilter(0., CPU_TEMP_TAU, DT_TRML)
  health_prev = None
  charging_disabled = False
  should_start_prev = False
  handle_fan = None
  is_uno = False

  params = Params()
  pm = PowerMonitoring()
  no_panda_cnt = 0

  thermal_config = get_thermal_config()

  ts_last_ip = 0
  ip_addr = '255.255.255.255'

  # sound trigger
  sound_trigger = 1
  opkrAutoShutdown = 0

  shutdown_trigger = 1
  is_openpilot_view_enabled = 0

  env = dict(os.environ)
  env['LD_LIBRARY_PATH'] = mediaplayer

  getoff_alert = Params().get('OpkrEnableGetoffAlert') == b'1'

  if int(params.get('OpkrAutoShutdown')) == 0:
    opkrAutoShutdown = 0
  elif int(params.get('OpkrAutoShutdown')) == 1:
    opkrAutoShutdown = 5
  elif int(params.get('OpkrAutoShutdown')) == 2:
    opkrAutoShutdown = 30
  elif int(params.get('OpkrAutoShutdown')) == 3:
    opkrAutoShutdown = 60
  elif int(params.get('OpkrAutoShutdown')) == 4:
    opkrAutoShutdown = 180
  elif int(params.get('OpkrAutoShutdown')) == 5:
    opkrAutoShutdown = 300
  elif int(params.get('OpkrAutoShutdown')) == 6:
    opkrAutoShutdown = 600
  elif int(params.get('OpkrAutoShutdown')) == 7:
    opkrAutoShutdown = 1800
  elif int(params.get('OpkrAutoShutdown')) == 8:
    opkrAutoShutdown = 3600
  elif int(params.get('OpkrAutoShutdown')) == 9:
    opkrAutoShutdown = 10800
  else:
    opkrAutoShutdown = 18000
  
  lateral_control_method = int(params.get("LateralControlMethod"))
  lateral_control_method_prev = int(params.get("LateralControlMethod"))
  lateral_control_method_cnt = 0
  lateral_control_method_trigger = 0
  while 1:
    ts = sec_since_boot()
    health = messaging.recv_sock(health_sock, wait=True)
    location = messaging.recv_sock(location_sock)
    location = location.gpsLocation if location else None
    msg = read_thermal(thermal_config)

    if health is not None:
      usb_power = health.health.usbPowerMode != log.HealthData.UsbPowerMode.client

      # If we lose connection to the panda, wait 5 seconds before going offroad
      lateral_control_method = int(params.get("LateralControlMethod"))
      if lateral_control_method != lateral_control_method_prev and lateral_control_method_trigger == 0:
        startup_conditions["ignition"] = False
        lateral_control_method_trigger = 1
      elif lateral_control_method != lateral_control_method_prev:
        lateral_control_method_cnt += 1
        if lateral_control_method_cnt > 1 / DT_TRML:
          lateral_control_method_prev = lateral_control_method
      elif health.health.hwType == log.HealthData.HwType.unknown:
        no_panda_cnt += 1
        if no_panda_cnt > DISCONNECT_TIMEOUT / DT_TRML:
          if startup_conditions["ignition"]:
            cloudlog.error("Lost panda connection while onroad")
          startup_conditions["ignition"] = False
          shutdown_trigger = 1
      else:
        no_panda_cnt = 0
        startup_conditions["ignition"] = health.health.ignitionLine or health.health.ignitionCan
        sound_trigger == 1
        lateral_control_method_cnt = 0
        lateral_control_method_trigger = 0

      # Setup fan handler on first connect to panda
      if handle_fan is None and health.health.hwType != log.HealthData.HwType.unknown:
        is_uno = health.health.hwType == log.HealthData.HwType.uno

        if (not EON) or is_uno:
          cloudlog.info("Setting up UNO fan handler")
          handle_fan = handle_fan_uno
        else:
          cloudlog.info("Setting up EON fan handler")
          setup_eon_fan()
          handle_fan = handle_fan_eon

      # Handle disconnect
      if health_prev is not None:
        if health.health.hwType == log.HealthData.HwType.unknown and \
          health_prev.health.hwType != log.HealthData.HwType.unknown:
          params.panda_disconnect()
      health_prev = health
    elif int(params.get("IsOpenpilotViewEnabled")) == 1 and int(params.get("IsDriverViewEnabled")) == 0 and is_openpilot_view_enabled == 0:
      is_openpilot_view_enabled = 1
      startup_conditions["ignition"] = True
    elif int(params.get("IsOpenpilotViewEnabled")) == 0 and int(params.get("IsDriverViewEnabled")) == 0 and is_openpilot_view_enabled == 1:
      shutdown_trigger = 0
      sound_trigger == 0
      is_openpilot_view_enabled = 0
      startup_conditions["ignition"] = False

    # get_network_type is an expensive call. update every 10s
    if (count % int(10. / DT_TRML)) == 0:
      try:
        network_type = HARDWARE.get_network_type()
        network_strength = HARDWARE.get_network_strength(network_type)
      except Exception:
        cloudlog.exception("Error getting network status")

    msg.thermal.freeSpace = get_available_percent(default=100.0) / 100.0
    msg.thermal.memUsedPercent = int(round(psutil.virtual_memory().percent))
    msg.thermal.cpuPerc = int(round(psutil.cpu_percent()))
    msg.thermal.networkType = network_type
    msg.thermal.networkStrength = network_strength
    msg.thermal.batteryPercent = get_battery_capacity()
    msg.thermal.batteryStatus = get_battery_status()
    msg.thermal.batteryCurrent = get_battery_current()
    msg.thermal.batteryVoltage = get_battery_voltage()
    msg.thermal.usbOnline = get_usb_present()

    # Fake battery levels on uno for frame
    if (not EON) or is_uno:
      msg.thermal.batteryPercent = 100
      msg.thermal.batteryStatus = "Charging"
      msg.thermal.bat = 0

    # update ip every 10 seconds
    ts = sec_since_boot()
    if ts - ts_last_ip >= 10.:
      try:
        result = subprocess.check_output(["ifconfig", "wlan0"], encoding='utf8')  # pylint: disable=unexpected-keyword-arg
        ip_addr = re.findall(r"inet addr:((\d+\.){3}\d+)", result)[0][0]
      except:
        ip_addr = 'N/A'
      ts_last_ip = ts
    msg.thermal.ipAddr = ip_addr

    current_filter.update(msg.thermal.batteryCurrent / 1e6)

    # TODO: add car battery voltage check
    max_cpu_temp = cpu_temp_filter.update(max(msg.thermal.cpu))
    max_comp_temp = max(max_cpu_temp, msg.thermal.mem, max(msg.thermal.gpu))
    bat_temp = msg.thermal.bat

    if handle_fan is not None:
      fan_speed = handle_fan(max_cpu_temp, bat_temp, fan_speed, startup_conditions["ignition"])
      msg.thermal.fanSpeed = fan_speed

    # If device is offroad we want to cool down before going onroad
    # since going onroad increases load and can make temps go over 107
    # We only do this if there is a relay that prevents the car from faulting
    is_offroad_for_5_min = (started_ts is None) and ((not started_seen) or (off_ts is None) or (sec_since_boot() - off_ts > 60 * 5))
    if max_cpu_temp > 107. or bat_temp >= 63. or (is_offroad_for_5_min and max_cpu_temp > 70.0):
      # onroad not allowed
      thermal_status = ThermalStatus.danger
    elif max_comp_temp > 96.0 or bat_temp > 60.:
      # hysteresis between onroad not allowed and engage not allowed
      thermal_status = clip(thermal_status, ThermalStatus.red, ThermalStatus.danger)
    elif max_cpu_temp > 94.0:
      # hysteresis between engage not allowed and uploader not allowed
      thermal_status = clip(thermal_status, ThermalStatus.yellow, ThermalStatus.red)
    elif max_cpu_temp > 80.0:
      # uploader not allowed
      thermal_status = ThermalStatus.yellow
    elif max_cpu_temp > 75.0:
      # hysteresis between uploader not allowed and all good
      thermal_status = clip(thermal_status, ThermalStatus.green, ThermalStatus.yellow)
    else:
      # all good
      thermal_status = ThermalStatus.green

    # **** starting logic ****

    # Check for last update time and display alerts if needed
    now = datetime.datetime.utcnow()

    # show invalid date/time alert
    startup_conditions["time_valid"] = now.year >= True
    set_offroad_alert_if_changed("Offroad_InvalidTime", (not startup_conditions["time_valid"]))

    # Show update prompt
#    try:
#      last_update = datetime.datetime.fromisoformat(params.get("LastUpdateTime", encoding='utf8'))
#    except (TypeError, ValueError):
#      last_update = now
#    dt = now - last_update
#
#    update_failed_count = params.get("UpdateFailedCount")
#    update_failed_count = 0 if update_failed_count is None else int(update_failed_count)
#    last_update_exception = params.get("LastUpdateException", encoding='utf8')
#
#    if update_failed_count > 15 and last_update_exception is not None:
#      if current_branch in ["release2", "dashcam"]:
#        extra_text = "Ensure the software is correctly installed"
#      else:
#        extra_text = last_update_exception
#
#      set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
#      set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False)
#      set_offroad_alert_if_changed("Offroad_UpdateFailed", True, extra_text=extra_text)
#    elif dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
#      set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
#      set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False)
#      set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", True)
#    elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
#      remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
#      set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
#      set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
#      set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", True, extra_text=f"{remaining_time} days.")
#    else:
#      set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
#      set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
#      set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False)

    startup_conditions["not_uninstalling"] = not params.get("DoUninstall") == b"1"
    startup_conditions["accepted_terms"] = params.get("HasAcceptedTerms") == terms_version

    panda_signature = params.get("PandaFirmware")
    startup_conditions["fw_version_match"] = (panda_signature is None) or (panda_signature == FW_SIGNATURE)   # don't show alert is no panda is connected (None)
    set_offroad_alert_if_changed("Offroad_PandaFirmwareMismatch", (not startup_conditions["fw_version_match"]))

    # with 2% left, we killall, otherwise the phone will take a long time to boot
    startup_conditions["free_space"] = msg.thermal.freeSpace > 0.02
    startup_conditions["completed_training"] = params.get("CompletedTrainingVersion") == training_version or \
                                               (current_branch in ['dashcam', 'dashcam-staging'])
    startup_conditions["not_driver_view"] = not params.get("IsDriverViewEnabled") == b"1"
    startup_conditions["not_taking_snapshot"] = not params.get("IsTakingSnapshot") == b"1"
    # if any CPU gets above 107 or the battery gets above 63, kill all processes
    # controls will warn with CPU above 95 or battery above 60
    startup_conditions["device_temp_good"] = thermal_status < ThermalStatus.danger
    set_offroad_alert_if_changed("Offroad_TemperatureTooHigh", (not startup_conditions["device_temp_good"]))
    should_start = all(startup_conditions.values())

    if should_start:
      if not should_start_prev:
        params.delete("IsOffroad")

      off_ts = None
      if started_ts is None:
        started_ts = sec_since_boot()
        started_seen = True
        os.system('echo performance > /sys/class/devfreq/soc:qcom,cpubw/governor')
    else:
      if startup_conditions["ignition"] and (startup_conditions != startup_conditions_prev):
        cloudlog.event("Startup blocked", startup_conditions=startup_conditions)
      if should_start_prev or (count == 0):
        params.put("IsOffroad", "1")

      started_ts = None
      if off_ts is None:
        off_ts = sec_since_boot()
        os.system('echo powersave > /sys/class/devfreq/soc:qcom,cpubw/governor')

      if shutdown_trigger == 1 and sound_trigger == 1 and msg.thermal.batteryStatus == "Discharging" and started_seen and (sec_since_boot() - off_ts) > 1 and getoff_alert:
        subprocess.Popen([mediaplayer + 'mediaplayer', '/data/openpilot/selfdrive/assets/sounds/eondetach.wav'], shell = False, stdin=None, stdout=None, stderr=None, env = env, close_fds=True)
        sound_trigger = 0
      # shutdown if the battery gets lower than 3%, it's discharging, we aren't running for
      # more than a minute but we were running
      if shutdown_trigger == 1 and msg.thermal.batteryStatus == "Discharging" and \
         started_seen and opkrAutoShutdown and (sec_since_boot() - off_ts) > opkrAutoShutdown and not os.path.isfile(pandaflash_ongoing):
        os.system('LD_LIBRARY_PATH="" svc power shutdown')

    charging_disabled = check_car_battery_voltage(should_start, health, charging_disabled, msg)

    if msg.thermal.batteryCurrent > 0:
      msg.thermal.batteryStatus = "Discharging"
    else:
      msg.thermal.batteryStatus = "Charging"

    
    msg.thermal.chargingDisabled = charging_disabled

    prebuiltlet = Params().get('PutPrebuiltOn') == b'1'
    if not os.path.isfile(prebuiltfile) and prebuiltlet:
      os.system("cd /data/openpilot; touch prebuilt")
    elif os.path.isfile(prebuiltfile) and not prebuiltlet:
      os.system("cd /data/openpilot; rm -f prebuilt")

    # Offroad power monitoring
    pm.calculate(health)
    msg.thermal.offroadPowerUsage = pm.get_power_used()
    msg.thermal.carBatteryCapacity = max(0, pm.get_car_battery_capacity())

#    # Check if we need to disable charging (handled by boardd)
#    msg.thermal.chargingDisabled = pm.should_disable_charging(health, off_ts)
#
#    # Check if we need to shut down
#    if pm.should_shutdown(health, off_ts, started_seen, LEON):
#      cloudlog.info(f"shutting device down, offroad since {off_ts}")
#      # TODO: add function for blocking cloudlog instead of sleep
#      time.sleep(10)
#      os.system('LD_LIBRARY_PATH="" svc power shutdown')

    msg.thermal.chargingError = current_filter.x > 0. and msg.thermal.batteryPercent < 90  # if current is positive, then battery is being discharged
    msg.thermal.started = started_ts is not None
    msg.thermal.startedTs = int(1e9*(started_ts or 0))

    msg.thermal.thermalStatus = thermal_status
    thermal_sock.send(msg.to_bytes())

    set_offroad_alert_if_changed("Offroad_ChargeDisabled", (not usb_power))

    should_start_prev = should_start
    startup_conditions_prev = startup_conditions.copy()

    # report to server once per minute
    if (count % int(60. / DT_TRML)) == 0:
      cloudlog.event("STATUS_PACKET",
                     count=count,
                     health=(health.to_dict() if health else None),
                     location=(location.to_dict() if location else None),
                     thermal=msg.to_dict())

    count += 1
Exemple #2
0
def thermald_thread():

    pm = messaging.PubMaster(['deviceState'])

    pandaState_timeout = int(1000 * 2.5 *
                             DT_TRML)  # 2.5x the expected pandaState frequency
    pandaState_sock = messaging.sub_sock('pandaState',
                                         timeout=pandaState_timeout)
    location_sock = messaging.sub_sock('gpsLocationExternal')
    managerState_sock = messaging.sub_sock('managerState', conflate=True)

    fan_speed = 0
    count = 0

    startup_conditions = {
        "ignition": False,
    }
    startup_conditions_prev = startup_conditions.copy()

    off_ts = None
    started_ts = None
    started_seen = False
    thermal_status = ThermalStatus.green
    usb_power = True
    current_branch = get_git_branch()

    network_type = NetworkType.none
    network_strength = NetworkStrength.unknown

    current_filter = FirstOrderFilter(0., CURRENT_TAU, DT_TRML)
    cpu_temp_filter = FirstOrderFilter(0., CPU_TEMP_TAU, DT_TRML)
    charging_disabled = False  #CHO: Add battery management
    pandaState_prev = None
    should_start_prev = False
    handle_fan = None
    is_uno = False
    #ui_running_prev = False
    ui_running_prev = True  #CHO: Add battery management

    params = Params()
    power_monitor = PowerMonitoring()
    no_panda_cnt = 0

    thermal_config = HARDWARE.get_thermal_config()

    # CPR3 logging
    if EON:
        base_path = "/sys/kernel/debug/cpr3-regulator/"
        cpr_files = [p for p in Path(base_path).glob("**/*") if p.is_file()]
        cpr_data = {}
        for cf in cpr_files:
            with open(cf, "r") as f:
                try:
                    cpr_data[str(cf)] = f.read().strip()
                except Exception:
                    pass
        cloudlog.event("CPR", data=cpr_data)

    while 1:
        pandaState = messaging.recv_sock(pandaState_sock, wait=True)
        msg = read_thermal(thermal_config)

        if pandaState is not None:
            usb_power = pandaState.pandaState.usbPowerMode != log.PandaState.UsbPowerMode.client

            # If we lose connection to the panda, wait 5 seconds before going offroad
            if pandaState.pandaState.pandaType == log.PandaState.PandaType.unknown:
                no_panda_cnt += 1
                if no_panda_cnt > DISCONNECT_TIMEOUT / DT_TRML:
                    if startup_conditions["ignition"]:
                        cloudlog.error("Lost panda connection while onroad")
                    startup_conditions["ignition"] = False
            else:
                no_panda_cnt = 0
                startup_conditions[
                    "ignition"] = pandaState.pandaState.ignitionLine or pandaState.pandaState.ignitionCan

            startup_conditions["hardware_supported"] = True
            set_offroad_alert_if_changed(
                "Offroad_HardwareUnsupported",
                not startup_conditions["hardware_supported"])

            # Setup fan handler on first connect to panda
            if handle_fan is None and pandaState.pandaState.pandaType != log.PandaState.PandaType.unknown:
                is_uno = pandaState.pandaState.pandaType == log.PandaState.PandaType.uno

                if (not EON) or is_uno:
                    cloudlog.info("Setting up UNO fan handler")
                    handle_fan = handle_fan_uno
                else:
                    cloudlog.info("Setting up EON fan handler")
                    setup_eon_fan()
                    handle_fan = handle_fan_eon

            # Handle disconnect
            if pandaState_prev is not None:
                if pandaState.pandaState.pandaType == log.PandaState.PandaType.unknown and \
                  pandaState_prev.pandaState.pandaType != log.PandaState.PandaType.unknown:
                    params.panda_disconnect()
            pandaState_prev = pandaState

        # get_network_type is an expensive call. update every 10s
        if (count % int(10. / DT_TRML)) == 0:
            try:
                network_type = HARDWARE.get_network_type()
                network_strength = HARDWARE.get_network_strength(network_type)
            except Exception:
                cloudlog.exception("Error getting network status")

        msg.deviceState.freeSpacePercent = get_available_percent(default=100.0)
        msg.deviceState.memoryUsagePercent = int(
            round(psutil.virtual_memory().percent))
        msg.deviceState.cpuUsagePercent = int(round(psutil.cpu_percent()))
        msg.deviceState.networkType = network_type
        msg.deviceState.networkStrength = network_strength
        msg.deviceState.batteryPercent = HARDWARE.get_battery_capacity()
        msg.deviceState.batteryStatus = HARDWARE.get_battery_status()
        msg.deviceState.batteryCurrent = HARDWARE.get_battery_current()
        msg.deviceState.batteryVoltage = HARDWARE.get_battery_voltage()
        msg.deviceState.usbOnline = HARDWARE.get_usb_present()

        # Fake battery levels on uno for frame
        if (not EON) or is_uno:
            msg.deviceState.batteryPercent = 100
            msg.deviceState.batteryStatus = "Charging"
            msg.deviceState.batteryTempC = 0

        current_filter.update(msg.deviceState.batteryCurrent / 1e6)

        # TODO: add car battery voltage check
        max_cpu_temp = cpu_temp_filter.update(max(msg.deviceState.cpuTempC))
        max_comp_temp = max(max_cpu_temp, msg.deviceState.memoryTempC,
                            max(msg.deviceState.gpuTempC))
        bat_temp = msg.deviceState.batteryTempC

        if handle_fan is not None:
            fan_speed = handle_fan(max_cpu_temp, bat_temp, fan_speed,
                                   startup_conditions["ignition"])
            msg.deviceState.fanSpeedPercentDesired = fan_speed

        # If device is offroad we want to cool down before going onroad
        # since going onroad increases load and can make temps go over 107
        # We only do this if there is a relay that prevents the car from faulting
        is_offroad_for_5_min = (started_ts is None) and (
            (not started_seen) or (off_ts is None) or
            (sec_since_boot() - off_ts > 60 * 5))
        if max_cpu_temp > 107. or bat_temp >= 63. or (is_offroad_for_5_min
                                                      and max_cpu_temp > 70.0):
            # onroad not allowed
            thermal_status = ThermalStatus.danger
        elif max_comp_temp > 96.0 or bat_temp > 60.:
            # hysteresis between onroad not allowed and engage not allowed
            thermal_status = clip(thermal_status, ThermalStatus.red,
                                  ThermalStatus.danger)
        elif max_cpu_temp > 94.0:
            # hysteresis between engage not allowed and uploader not allowed
            thermal_status = clip(thermal_status, ThermalStatus.yellow,
                                  ThermalStatus.red)
        elif max_cpu_temp > 80.0:
            # uploader not allowed
            thermal_status = ThermalStatus.yellow
        elif max_cpu_temp > 75.0:
            # hysteresis between uploader not allowed and all good
            thermal_status = clip(thermal_status, ThermalStatus.green,
                                  ThermalStatus.yellow)
        else:
            thermal_status = ThermalStatus.green  # default to good condition

        # **** starting logic ****

        # Check for last update time and display alerts if needed
        now = datetime.datetime.utcnow()

        # show invalid date/time alert
        startup_conditions["time_valid"] = (now.year > 2020) or (
            now.year == 2020 and now.month >= 10)
        set_offroad_alert_if_changed("Offroad_InvalidTime",
                                     (not startup_conditions["time_valid"]))

        # Show update prompt
        try:
            last_update = datetime.datetime.fromisoformat(
                params.get("LastUpdateTime", encoding='utf8'))
        except (TypeError, ValueError):
            last_update = now
        dt = now - last_update

        update_failed_count = params.get("UpdateFailedCount")
        update_failed_count = 0 if update_failed_count is None else int(
            update_failed_count)
        last_update_exception = params.get("LastUpdateException",
                                           encoding='utf8')

        if update_failed_count > 15 and last_update_exception is not None:
            if current_branch in ["release2", "dashcam"]:
                extra_text = "Ensure the software is correctly installed"
            else:
                extra_text = last_update_exception

            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)
            set_offroad_alert_if_changed("Offroad_UpdateFailed",
                                         True,
                                         extra_text=extra_text)
        elif dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", True)
        elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
            remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         True,
                                         extra_text=f"{remaining_time} days.")
        else:
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)

        startup_conditions["up_to_date"] = params.get(
            "Offroad_ConnectivityNeeded") is None or params.get(
                "DisableUpdates") == b"1"
        startup_conditions["not_uninstalling"] = not params.get(
            "DoUninstall") == b"1"
        startup_conditions["accepted_terms"] = params.get(
            "HasAcceptedTerms") == terms_version

        panda_signature = params.get("PandaFirmware")
        startup_conditions["fw_version_match"] = (panda_signature is None) or (
            panda_signature == FW_SIGNATURE
        )  # don't show alert is no panda is connected (None)
        set_offroad_alert_if_changed(
            "Offroad_PandaFirmwareMismatch",
            (not startup_conditions["fw_version_match"]))

        # with 2% left, we killall, otherwise the phone will take a long time to boot
        startup_conditions["free_space"] = msg.deviceState.freeSpacePercent > 2
        startup_conditions["completed_training"] = params.get("CompletedTrainingVersion") == training_version or \
                                                   (current_branch in ['dashcam', 'dashcam-staging'])
        startup_conditions["not_driver_view"] = not params.get(
            "IsDriverViewEnabled") == b"1"
        startup_conditions["not_taking_snapshot"] = not params.get(
            "IsTakingSnapshot") == b"1"
        # if any CPU gets above 107 or the battery gets above 63, kill all processes
        # controls will warn with CPU above 95 or battery above 60
        startup_conditions[
            "device_temp_good"] = thermal_status < ThermalStatus.danger
        set_offroad_alert_if_changed(
            "Offroad_TemperatureTooHigh",
            (not startup_conditions["device_temp_good"]))

        # Handle offroad/onroad transition
        should_start = all(startup_conditions.values())
        if should_start:
            if not should_start_prev:
                params.delete("IsOffroad")
                if TICI and DISABLE_LTE_ONROAD:
                    os.system("sudo systemctl stop --no-block lte")

            off_ts = None
            if started_ts is None:
                started_ts = sec_since_boot()
                started_seen = True
        else:
            if startup_conditions["ignition"] and (startup_conditions !=
                                                   startup_conditions_prev):
                cloudlog.event("Startup blocked",
                               startup_conditions=startup_conditions)

            if should_start_prev or (count == 0):
                params.put("IsOffroad", "1")
                if TICI and DISABLE_LTE_ONROAD:
                    os.system("sudo systemctl start --no-block lte")

            started_ts = None
            if off_ts is None:
                off_ts = sec_since_boot()
        #CHO: Added battery management
        charging_disabled = check_car_battery_voltage(should_start, pandaState,
                                                      charging_disabled, msg)

        if msg.deviceState.batteryCurrent > 0:
            msg.deviceState.batteryStatus = "Discharging"
        else:
            msg.deviceState.batteryStatus = "Charging"

        msg.deviceState.chargingDisabled = charging_disabled
        #CHO: END

        # Offroad power monitoring
        power_monitor.calculate(pandaState)
        msg.deviceState.offroadPowerUsageUwh = power_monitor.get_power_used()
        msg.deviceState.carBatteryCapacityUwh = max(
            0, power_monitor.get_car_battery_capacity())

        # Check if we need to disable charging (handled by boardd)
        msg.deviceState.chargingDisabled = power_monitor.should_disable_charging(
            pandaState, off_ts)

        # Check if we need to shut down
        if power_monitor.should_shutdown(pandaState, off_ts, started_seen):
            cloudlog.info(f"shutting device down, offroad since {off_ts}")
            # TODO: add function for blocking cloudlog instead of sleep
            time.sleep(10)
            HARDWARE.shutdown()

        # If UI has crashed, set the brightness to reasonable non-zero value
        manager_state = messaging.recv_one_or_none(managerState_sock)
        if manager_state is not None:
            ui_running = "ui" in (p.name
                                  for p in manager_state.managerState.processes
                                  if p.running)
            if ui_running_prev and not ui_running:
                HARDWARE.set_screen_brightness(20)
            ui_running_prev = ui_running

        msg.deviceState.chargingError = current_filter.x > 0. and msg.deviceState.batteryPercent < 90  # if current is positive, then battery is being discharged
        msg.deviceState.started = started_ts is not None
        msg.deviceState.startedMonoTime = int(1e9 * (started_ts or 0))

        msg.deviceState.thermalStatus = thermal_status
        pm.send("deviceState", msg)

        if EON and not is_uno:
            set_offroad_alert_if_changed("Offroad_ChargeDisabled",
                                         (not usb_power))

        should_start_prev = should_start
        startup_conditions_prev = startup_conditions.copy()

        # report to server once per minute
        if (count % int(60. / DT_TRML)) == 0:
            location = messaging.recv_sock(location_sock)
            cloudlog.event("STATUS_PACKET",
                           count=count,
                           pandaState=(strip_deprecated_keys(
                               pandaState.to_dict()) if pandaState else None),
                           location=(strip_deprecated_keys(
                               location.gpsLocationExternal.to_dict())
                                     if location else None),
                           deviceState=strip_deprecated_keys(msg.to_dict()))

        count += 1
Exemple #3
0
def ui_thread(addr, frame_address):
  # TODO: Detect car from replay and use that to select carparams
  CP = ToyotaInterface.get_params("TOYOTA PRIUS 2017")
  VM = VehicleModel(CP)

  CalP = np.asarray([[0, 0], [MODEL_INPUT_SIZE[0], 0], [MODEL_INPUT_SIZE[0], MODEL_INPUT_SIZE[1]], [0, MODEL_INPUT_SIZE[1]]])
  vanishing_point = np.asarray([[MODEL_CX, MODEL_CY]])

  pygame.init()
  pygame.font.init()
  assert pygame_modules_have_loaded()

  if HOR:
    size = (640+384+640, 960)
    write_x = 5
    write_y = 680
  else:
    size = (640+384, 960+300)
    write_x = 645
    write_y = 970

  pygame.display.set_caption("openpilot debug UI")
  screen = pygame.display.set_mode(size, pygame.DOUBLEBUF)

  alert1_font = pygame.font.SysFont("arial", 30)
  alert2_font = pygame.font.SysFont("arial", 20)
  info_font = pygame.font.SysFont("arial", 15)

  camera_surface = pygame.surface.Surface((640, 480), 0, 24).convert()
  cameraw_surface = pygame.surface.Surface(MODEL_INPUT_SIZE, 0, 24).convert()
  cameraw_test_surface = pygame.surface.Surface(MODEL_INPUT_SIZE, 0, 24)
  top_down_surface = pygame.surface.Surface((UP.lidar_x, UP.lidar_y),0,8)

  frame = messaging.sub_sock('frame', addr=addr, conflate=True)
  sm = messaging.SubMaster(['carState', 'plan', 'carControl', 'radarState', 'liveCalibration', 'controlsState', 'liveTracks', 'model', 'liveMpc', 'liveParameters', 'pathPlan'], addr=addr)

  calibration = None
  img = np.zeros((480, 640, 3), dtype='uint8')
  imgff = np.zeros((FULL_FRAME_SIZE[1], FULL_FRAME_SIZE[0], 3), dtype=np.uint8)
  imgw = np.zeros((160, 320, 3), dtype=np.uint8)  # warped image
  lid_overlay_blank = get_blank_lid_overlay(UP)

  # plots
  name_to_arr_idx = { "gas": 0,
                      "computer_gas": 1,
                      "user_brake": 2,
                      "computer_brake": 3,
                      "v_ego": 4,
                      "v_pid": 5,
                      "angle_steers_des": 6,
                      "angle_steers": 7,
                      "angle_steers_k": 8,
                      "steer_torque": 9,
                      "v_override": 10,
                      "v_cruise": 11,
                      "a_ego": 12,
                      "a_target": 13,
                      "accel_override": 14}

  plot_arr = np.zeros((100, len(name_to_arr_idx.values())))

  plot_xlims = [(0, plot_arr.shape[0]), (0, plot_arr.shape[0]), (0, plot_arr.shape[0]), (0, plot_arr.shape[0])]
  plot_ylims = [(-0.1, 1.1), (-ANGLE_SCALE, ANGLE_SCALE), (0., 75.), (-3.0, 2.0)]
  plot_names = [["gas", "computer_gas", "user_brake", "computer_brake", "accel_override"],
                ["angle_steers", "angle_steers_des", "angle_steers_k", "steer_torque"],
                ["v_ego", "v_override", "v_pid", "v_cruise"],
                ["a_ego", "a_target"]]
  plot_colors = [["b", "b", "g", "r", "y"],
                 ["b", "g", "y", "r"],
                 ["b", "g", "r", "y"],
                 ["b", "r"]]
  plot_styles = [["-", "-", "-", "-", "-"],
                 ["-", "-", "-", "-"],
                 ["-", "-", "-", "-"],
                 ["-", "-"]]

  draw_plots = init_plots(plot_arr, name_to_arr_idx, plot_xlims, plot_ylims, plot_names, plot_colors, plot_styles, bigplots=True)

  counter = 0
  while 1:
    list(pygame.event.get())

    screen.fill((64,64,64))
    lid_overlay = lid_overlay_blank.copy()
    top_down = top_down_surface, lid_overlay

    # ***** frame *****
    fpkt = messaging.recv_one(frame)
    rgb_img_raw = fpkt.frame.image

    if fpkt.frame.transform:
      img_transform = np.array(fpkt.frame.transform).reshape(3,3)
    else:
      # assume frame is flipped
      img_transform = np.array([
        [-1.0,  0.0, FULL_FRAME_SIZE[0]-1],
        [ 0.0, -1.0, FULL_FRAME_SIZE[1]-1],
        [ 0.0,  0.0, 1.0]
      ])


    if rgb_img_raw and len(rgb_img_raw) == FULL_FRAME_SIZE[0] * FULL_FRAME_SIZE[1] * 3:
      imgff = np.frombuffer(rgb_img_raw, dtype=np.uint8).reshape((FULL_FRAME_SIZE[1], FULL_FRAME_SIZE[0], 3))
      imgff = imgff[:, :, ::-1] # Convert BGR to RGB
      cv2.warpAffine(imgff, np.dot(img_transform, _BB_TO_FULL_FRAME)[:2],
        (img.shape[1], img.shape[0]), dst=img, flags=cv2.WARP_INVERSE_MAP)

      intrinsic_matrix = eon_intrinsics
    else:
      img.fill(0)
      intrinsic_matrix = np.eye(3)

    if calibration is not None:
      transform = np.dot(img_transform, calibration.model_to_full_frame)
      imgw = cv2.warpAffine(imgff, transform[:2], (MODEL_INPUT_SIZE[0], MODEL_INPUT_SIZE[1]), flags=cv2.WARP_INVERSE_MAP)
    else:
      imgw.fill(0)

    sm.update()

    w = sm['controlsState'].lateralControlState.which()
    if w == 'lqrState':
      angle_steers_k = sm['controlsState'].lateralControlState.lqrState.steerAngle
    elif w == 'indiState':
      angle_steers_k = sm['controlsState'].lateralControlState.indiState.steerAngle
    else:
      angle_steers_k = np.inf

    plot_arr[:-1] = plot_arr[1:]
    plot_arr[-1, name_to_arr_idx['angle_steers']] = sm['controlsState'].angleSteers
    plot_arr[-1, name_to_arr_idx['angle_steers_des']] = sm['carControl'].actuators.steerAngle
    plot_arr[-1, name_to_arr_idx['angle_steers_k']] = angle_steers_k
    plot_arr[-1, name_to_arr_idx['gas']] = sm['carState'].gas
    plot_arr[-1, name_to_arr_idx['computer_gas']] = sm['carControl'].actuators.gas
    plot_arr[-1, name_to_arr_idx['user_brake']] = sm['carState'].brake
    plot_arr[-1, name_to_arr_idx['steer_torque']] = sm['carControl'].actuators.steer * ANGLE_SCALE
    plot_arr[-1, name_to_arr_idx['computer_brake']] = sm['carControl'].actuators.brake
    plot_arr[-1, name_to_arr_idx['v_ego']] = sm['controlsState'].vEgo
    plot_arr[-1, name_to_arr_idx['v_pid']] = sm['controlsState'].vPid
    plot_arr[-1, name_to_arr_idx['v_override']] = sm['carControl'].cruiseControl.speedOverride
    plot_arr[-1, name_to_arr_idx['v_cruise']] = sm['carState'].cruiseState.speed
    plot_arr[-1, name_to_arr_idx['a_ego']] = sm['carState'].aEgo
    plot_arr[-1, name_to_arr_idx['a_target']] = sm['plan'].aTarget
    plot_arr[-1, name_to_arr_idx['accel_override']] = sm['carControl'].cruiseControl.accelOverride

    # ***** model ****
    # if len(sm['model'].path.poly) > 0:
    model_data = extract_model_data(sm['model'])

    imgw_copy = copy.deepcopy(imgw)

    paths = plot_model(model_data, VM, sm['controlsState'].vEgo, sm['controlsState'].curvature, imgw, calibration,
                top_down, np.array(sm['pathPlan'].dPoly))
    
    # interlock code HERE
    if calibration:
      left_fit = np.polyfit(_PATH_XD, model_data.lpath.y,2)
      right_fit = np.polyfit(_PATH_XD, model_data.rpath.y,2)
      imgw_copy = cv2.resize(imgw_copy, (int(imgw_copy.shape[1] * SCALE), int(imgw_copy.shape[0] * SCALE)))
      interlock(imgw_copy, left_fit, right_fit, calibration.car_to_model, REG_THRESHOLDS)
    
    # MPC
    if sm.updated['liveMpc']:
      draw_mpc(sm['liveMpc'], top_down)

    # draw all radar points
    maybe_update_radar_points(sm['liveTracks'], top_down[1])


    if sm.updated['liveCalibration']:
      extrinsic_matrix = np.asarray(sm['liveCalibration'].extrinsicMatrix).reshape(3, 4)
      ke = intrinsic_matrix.dot(extrinsic_matrix)
      warp_matrix = get_camera_frame_from_model_frame(ke)
      calibration = CalibrationTransformsForWarpMatrix(warp_matrix, intrinsic_matrix, extrinsic_matrix)

    # draw red pt for lead car in the main img
    for lead in [sm['radarState'].leadOne, sm['radarState'].leadTwo]:
      if lead.status:
        if calibration is not None:
          draw_lead_on(img, lead.dRel, lead.yRel, calibration, color=(192,0,0))

        draw_lead_car(lead.dRel, top_down)

    # *** blits ***
    pygame.surfarray.blit_array(camera_surface, img.swapaxes(0,1))
    screen.blit(camera_surface, (0, 0))

    # display alerts
    alert_line1 = alert1_font.render(sm['controlsState'].alertText1, True, (255,0,0))
    alert_line2 = alert2_font.render(sm['controlsState'].alertText2, True, (255,0,0))
    screen.blit(alert_line1, (180, 150))
    screen.blit(alert_line2, (180, 190))

    if calibration is not None and img is not None:
      cpw = warp_points(CalP, calibration.model_to_bb)
      vanishing_pointw = warp_points(vanishing_point, calibration.model_to_bb)
      pygame.draw.polygon(screen, BLUE, tuple(map(tuple, cpw)), 1)
      pygame.draw.circle(screen, BLUE, list(map(int, map(round, vanishing_pointw[0]))), 2)

    if HOR:
      screen.blit(draw_plots(plot_arr), (640+384, 0))
    else:
      screen.blit(draw_plots(plot_arr), (0, 600))

    pygame.surfarray.blit_array(cameraw_surface, imgw.swapaxes(0, 1))
    screen.blit(cameraw_surface, (320, 480))

    pygame.surfarray.blit_array(*top_down)
    screen.blit(top_down[0], (640,0))

    i = 0
    SPACING = 25

    lines = [
      info_font.render("ENABLED", True, GREEN if sm['controlsState'].enabled else BLACK),
      info_font.render("BRAKE LIGHTS", True, RED if sm['carState'].brakeLights else BLACK),
      info_font.render("SPEED: " + str(round(sm['carState'].vEgo, 1)) + " m/s", True, YELLOW),
      info_font.render("LONG CONTROL STATE: " + str(sm['controlsState'].longControlState), True, YELLOW),
      info_font.render("LONG MPC SOURCE: " + str(sm['plan'].longitudinalPlanSource), True, YELLOW),
      None,
      info_font.render("ANGLE OFFSET (AVG): " + str(round(sm['liveParameters'].angleOffsetAverage, 2)) + " deg", True, YELLOW),
      info_font.render("ANGLE OFFSET (INSTANT): " + str(round(sm['liveParameters'].angleOffset, 2)) + " deg", True, YELLOW),
      info_font.render("STIFFNESS: " + str(round(sm['liveParameters'].stiffnessFactor * 100., 2)) + " %", True, YELLOW),
      info_font.render("STEER RATIO: " + str(round(sm['liveParameters'].steerRatio, 2)), True, YELLOW)
    ]

    for i, line in enumerate(lines):
      if line is not None:
        screen.blit(line, (write_x, write_y + i * SPACING))

    # this takes time...vsync or something
    pygame.display.flip()
Exemple #4
0
    def __init__(self, sm=None, pm=None, can_sock=None):
        config_realtime_process(4 if TICI else 3, Priority.CTRL_HIGH)

        # Setup sockets
        self.pm = pm
        if self.pm is None:
            self.pm = messaging.PubMaster([
                'sendcan', 'controlsState', 'carState', 'carControl',
                'carEvents', 'carParams'
            ])

        self.camera_packets = ["roadCameraState", "driverCameraState"]
        if TICI:
            self.camera_packets.append("wideRoadCameraState")

        params = Params()
        self.joystick_mode = params.get_bool("JoystickDebugMode")
        joystick_packet = ['testJoystick'] if self.joystick_mode else []

        self.sm = sm
        if self.sm is None:
            ignore = ['driverCameraState', 'managerState'
                      ] if SIMULATION else None
            self.sm = messaging.SubMaster(
                [
                    'deviceState', 'pandaStates', 'peripheralState', 'modelV2',
                    'liveCalibration', 'driverMonitoringState',
                    'longitudinalPlan', 'lateralPlan', 'liveLocationKalman',
                    'managerState', 'liveParameters', 'radarState'
                ] + self.camera_packets + joystick_packet,
                ignore_alive=ignore,
                ignore_avg_freq=['radarState', 'longitudinalPlan'])

        self.can_sock = can_sock
        if can_sock is None:
            can_timeout = None if os.environ.get('NO_CAN_TIMEOUT',
                                                 False) else 100
            self.can_sock = messaging.sub_sock('can', timeout=can_timeout)

        if TICI:
            self.log_sock = messaging.sub_sock('androidLog')

        # wait for one pandaState and one CAN packet
        print("Waiting for CAN messages...")
        get_one_can(self.can_sock)

        self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'])

        # read params
        self.is_metric = params.get_bool("IsMetric")
        self.is_ldw_enabled = params.get_bool("IsLdwEnabled")
        community_feature_toggle = params.get_bool("CommunityFeaturesToggle")
        openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle")
        passive = params.get_bool("Passive") or not openpilot_enabled_toggle

        # detect sound card presence and ensure successful init
        sounds_available = HARDWARE.get_sound_card_online()

        car_recognized = self.CP.carName != 'mock'

        controller_available = self.CI.CC is not None and not passive and not self.CP.dashcamOnly
        community_feature = self.CP.communityFeature or \
                            self.CP.fingerprintSource == car.CarParams.FingerprintSource.can
        community_feature_disallowed = community_feature and (
            not community_feature_toggle)
        self.read_only = not car_recognized or not controller_available or \
                           self.CP.dashcamOnly or community_feature_disallowed
        if self.read_only:
            safety_config = car.CarParams.SafetyConfig.new_message()
            safety_config.safetyModel = car.CarParams.SafetyModel.noOutput
            self.CP.safetyConfigs = [safety_config]

        # Write CarParams for radard
        cp_bytes = self.CP.to_bytes()
        params.put("CarParams", cp_bytes)
        put_nonblocking("CarParamsCache", cp_bytes)

        self.CC = car.CarControl.new_message()
        self.AM = AlertManager()
        self.events = Events()

        self.LoC = LongControl(self.CP)
        self.VM = VehicleModel(self.CP)

        if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
            self.LaC = LatControlAngle(self.CP)
        elif self.CP.lateralTuning.which() == 'pid':
            self.LaC = LatControlPID(self.CP, self.CI)
        elif self.CP.lateralTuning.which() == 'indi':
            self.LaC = LatControlINDI(self.CP)
        elif self.CP.lateralTuning.which() == 'lqr':
            self.LaC = LatControlLQR(self.CP)

        self.initialized = False
        self.state = State.disabled
        self.enabled = False
        self.active = False
        self.can_rcv_error = False
        self.soft_disable_timer = 0
        self.v_cruise_kph = 255
        self.v_cruise_kph_last = 0
        self.mismatch_counter = 0
        self.cruise_mismatch_counter = 0
        self.can_error_counter = 0
        self.last_blinker_frame = 0
        self.saturated_count = 0
        self.distance_traveled = 0
        self.last_functional_fan_frame = 0
        self.events_prev = []
        self.current_alert_types = [ET.PERMANENT]
        self.logged_comm_issue = False
        self.button_timers = {
            ButtonEvent.Type.decelCruise: 0,
            ButtonEvent.Type.accelCruise: 0
        }

        # scc smoother
        self.is_cruise_enabled = False
        self.applyMaxSpeed = 0
        self.apply_accel = 0.
        self.fused_accel = 0.
        self.lead_drel = 0.
        self.aReqValue = 0.
        self.aReqValueMin = 0.
        self.aReqValueMax = 0.
        self.sccStockCamStatus = 0
        self.sccStockCamAct = 0

        self.left_lane_visible = False
        self.right_lane_visible = False

        self.wide_camera = TICI and params.get_bool('EnableWideCamera')
        self.disable_op_fcw = params.get_bool('DisableOpFcw')

        # TODO: no longer necessary, aside from process replay
        self.sm['liveParameters'].valid = True

        self.startup_event = get_startup_event(car_recognized,
                                               controller_available,
                                               len(self.CP.carFw) > 0)

        if not sounds_available:
            self.events.add(EventName.soundsUnavailable, static=True)
        if community_feature_disallowed and car_recognized and not self.CP.dashcamOnly:
            self.events.add(EventName.communityFeatureDisallowed, static=True)
        if not car_recognized:
            self.events.add(EventName.carUnrecognized, static=True)
            if len(self.CP.carFw) > 0:
                set_offroad_alert("Offroad_CarUnrecognized", True)
            else:
                set_offroad_alert("Offroad_NoFirmware", True)
        elif self.read_only:
            self.events.add(EventName.dashcamMode, static=True)
        elif self.joystick_mode:
            self.events.add(EventName.joystickDebug, static=True)
            self.startup_event = None

        # controlsd is driven by can recv, expected at 100Hz
        self.rk = Ratekeeper(100, print_delay_threshold=None)
        self.prof = Profiler(False)  # off by default
    def __init__(self, sm=None, pm=None, can_sock=None):
        config_realtime_process(3, Priority.CTRL_HIGH)

        # Setup sockets
        self.pm = pm
        if self.pm is None:
            self.pm = messaging.PubMaster([
                'sendcan', 'controlsState', 'carState', 'carControl',
                'carEvents', 'carParams'
            ])

        self.sm = sm
        if self.sm is None:
            self.sm = messaging.SubMaster([
                'thermal', 'health', 'model', 'liveCalibration', 'frontFrame',
                'dMonitoringState', 'plan', 'pathPlan', 'liveLocationKalman'
            ])

        self.can_sock = can_sock
        if can_sock is None:
            can_timeout = None if os.environ.get('NO_CAN_TIMEOUT',
                                                 False) else 100
            self.can_sock = messaging.sub_sock('can', timeout=can_timeout)

        # wait for one health and one CAN packet
        print("Waiting for CAN messages...")
        get_one_can(self.can_sock)

        self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'])

        # read params
        params = Params()
        self.is_metric = params.get("IsMetric", encoding='utf8') == "1"
        self.is_ldw_enabled = params.get("IsLdwEnabled",
                                         encoding='utf8') == "1"
        internet_needed = (params.get("Offroad_ConnectivityNeeded",
                                      encoding='utf8') is not None) and (
                                          params.get("DisableUpdates") != b"1")
        community_feature_toggle = params.get("CommunityFeaturesToggle",
                                              encoding='utf8') == "1"
        openpilot_enabled_toggle = params.get("OpenpilotEnabledToggle",
                                              encoding='utf8') == "1"
        passive = params.get("Passive", encoding='utf8') == "1" or \
                  internet_needed or not openpilot_enabled_toggle

        # detect sound card presence and ensure successful init
        sounds_available = HARDWARE.get_sound_card_online()

        car_recognized = self.CP.carName != 'mock'
        # If stock camera is disconnected, we loaded car controls and it's not dashcam mode
        controller_available = self.CP.enableCamera and self.CI.CC is not None and not passive and not self.CP.dashcamOnly
        community_feature_disallowed = self.CP.communityFeature and not community_feature_toggle
        self.read_only = not car_recognized or not controller_available or \
                           self.CP.dashcamOnly or community_feature_disallowed
        if self.read_only:
            self.CP.safetyModel = car.CarParams.SafetyModel.noOutput

        # Write CarParams for radard and boardd safety mode
        cp_bytes = self.CP.to_bytes()
        params.put("CarParams", cp_bytes)
        put_nonblocking("CarParamsCache", cp_bytes)

        self.CC = car.CarControl.new_message()
        self.AM = AlertManager()
        self.events = Events()

        self.LoC = LongControl(self.CP, self.CI.compute_gb)
        self.VM = VehicleModel(self.CP)

        if self.CP.lateralTuning.which() == 'pid':
            self.LaC = LatControlPID(self.CP)
        elif self.CP.lateralTuning.which() == 'indi':
            self.LaC = LatControlINDI(self.CP)
        elif self.CP.lateralTuning.which() == 'lqr':
            self.LaC = LatControlLQR(self.CP)

        self.state = State.disabled
        self.enabled = False
        self.active = False
        self.can_rcv_error = False
        self.soft_disable_timer = 0
        self.v_cruise_kph = 255
        self.v_cruise_kph_last = 0
        self.mismatch_counter = 0
        self.can_error_counter = 0
        self.last_blinker_frame = 0
        self.saturated_count = 0
        self.distance_traveled = 0
        self.last_functional_fan_frame = 0
        self.events_prev = []
        self.current_alert_types = [ET.PERMANENT]

        self.sm['liveCalibration'].calStatus = Calibration.CALIBRATED
        self.sm['thermal'].freeSpace = 1.
        self.sm['dMonitoringState'].events = []
        self.sm['dMonitoringState'].awarenessStatus = 1.
        self.sm['dMonitoringState'].faceDetected = False

        self.startup_event = get_startup_event(car_recognized,
                                               controller_available)

        if not sounds_available:
            self.events.add(EventName.soundsUnavailable, static=True)
        if internet_needed:
            self.events.add(EventName.internetConnectivityNeeded, static=True)
        if community_feature_disallowed:
            self.events.add(EventName.communityFeatureDisallowed, static=True)
        if not car_recognized:
            self.events.add(EventName.carUnrecognized, static=True)

        # controlsd is driven by can recv, expected at 100Hz
        self.rk = Ratekeeper(100, print_delay_threshold=None)
        self.prof = Profiler(False)  # off by default
Exemple #6
0
def manager_thread():
    # now loop
    thermal_sock = messaging.sub_sock('thermal')

    cloudlog.info("manager start")
    cloudlog.info({"environ": os.environ})

    # save boot log
    subprocess.call(["./loggerd", "--bootlog"],
                    cwd=os.path.join(BASEDIR, "selfdrive/loggerd"))

    params = Params()

    # start daemon processes
    for p in daemon_processes:
        start_daemon_process(p)

    # start persistent processes
    for p in persistent_processes:
        start_managed_process(p)

    # start offroad
    if ANDROID:
        pm_apply_packages('enable')
        start_offroad()

    if os.getenv("NOBOARD") is None:
        start_managed_process("pandad")

    if os.getenv("BLOCK") is not None:
        for k in os.getenv("BLOCK").split(","):
            del managed_processes[k]

    started_prev = False
    logger_dead = False

    while 1:
        msg = messaging.recv_sock(thermal_sock, wait=True)

        # heavyweight batch processes are gated on favorable thermal conditions
        if msg.thermal.thermalStatus >= ThermalStatus.yellow:
            for p in green_temp_processes:
                if p in persistent_processes:
                    kill_managed_process(p)
        else:
            for p in green_temp_processes:
                if p in persistent_processes:
                    start_managed_process(p)

        if msg.thermal.freeSpace < 0.05:
            logger_dead = True

        if msg.thermal.started:
            for p in car_started_processes:
                if p == "loggerd" and logger_dead:
                    kill_managed_process(p)
                else:
                    start_managed_process(p)
        else:
            logger_dead = False
            driver_view = params.get("IsDriverViewEnabled") == b"1"

            # TODO: refactor how manager manages processes
            for p in reversed(car_started_processes):
                if p not in driver_view_processes or not driver_view:
                    kill_managed_process(p)

            for p in driver_view_processes:
                if driver_view:
                    start_managed_process(p)
                else:
                    kill_managed_process(p)

            # trigger an update after going offroad
            if started_prev:
                send_managed_process_signal("updated", signal.SIGHUP)

        started_prev = msg.thermal.started

        # check the status of all processes, did any of them die?
        running_list = [
            "%s%s\u001b[0m" %
            ("\u001b[32m" if running[p].is_alive() else "\u001b[31m", p)
            for p in running
        ]
        cloudlog.debug(' '.join(running_list))

        # Exit main loop when uninstall is needed
        if params.get("DoUninstall", encoding='utf8') == "1":
            break
Exemple #7
0
    def __init__(self):
        self.slowing_down = False
        self.started_dist = 0

        self.sock = messaging.sub_sock("roadLimitSpeed")
        self.roadLimitSpeed = None
Exemple #8
0
def mapsd_thread():
    global last_gps

    gps_sock = messaging.sub_sock('gpsLocation', conflate=True)
    gps_external_sock = messaging.sub_sock('gpsLocationExternal',
                                           conflate=True)
    map_data_sock = messaging.pub_sock('liveMapData')

    cur_way = None
    curvature_valid = False
    curvature = None
    upcoming_curvature = 0.
    dist_to_turn = 0.
    road_points = None

    while True:
        gps = messaging.recv_one(gps_sock)
        gps_ext = messaging.recv_one_or_none(gps_external_sock)

        if gps_ext is not None:
            gps = gps_ext.gpsLocationExternal
        else:
            gps = gps.gpsLocation

        last_gps = gps

        fix_ok = gps.flags & 1
        if not fix_ok or last_query_result is None or not cache_valid:
            cur_way = None
            curvature = None
            curvature_valid = False
            upcoming_curvature = 0.
            dist_to_turn = 0.
            road_points = None
            map_valid = False
        else:
            map_valid = True
            lat = gps.latitude
            lon = gps.longitude
            heading = gps.bearing
            speed = gps.speed

            query_lock.acquire()
            cur_way = Way.closest(last_query_result, lat, lon, heading,
                                  cur_way)
            if cur_way is not None:
                pnts, curvature_valid = cur_way.get_lookahead(
                    lat, lon, heading, MAPS_LOOKAHEAD_DISTANCE)

                xs = pnts[:, 0]
                ys = pnts[:, 1]
                road_points = [float(x) for x in xs], [float(y) for y in ys]

                if speed < 10:
                    curvature_valid = False
                if curvature_valid and pnts.shape[0] <= 3:
                    curvature_valid = False

                # The curvature is valid when at least MAPS_LOOKAHEAD_DISTANCE of road is found
                if curvature_valid:
                    # Compute the curvature for each point
                    with np.errstate(divide='ignore'):
                        circles = [
                            circle_through_points(*p)
                            for p in zip(pnts, pnts[1:], pnts[2:])
                        ]
                        circles = np.asarray(circles)
                        radii = np.nan_to_num(circles[:, 2])
                        radii[radii < 10] = np.inf
                        curvature = 1. / radii

                    # Index of closest point
                    closest = np.argmin(np.linalg.norm(pnts, axis=1))
                    dist_to_closest = pnts[
                        closest,
                        0]  # We can use x distance here since it should be close

                    # Compute distance along path
                    dists = list()
                    dists.append(0)
                    for p, p_prev in zip(pnts, pnts[1:, :]):
                        dists.append(dists[-1] + np.linalg.norm(p - p_prev))
                    dists = np.asarray(dists)
                    dists = dists - dists[closest] + dist_to_closest
                    dists = dists[1:-1]

                    close_idx = np.logical_and(dists > 0, dists < 500)
                    dists = dists[close_idx]
                    curvature = curvature[close_idx]

                    if len(curvature):
                        # TODO: Determine left or right turn
                        curvature = np.nan_to_num(curvature)

                        # Outlier rejection
                        new_curvature = np.percentile(curvature,
                                                      90,
                                                      interpolation='lower')

                        k = 0.6
                        upcoming_curvature = k * upcoming_curvature + (
                            1 - k) * new_curvature
                        in_turn_indices = curvature > 0.8 * new_curvature

                        if np.any(in_turn_indices):
                            dist_to_turn = np.min(dists[in_turn_indices])
                        else:
                            dist_to_turn = 999
                    else:
                        upcoming_curvature = 0.
                        dist_to_turn = 999

            query_lock.release()

        dat = messaging.new_message('liveMapData')

        if last_gps is not None:
            dat.liveMapData.lastGps = last_gps

        if cur_way is not None:
            dat.liveMapData.wayId = cur_way.id

            # Speed limit
            max_speed = cur_way.max_speed()
            if max_speed is not None:
                dat.liveMapData.speedLimitValid = True
                dat.liveMapData.speedLimit = max_speed

                # TODO: use the function below to anticipate upcoming speed limits
                #max_speed_ahead, max_speed_ahead_dist = cur_way.max_speed_ahead(max_speed, lat, lon, heading, MAPS_LOOKAHEAD_DISTANCE)
                #if max_speed_ahead is not None and max_speed_ahead_dist is not None:
                #  dat.liveMapData.speedLimitAheadValid = True
                #  dat.liveMapData.speedLimitAhead = float(max_speed_ahead)
                #  dat.liveMapData.speedLimitAheadDistance = float(max_speed_ahead_dist)

            advisory_max_speed = cur_way.advisory_max_speed()
            if advisory_max_speed is not None:
                dat.liveMapData.speedAdvisoryValid = True
                dat.liveMapData.speedAdvisory = advisory_max_speed

            # Curvature
            dat.liveMapData.curvatureValid = curvature_valid
            dat.liveMapData.curvature = float(upcoming_curvature)
            dat.liveMapData.distToTurn = float(dist_to_turn)
            if road_points is not None:
                dat.liveMapData.roadX, dat.liveMapData.roadY = road_points
            if curvature is not None:
                dat.liveMapData.roadCurvatureX = [float(x) for x in dists]
                dat.liveMapData.roadCurvature = [float(x) for x in curvature]

        dat.liveMapData.mapValid = map_valid

        map_data_sock.send(dat.to_bytes())
Exemple #9
0
    fig, ax = plt.subplots()
    #fig = plt.figure(figsize=(10, 15))
    #ax = fig.add_subplot(111)
    ax.grid(True)
    fig.canvas.draw()

    subs_name = sys.argv[1:]
    lines = []
    x, y = [], []
    LEN = 500

    for i, sub in enumerate(subs_name):
        sub_split = sub.split(".")
        services.append(sub_split[0])
        fields.append(".".join(sub_split[1:]))
        subs.append(messaging.sub_sock(sub_split[0], poller))

        x.append(np.ones(LEN) * np.nan)
        y.append(np.ones(LEN) * np.nan)
        lines.append(ax.plot(x[i], y[i])[0])

    for l in lines:
        l.set_marker("*")

    cur_t = 0.
    ax.legend(subs_name)
    ax.set_xlabel('time [s]')

    while 1:
        print(1. / (time.time() - cur_t))
        cur_t = time.time()
Exemple #10
0
def ui_thread(addr, frame_address):
    pygame.init()
    pygame.font.init()
    assert pygame_modules_have_loaded()

    size = (int(_FULL_FRAME_SIZE[0] * SCALE), int(_FULL_FRAME_SIZE[1] * SCALE))
    print(size)
    pygame.display.set_caption("comma one debug UI")
    screen = pygame.display.set_mode(size, pygame.DOUBLEBUF)

    camera_surface = pygame.surface.Surface(
        (_FULL_FRAME_SIZE[0] * SCALE, _FULL_FRAME_SIZE[1] * SCALE), 0,
        24).convert()

    frame = messaging.sub_sock('frame', conflate=True)

    img = np.zeros((_FULL_FRAME_SIZE[1], _FULL_FRAME_SIZE[0], 3),
                   dtype='uint8')
    imgff = np.zeros((_FULL_FRAME_SIZE[1], _FULL_FRAME_SIZE[0], 3),
                     dtype=np.uint8)

    while 1:
        list(pygame.event.get())
        screen.fill((64, 64, 64))

        # ***** frame *****
        fpkt = messaging.recv_one(frame)
        yuv_img = fpkt.frame.image

        if fpkt.frame.transform:
            yuv_transform = np.array(fpkt.frame.transform).reshape(3, 3)
        else:
            # assume frame is flipped
            yuv_transform = np.array([[-1.0, 0.0, _FULL_FRAME_SIZE[0] - 1],
                                      [0.0, -1.0, _FULL_FRAME_SIZE[1] - 1],
                                      [0.0, 0.0, 1.0]])

        if yuv_img and len(
                yuv_img) == _FULL_FRAME_SIZE[0] * _FULL_FRAME_SIZE[1] * 3 // 2:
            yuv_np = np.frombuffer(yuv_img, dtype=np.uint8).reshape(
                _FULL_FRAME_SIZE[1] * 3 // 2, -1)
            cv2.cvtColor(yuv_np, cv2.COLOR_YUV2RGB_I420, dst=imgff)
            cv2.warpAffine(imgff,
                           np.dot(yuv_transform, _BB_TO_FULL_FRAME)[:2],
                           (img.shape[1], img.shape[0]),
                           dst=img,
                           flags=cv2.WARP_INVERSE_MAP)
        else:
            # actually RGB
            img = np.frombuffer(yuv_img, dtype=np.uint8).reshape(
                (_FULL_FRAME_SIZE[1], _FULL_FRAME_SIZE[0], 3))
            img = img[:, :, ::-1]  # Convert BGR to RGB

        height, width = img.shape[:2]
        img_resized = cv2.resize(img,
                                 (int(SCALE * width), int(SCALE * height)),
                                 interpolation=cv2.INTER_CUBIC)
        # *** blits ***
        pygame.surfarray.blit_array(camera_surface, img_resized.swapaxes(0, 1))
        screen.blit(camera_surface, (0, 0))

        # this takes time...vsync or something
        pygame.display.flip()
Exemple #11
0
def thermald_thread():

    pm = messaging.PubMaster(['deviceState'])

    pandaState_timeout = int(1000 * 2.5 *
                             DT_TRML)  # 2.5x the expected pandaState frequency
    pandaState_sock = messaging.sub_sock('pandaStates',
                                         timeout=pandaState_timeout)
    sm = messaging.SubMaster(
        ["peripheralState", "gpsLocationExternal", "managerState"])

    fan_speed = 0
    count = 0

    startup_conditions = {
        "ignition": False,
    }
    startup_conditions_prev = startup_conditions.copy()

    off_ts = None
    started_ts = None
    started_seen = False
    thermal_status = ThermalStatus.green
    usb_power = True

    network_type = NetworkType.none
    network_strength = NetworkStrength.unknown
    network_info = None
    modem_version = None
    registered_count = 0
    nvme_temps = None
    modem_temps = None

    current_filter = FirstOrderFilter(0., CURRENT_TAU, DT_TRML)
    temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_TRML)
    pandaState_prev = None
    should_start_prev = False
    in_car = False
    handle_fan = None
    is_uno = False
    ui_running_prev = False

    params = Params()
    power_monitor = PowerMonitoring()
    no_panda_cnt = 0

    HARDWARE.initialize_hardware()
    thermal_config = HARDWARE.get_thermal_config()

    # TODO: use PI controller for UNO
    controller = PIController(k_p=0,
                              k_i=2e-3,
                              neg_limit=-80,
                              pos_limit=0,
                              rate=(1 / DT_TRML))

    # Leave flag for loggerd to indicate device was left onroad
    if params.get_bool("IsOnroad"):
        params.put_bool("BootedOnroad", True)

    while True:
        pandaStates = messaging.recv_sock(pandaState_sock, wait=True)

        sm.update(0)
        peripheralState = sm['peripheralState']

        msg = read_thermal(thermal_config)

        if pandaStates is not None and len(pandaStates.pandaStates) > 0:
            pandaState = pandaStates.pandaStates[0]

            # If we lose connection to the panda, wait 5 seconds before going offroad
            if pandaState.pandaType == log.PandaState.PandaType.unknown:
                no_panda_cnt += 1
                if no_panda_cnt > DISCONNECT_TIMEOUT / DT_TRML:
                    if startup_conditions["ignition"]:
                        cloudlog.error("Lost panda connection while onroad")
                    startup_conditions["ignition"] = False
            else:
                no_panda_cnt = 0
                startup_conditions[
                    "ignition"] = pandaState.ignitionLine or pandaState.ignitionCan

            in_car = pandaState.harnessStatus != log.PandaState.HarnessStatus.notConnected
            usb_power = peripheralState.usbPowerMode != log.PeripheralState.UsbPowerMode.client

            # Setup fan handler on first connect to panda
            if handle_fan is None and peripheralState.pandaType != log.PandaState.PandaType.unknown:
                is_uno = peripheralState.pandaType == log.PandaState.PandaType.uno

                if TICI:
                    cloudlog.info("Setting up TICI fan handler")
                    handle_fan = handle_fan_tici
                elif is_uno or PC:
                    cloudlog.info("Setting up UNO fan handler")
                    handle_fan = handle_fan_uno
                else:
                    cloudlog.info("Setting up EON fan handler")
                    setup_eon_fan()
                    handle_fan = handle_fan_eon

            # Handle disconnect
            if pandaState_prev is not None:
                if pandaState.pandaType == log.PandaState.PandaType.unknown and \
                  pandaState_prev.pandaType != log.PandaState.PandaType.unknown:
                    params.clear_all(ParamKeyType.CLEAR_ON_PANDA_DISCONNECT)
            pandaState_prev = pandaState

        # these are expensive calls. update every 10s
        if (count % int(10. / DT_TRML)) == 0:
            try:
                network_type = HARDWARE.get_network_type()
                network_strength = HARDWARE.get_network_strength(network_type)
                network_info = HARDWARE.get_network_info()  # pylint: disable=assignment-from-none
                nvme_temps = HARDWARE.get_nvme_temperatures()
                modem_temps = HARDWARE.get_modem_temperatures()

                # Log modem version once
                if modem_version is None:
                    modem_version = HARDWARE.get_modem_version()  # pylint: disable=assignment-from-none
                    if modem_version is not None:
                        cloudlog.warning(f"Modem version: {modem_version}")

                if TICI and (network_info.get('state', None) == "REGISTERED"):
                    registered_count += 1
                else:
                    registered_count = 0

                if registered_count > 10:
                    cloudlog.warning(
                        f"Modem stuck in registered state {network_info}. nmcli conn up lte"
                    )
                    os.system("nmcli conn up lte")
                    registered_count = 0

            except Exception:
                cloudlog.exception("Error getting network status")

        msg.deviceState.freeSpacePercent = get_available_percent(default=100.0)
        msg.deviceState.memoryUsagePercent = int(
            round(psutil.virtual_memory().percent))
        msg.deviceState.cpuUsagePercent = [
            int(round(n)) for n in psutil.cpu_percent(percpu=True)
        ]
        msg.deviceState.gpuUsagePercent = int(
            round(HARDWARE.get_gpu_usage_percent()))
        msg.deviceState.networkType = network_type
        msg.deviceState.networkStrength = network_strength
        if network_info is not None:
            msg.deviceState.networkInfo = network_info
        if nvme_temps is not None:
            msg.deviceState.nvmeTempC = nvme_temps
        if modem_temps is not None:
            msg.deviceState.modemTempC = modem_temps

        msg.deviceState.screenBrightnessPercent = HARDWARE.get_screen_brightness(
        )
        msg.deviceState.batteryPercent = HARDWARE.get_battery_capacity()
        msg.deviceState.batteryCurrent = HARDWARE.get_battery_current()
        msg.deviceState.usbOnline = HARDWARE.get_usb_present()
        current_filter.update(msg.deviceState.batteryCurrent / 1e6)

        max_comp_temp = temp_filter.update(
            max(max(msg.deviceState.cpuTempC), msg.deviceState.memoryTempC,
                max(msg.deviceState.gpuTempC)))

        if handle_fan is not None:
            fan_speed = handle_fan(controller, max_comp_temp, fan_speed,
                                   startup_conditions["ignition"])
            msg.deviceState.fanSpeedPercentDesired = fan_speed

        is_offroad_for_5_min = (started_ts is None) and (
            (not started_seen) or (off_ts is None) or
            (sec_since_boot() - off_ts > 60 * 5))
        if is_offroad_for_5_min and max_comp_temp > OFFROAD_DANGER_TEMP:
            # If device is offroad we want to cool down before going onroad
            # since going onroad increases load and can make temps go over 107
            thermal_status = ThermalStatus.danger
        else:
            current_band = THERMAL_BANDS[thermal_status]
            band_idx = list(THERMAL_BANDS.keys()).index(thermal_status)
            if current_band.min_temp is not None and max_comp_temp < current_band.min_temp:
                thermal_status = list(THERMAL_BANDS.keys())[band_idx - 1]
            elif current_band.max_temp is not None and max_comp_temp > current_band.max_temp:
                thermal_status = list(THERMAL_BANDS.keys())[band_idx + 1]

        # **** starting logic ****

        # Check for last update time and display alerts if needed
        now = datetime.datetime.utcnow()

        # show invalid date/time alert
        startup_conditions["time_valid"] = (now.year > 2020) or (
            now.year == 2020 and now.month >= 10)
        set_offroad_alert_if_changed("Offroad_InvalidTime",
                                     (not startup_conditions["time_valid"]))

        # Show update prompt
        try:
            last_update = datetime.datetime.fromisoformat(
                params.get("LastUpdateTime", encoding='utf8'))
        except (TypeError, ValueError):
            last_update = now
        dt = now - last_update

        update_failed_count = params.get("UpdateFailedCount")
        update_failed_count = 0 if update_failed_count is None else int(
            update_failed_count)
        last_update_exception = params.get("LastUpdateException",
                                           encoding='utf8')

        if update_failed_count > 15 and last_update_exception is not None:
            if tested_branch:
                extra_text = "Ensure the software is correctly installed"
            else:
                extra_text = last_update_exception

            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)
            set_offroad_alert_if_changed("Offroad_UpdateFailed",
                                         True,
                                         extra_text=extra_text)
        elif dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", True)
        elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
            remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         True,
                                         extra_text=f"{remaining_time} days.")
        else:
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)

        startup_conditions["up_to_date"] = params.get(
            "Offroad_ConnectivityNeeded") is None or params.get_bool(
                "DisableUpdates")
        startup_conditions["not_uninstalling"] = not params.get_bool(
            "DoUninstall")
        startup_conditions["accepted_terms"] = params.get(
            "HasAcceptedTerms") == terms_version

        panda_signature = params.get("PandaFirmware")
        startup_conditions["fw_version_match"] = (panda_signature is None) or (
            panda_signature == FW_SIGNATURE
        )  # don't show alert is no panda is connected (None)
        set_offroad_alert_if_changed(
            "Offroad_PandaFirmwareMismatch",
            (not startup_conditions["fw_version_match"]))

        # with 2% left, we killall, otherwise the phone will take a long time to boot
        startup_conditions["free_space"] = msg.deviceState.freeSpacePercent > 2
        startup_conditions["completed_training"] = params.get("CompletedTrainingVersion") == training_version or \
                                                   params.get_bool("Passive")
        startup_conditions["not_driver_view"] = not params.get_bool(
            "IsDriverViewEnabled")
        startup_conditions["not_taking_snapshot"] = not params.get_bool(
            "IsTakingSnapshot")
        # if any CPU gets above 107 or the battery gets above 63, kill all processes
        # controls will warn with CPU above 95 or battery above 60
        startup_conditions[
            "device_temp_good"] = thermal_status < ThermalStatus.danger
        set_offroad_alert_if_changed(
            "Offroad_TemperatureTooHigh",
            (not startup_conditions["device_temp_good"]))

        if TICI:
            set_offroad_alert_if_changed("Offroad_StorageMissing",
                                         (not Path("/data/media").is_mount()))

        # Handle offroad/onroad transition
        should_start = all(startup_conditions.values())
        if should_start != should_start_prev or (count == 0):
            params.put_bool("IsOnroad", should_start)
            params.put_bool("IsOffroad", not should_start)
            HARDWARE.set_power_save(not should_start)

        if should_start:
            off_ts = None
            if started_ts is None:
                started_ts = sec_since_boot()
                started_seen = True
        else:
            if startup_conditions["ignition"] and (startup_conditions !=
                                                   startup_conditions_prev):
                cloudlog.event("Startup blocked",
                               startup_conditions=startup_conditions)

            started_ts = None
            if off_ts is None:
                off_ts = sec_since_boot()

        # Offroad power monitoring
        power_monitor.calculate(peripheralState,
                                startup_conditions["ignition"])
        msg.deviceState.offroadPowerUsageUwh = power_monitor.get_power_used()
        msg.deviceState.carBatteryCapacityUwh = max(
            0, power_monitor.get_car_battery_capacity())

        # Check if we need to disable charging (handled by boardd)
        msg.deviceState.chargingDisabled = power_monitor.should_disable_charging(
            startup_conditions["ignition"], in_car, off_ts)

        # Check if we need to shut down
        if power_monitor.should_shutdown(peripheralState,
                                         startup_conditions["ignition"],
                                         in_car, off_ts, started_seen):
            cloudlog.info(f"shutting device down, offroad since {off_ts}")
            # TODO: add function for blocking cloudlog instead of sleep
            time.sleep(10)
            HARDWARE.shutdown()

        # If UI has crashed, set the brightness to reasonable non-zero value
        ui_running = "ui" in (p.name for p in sm["managerState"].processes
                              if p.running)
        if ui_running_prev and not ui_running:
            HARDWARE.set_screen_brightness(20)
        ui_running_prev = ui_running

        msg.deviceState.chargingError = current_filter.x > 0. and msg.deviceState.batteryPercent < 90  # if current is positive, then battery is being discharged
        msg.deviceState.started = started_ts is not None
        msg.deviceState.startedMonoTime = int(1e9 * (started_ts or 0))

        last_ping = params.get("LastAthenaPingTime")
        if last_ping is not None:
            msg.deviceState.lastAthenaPingTime = int(last_ping)

        msg.deviceState.thermalStatus = thermal_status
        pm.send("deviceState", msg)

        if EON and not is_uno:
            set_offroad_alert_if_changed("Offroad_ChargeDisabled",
                                         (not usb_power))

        should_start_prev = should_start
        startup_conditions_prev = startup_conditions.copy()

        # report to server once every 10 minutes
        if (count % int(600. / DT_TRML)) == 0:
            if EON and started_ts is None and msg.deviceState.memoryUsagePercent > 40:
                cloudlog.event("High offroad memory usage",
                               mem=msg.deviceState.memoryUsagePercent)

            cloudlog.event(
                "STATUS_PACKET",
                count=count,
                pandaStates=(strip_deprecated_keys(pandaStates.to_dict())
                             if pandaStates else None),
                peripheralState=strip_deprecated_keys(
                    peripheralState.to_dict()),
                location=(strip_deprecated_keys(
                    sm["gpsLocationExternal"].to_dict())
                          if sm.alive["gpsLocationExternal"] else None),
                deviceState=strip_deprecated_keys(msg.to_dict()))

        count += 1
    def __init__(self, sm=None, pm=None, can_sock=None):
        gc.disable()
        set_realtime_priority(3)

        # Setup sockets
        self.pm = pm
        if self.pm is None:
            self.pm = messaging.PubMaster(['sendcan', 'controlsState', 'carState', \
                                           'carControl', 'carEvents', 'carParams'])

        self.sm = sm
        if self.sm is None:
            self.sm = messaging.SubMaster(['thermal', 'health', 'model', 'liveCalibration', \
                                           'dMonitoringState', 'plan', 'pathPlan', 'liveLocationKalman'])

        self.can_sock = can_sock
        if can_sock is None:
            can_timeout = None if os.environ.get('NO_CAN_TIMEOUT',
                                                 False) else 100
            self.can_sock = messaging.sub_sock('can', timeout=can_timeout)

        # wait for one health and one CAN packet
        hw_type = messaging.recv_one(self.sm.sock['health']).health.hwType
        has_relay = hw_type in [HwType.blackPanda, HwType.uno]
        print("Waiting for CAN messages...")
        messaging.get_one_can(self.can_sock)

        self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'],
                                   has_relay)

        # read params
        params = Params()
        self.is_metric = params.get("IsMetric", encoding='utf8') == "1"
        self.is_ldw_enabled = params.get("IsLdwEnabled",
                                         encoding='utf8') == "1"
        internet_needed = params.get("Offroad_ConnectivityNeeded",
                                     encoding='utf8') is not None
        community_feature_toggle = params.get("CommunityFeaturesToggle",
                                              encoding='utf8') == "1"
        openpilot_enabled_toggle = params.get("OpenpilotEnabledToggle",
                                              encoding='utf8') == "1"
        passive = params.get("Passive", encoding='utf8') == "1" or \
                  internet_needed or not openpilot_enabled_toggle

        # detect sound card presence and ensure successful init
        sounds_available = not os.path.isfile('/EON') or (os.path.isfile('/proc/asound/card0/state') \
                                and open('/proc/asound/card0/state').read().strip() == 'ONLINE')

        car_recognized = self.CP.carName != 'mock'
        # If stock camera is disconnected, we loaded car controls and it's not dashcam mode
        controller_available = self.CP.enableCamera and self.CI.CC is not None and not passive
        community_feature_disallowed = self.CP.communityFeature and not community_feature_toggle
        self.read_only = not car_recognized or not controller_available or \
                           self.CP.dashcamOnly or community_feature_disallowed
        if self.read_only:
            self.CP.safetyModel = car.CarParams.SafetyModel.noOutput

        # Write CarParams for radard and boardd safety mode
        cp_bytes = self.CP.to_bytes()
        params.put("CarParams", cp_bytes)
        put_nonblocking("CarParamsCache", cp_bytes)
        put_nonblocking("LongitudinalControl",
                        "1" if self.CP.openpilotLongitudinalControl else "0")

        self.CC = car.CarControl.new_message()
        self.AM = AlertManager()
        self.events = Events()

        self.LoC = LongControl(self.CP, self.CI.compute_gb)
        self.VM = VehicleModel(self.CP)

        if self.CP.lateralTuning.which() == 'pid':
            self.LaC = LatControlPID(self.CP)
        elif self.CP.lateralTuning.which() == 'indi':
            self.LaC = LatControlINDI(self.CP)
        elif self.CP.lateralTuning.which() == 'lqr':
            self.LaC = LatControlLQR(self.CP)

        self.state = State.disabled
        self.enabled = False
        self.active = False
        self.can_rcv_error = False
        self.soft_disable_timer = 0
        self.v_cruise_kph = 255
        self.v_cruise_kph_last = 0
        self.mismatch_counter = 0
        self.can_error_counter = 0
        self.consecutive_can_error_count = 0
        self.last_blinker_frame = 0
        self.saturated_count = 0
        self.events_prev = []
        self.current_alert_types = []

        self.sm['liveCalibration'].calStatus = Calibration.INVALID
        self.sm['thermal'].freeSpace = 1.
        self.sm['dMonitoringState'].events = []
        self.sm['dMonitoringState'].awarenessStatus = 1.
        self.sm['dMonitoringState'].faceDetected = False

        self.startup_event = get_startup_event(car_recognized,
                                               controller_available, hw_type)

        if not sounds_available:
            self.events.add(EventName.soundsUnavailable, static=True)
        if internet_needed:
            self.events.add(EventName.internetConnectivityNeeded, static=True)
        if community_feature_disallowed:
            self.events.add(EventName.communityFeatureDisallowed, static=True)
        if self.read_only and not passive:
            self.events.add(EventName.carUnrecognized, static=True)
        # if hw_type == HwType.whitePanda:
        # self.events.add(EventName.whitePandaUnsupported, static=True)

        # controlsd is driven by can recv, expected at 100Hz
        self.rk = Ratekeeper(100, print_delay_threshold=None)
        self.prof = Profiler(False)  # off by default
Exemple #13
0
def thermald_thread():
    # prevent LEECO from undervoltage
    BATT_PERC_OFF = 100  #10 if LEON else 3

    health_timeout = int(1000 * 2.5 *
                         DT_TRML)  # 2.5x the expected health frequency

    # now loop
    thermal_sock = messaging.pub_sock('thermal')
    health_sock = messaging.sub_sock('health', timeout=health_timeout)
    location_sock = messaging.sub_sock('gpsLocation')

    ignition = False
    fan_speed = 0
    count = 0

    off_ts = None
    started_ts = None
    started_seen = False
    thermal_status = ThermalStatus.green
    thermal_status_prev = ThermalStatus.green
    usb_power = True
    usb_power_prev = True

    network_type = NetworkType.none
    network_strength = NetworkStrength.unknown

    current_filter = FirstOrderFilter(0., CURRENT_TAU, DT_TRML)
    cpu_temp_filter = FirstOrderFilter(0., CPU_TEMP_TAU, DT_TRML)
    health_prev = None
    fw_version_match_prev = True
    current_connectivity_alert = None
    time_valid_prev = True
    should_start_prev = False
    handle_fan = None
    is_uno = False

    params = Params()
    pm = PowerMonitoring()
    no_panda_cnt = 0

    IsOpenpilotViewEnabled = 0

    OpkrLoadStep = 0
    OpkrAutoShutdown = 0
    do_uninstall = 0
    accepted_terms = 0
    completed_training = 0
    panda_signature = 0

    ts_last_ip = 0
    ip_addr = '255.255.255.255'

    # sound trigger
    sound_trigger = 1

    env = dict(os.environ)
    env['LD_LIBRARY_PATH'] = mediaplayer

    getoff_alert = Params().get('OpkrEnableGetoffAlert') == b'1'

    while 1:
        OpkrLoadStep += 1
        if OpkrLoadStep == 1:
            OpkrAutoShutdown = params.get_OpkrAutoShutdown()
        elif OpkrLoadStep == 2:
            do_uninstall = params.get("DoUninstall") == b"1"
        elif OpkrLoadStep == 3:
            accepted_terms = params.get("HasAcceptedTerms") == terms_version
        elif OpkrLoadStep == 4:
            completed_training = params.get(
                "CompletedTrainingVersion") == training_version
        elif OpkrLoadStep == 5:
            panda_signature = params.get("PandaFirmware")
        else:
            OpkrLoadStep = 0

        ts = sec_since_boot()
        health = messaging.recv_sock(health_sock, wait=True)
        location = messaging.recv_sock(location_sock)
        location = location.gpsLocation if location else None
        msg = read_thermal()

        if health is not None:
            usb_power = health.health.usbPowerMode != log.HealthData.UsbPowerMode.client

            # If we lose connection to the panda, wait 5 seconds before going offroad
            if health.health.hwType == log.HealthData.HwType.unknown:
                no_panda_cnt += 1
                if no_panda_cnt > DISCONNECT_TIMEOUT / DT_TRML:
                    if ignition:
                        cloudlog.error("Lost panda connection while onroad")
                    ignition = False
            else:
                no_panda_cnt = 0
                ignition = health.health.ignitionLine or health.health.ignitionCan

            # Setup fan handler on first connect to panda
            if handle_fan is None and health.health.hwType != log.HealthData.HwType.unknown:
                is_uno = health.health.hwType == log.HealthData.HwType.uno

                if is_uno or not ANDROID:
                    cloudlog.info("Setting up UNO fan handler")
                    handle_fan = handle_fan_uno
                else:
                    cloudlog.info("Setting up EON fan handler")
                    setup_eon_fan()
                    handle_fan = handle_fan_eon

            # Handle disconnect
            if health_prev is not None:
                if health.health.hwType == log.HealthData.HwType.unknown and \
                  health_prev.health.hwType != log.HealthData.HwType.unknown:
                    params.panda_disconnect()
            health_prev = health
        elif ignition == False or IsOpenpilotViewEnabled:
            IsOpenpilotViewEnabled = int(params.get("IsOpenpilotViewEnabled"))
            ignition = IsOpenpilotViewEnabled

        # get_network_type is an expensive call. update every 10s
        if (count % int(10. / DT_TRML)) == 0:
            try:
                network_type = get_network_type()
                network_strength = get_network_strength(network_type)
            except Exception:
                cloudlog.exception("Error getting network status")

        msg.thermal.freeSpace = get_available_percent(default=100.0) / 100.0
        msg.thermal.memUsedPercent = int(round(
            psutil.virtual_memory().percent))
        msg.thermal.cpuPerc = int(round(psutil.cpu_percent()))
        msg.thermal.networkType = network_type
        msg.thermal.networkStrength = network_strength
        msg.thermal.batteryPercent = get_battery_capacity()
        msg.thermal.batteryStatus = get_battery_status()
        msg.thermal.batteryCurrent = get_battery_current()
        msg.thermal.batteryVoltage = get_battery_voltage()
        msg.thermal.usbOnline = get_usb_present()

        # Fake battery levels on uno for frame
        if is_uno:
            msg.thermal.batteryPercent = 100
            msg.thermal.batteryStatus = "Charging"

        # update ip every 10 seconds
        ts = sec_since_boot()
        if ts - ts_last_ip >= 10.:
            try:
                result = subprocess.check_output(["ifconfig", "wlan0"],
                                                 encoding='utf8')  # pylint: disable=unexpected-keyword-arg
                ip_addr = re.findall(r"inet addr:((\d+\.){3}\d+)",
                                     result)[0][0]
            except:
                ip_addr = 'N/A'
            ts_last_ip = ts
        msg.thermal.ipAddr = ip_addr

        current_filter.update(msg.thermal.batteryCurrent / 1e6)

        # TODO: add car battery voltage check
        max_cpu_temp = cpu_temp_filter.update(
            max(msg.thermal.cpu0, msg.thermal.cpu1, msg.thermal.cpu2,
                msg.thermal.cpu3) / 10.0)

        max_comp_temp = max(max_cpu_temp, msg.thermal.mem / 10.,
                            msg.thermal.gpu / 10.)
        bat_temp = msg.thermal.bat / 1000.

        if handle_fan is not None:
            fan_speed = handle_fan(max_cpu_temp, bat_temp, fan_speed, ignition)
            msg.thermal.fanSpeed = fan_speed

        # thermal logic with hysterisis
        if max_cpu_temp > 107. or bat_temp >= 63.:
            # onroad not allowed
            thermal_status = ThermalStatus.danger
        elif max_comp_temp > 92.5 or bat_temp > 60.:  # CPU throttling starts around ~90C
            # hysteresis between onroad not allowed and engage not allowed
            thermal_status = clip(thermal_status, ThermalStatus.red,
                                  ThermalStatus.danger)
        elif max_cpu_temp > 87.5:
            # hysteresis between engage not allowed and uploader not allowed
            thermal_status = clip(thermal_status, ThermalStatus.yellow,
                                  ThermalStatus.red)
        elif max_cpu_temp > 80.0:
            # uploader not allowed
            thermal_status = ThermalStatus.yellow
        elif max_cpu_temp > 75.0:
            # hysteresis between uploader not allowed and all good
            thermal_status = clip(thermal_status, ThermalStatus.green,
                                  ThermalStatus.yellow)
        else:
            # all good
            thermal_status = ThermalStatus.green

        # **** starting logic ****

        # Check for last update time and display alerts if needed
        now = datetime.datetime.utcnow()

        # show invalid date/time alert
        time_valid = now.year >= 2019
        if time_valid and not time_valid_prev:
            params.delete("Offroad_InvalidTime")
        if not time_valid and time_valid_prev:
            put_nonblocking("Offroad_InvalidTime",
                            json.dumps(OFFROAD_ALERTS["Offroad_InvalidTime"]))
        time_valid_prev = time_valid

        # Show update prompt

        #    try:
        #      last_update = datetime.datetime.fromisoformat(params.get("LastUpdateTime", encoding='utf8'))
        #    except (TypeError, ValueError):
        #      last_update = now
        #    dt = now - last_update

        #    update_failed_count = params.get("UpdateFailedCount")
        #    update_failed_count = 0 if update_failed_count is None else int(update_failed_count)

        #    if dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
        #      if current_connectivity_alert != "expired":
        #        current_connectivity_alert = "expired"
        #        params.delete("Offroad_ConnectivityNeededPrompt")
        #        put_nonblocking("Offroad_ConnectivityNeeded", json.dumps(OFFROAD_ALERTS["Offroad_ConnectivityNeeded"]))
        #    elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
        #      remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
        #      if current_connectivity_alert != "prompt" + remaining_time:
        #        current_connectivity_alert = "prompt" + remaining_time
        #        alert_connectivity_prompt = copy.copy(OFFROAD_ALERTS["Offroad_ConnectivityNeededPrompt"])
        #        alert_connectivity_prompt["text"] += remaining_time + " days."
        #        params.delete("Offroad_ConnectivityNeeded")
        #        put_nonblocking("Offroad_ConnectivityNeededPrompt", json.dumps(alert_connectivity_prompt))
        #    elif current_connectivity_alert is not None:
        #      current_connectivity_alert = None
        #      params.delete("Offroad_ConnectivityNeeded")
        #      params.delete("Offroad_ConnectivityNeededPrompt")

        #accepted_terms = params.get("HasAcceptedTerms") == terms_version
        #completed_training = params.get("CompletedTrainingVersion") == training_version
        #panda_signature = params.get("PandaFirmware")

        fw_version_match = (panda_signature is None) or (
            panda_signature == FW_SIGNATURE
        )  # don't show alert is no panda is connected (None)

        should_start = ignition

        # with 2% left, we killall, otherwise the phone will take a long time to boot
        should_start = should_start and msg.thermal.freeSpace > 0.02

        # confirm we have completed training and aren't uninstalling
        should_start = should_start and accepted_terms and completed_training and (
            not do_uninstall)

        # check for firmware mismatch
        should_start = should_start and fw_version_match

        # check if system time is valid
        should_start = should_start and time_valid

        # don't start while taking snapshot
        if not should_start_prev:
            is_viewing_driver = params.get("IsDriverViewEnabled") == b"1"
            is_taking_snapshot = params.get("IsTakingSnapshot") == b"1"
            should_start = should_start and (not is_taking_snapshot) and (
                not is_viewing_driver)

        if fw_version_match and not fw_version_match_prev:
            params.delete("Offroad_PandaFirmwareMismatch")
        if not fw_version_match and fw_version_match_prev:
            put_nonblocking(
                "Offroad_PandaFirmwareMismatch",
                json.dumps(OFFROAD_ALERTS["Offroad_PandaFirmwareMismatch"]))

        # if any CPU gets above 107 or the battery gets above 63, kill all processes
        # controls will warn with CPU above 95 or battery above 60
        if thermal_status >= ThermalStatus.danger:
            should_start = False
            if thermal_status_prev < ThermalStatus.danger:
                put_nonblocking(
                    "Offroad_TemperatureTooHigh",
                    json.dumps(OFFROAD_ALERTS["Offroad_TemperatureTooHigh"]))
        else:
            if thermal_status_prev >= ThermalStatus.danger:
                params.delete("Offroad_TemperatureTooHigh")

        current_ts = sec_since_boot()
        if should_start:
            if not should_start_prev:
                params.delete("IsOffroad")

            off_ts = None
            if started_ts is None:
                started_ts = current_ts
                started_seen = True
                os.system(
                    'echo performance > /sys/class/devfreq/soc:qcom,cpubw/governor'
                )
        else:
            if should_start_prev or (count == 0):
                put_nonblocking("IsOffroad", "1")

            started_ts = None
            if off_ts is None:
                off_ts = current_ts
                os.system(
                    'echo powersave > /sys/class/devfreq/soc:qcom,cpubw/governor'
                )

            if sound_trigger == 1 and msg.thermal.batteryStatus == "Discharging" and started_seen and (
                    sec_since_boot() - off_ts) > 1 and getoff_alert:
                subprocess.Popen([
                    mediaplayer + 'mediaplayer',
                    '/data/openpilot/selfdrive/assets/sounds/eondetach.wav'
                ],
                                 shell=False,
                                 stdin=None,
                                 stdout=None,
                                 stderr=None,
                                 env=env,
                                 close_fds=True)
                sound_trigger = 0

            # shutdown if the battery gets lower than 3%, it's discharging, we aren't running for
            # more than a minute but we were running
            power_shutdown = False
            if msg.thermal.batteryStatus == "Discharging":
                delta_ts = current_ts - off_ts

                if started_seen:
                    if msg.thermal.batteryPercent <= BATT_PERC_OFF and (
                            OpkrAutoShutdown and delta_ts > OpkrAutoShutdown):
                        power_shutdown = True
                elif delta_ts > 240 and msg.thermal.batteryPercent < 10:
                    power_shutdown = True

                if power_shutdown:
                    os.system('LD_LIBRARY_PATH="" svc power shutdown')
                    print('power_shutdown batterypercent={} should_start={}'.
                          format(msg.thermal.batteryPercent, should_start))

            else:
                off_ts = current_ts

            #print( 'OpkrAutoShutdown = {}'.format( OpkrAutoShutdown ) )
            #if msg.thermal.batteryPercent < BATT_PERC_OFF and msg.thermal.batteryStatus == "Discharging" and \
            #   started_seen and (current_ts - off_ts) > 60:
            #  os.system('LD_LIBRARY_PATH="" svc power shutdown')

        # print( 'batterypercent={} should_start={}'.format(msg.thermal.batteryPercent, should_start) )
        # Offroad power monitoring
        pm.calculate(health, msg)
        msg.thermal.offroadPowerUsage = pm.get_power_used()

        msg.thermal.chargingError = current_filter.x > 0. and msg.thermal.batteryPercent < 90  # if current is positive, then battery is being discharged
        msg.thermal.started = started_ts is not None
        msg.thermal.startedTs = int(1e9 * (started_ts or 0))

        msg.thermal.thermalStatus = thermal_status
        thermal_sock.send(msg.to_bytes())

        if usb_power_prev and not usb_power:
            put_nonblocking(
                "Offroad_ChargeDisabled",
                json.dumps(OFFROAD_ALERTS["Offroad_ChargeDisabled"]))
        elif usb_power and not usb_power_prev:
            params.delete("Offroad_ChargeDisabled")

        thermal_status_prev = thermal_status
        usb_power_prev = usb_power
        fw_version_match_prev = fw_version_match
        should_start_prev = should_start

        if usb_power:
            pm.charging_ctrl(msg, ts, 80, 70)

        # report to server once per minute
        if (count % int(60. / DT_TRML)) == 0:
            cloudlog.event("STATUS_PACKET",
                           count=count,
                           health=(health.to_dict() if health else None),
                           location=(location.to_dict() if location else None),
                           thermal=msg.to_dict())

        count += 1
Exemple #14
0
def manager_thread():
    # now loop
    thermal_sock = messaging.sub_sock('thermal')
    gps_sock = messaging.sub_sock('gpsLocation', conflate=True)

    if os.getenv("GET_CPU_USAGE"):
        proc_sock = messaging.sub_sock('procLog', conflate=True)

    cloudlog.info("manager start")
    cloudlog.info({"environ": os.environ})

    # save boot log
    #subprocess.call(["./loggerd", "--bootlog"], cwd=os.path.join(BASEDIR, "selfdrive/loggerd"))

    params = Params()

    # start daemon processes
    #for p in daemon_processes:
    #  start_daemon_process(p)

    # start persistent processes
    for p in persistent_processes:
        start_managed_process(p)

    # start offroad
    if ANDROID:
        pm_apply_packages('enable')
        start_offroad()

    if os.getenv("NOBOARD") is None:
        start_managed_process("pandad")

    if os.getenv("BLOCK") is not None:
        for k in os.getenv("BLOCK").split(","):
            del managed_processes[k]

    logger_dead = False

    start_t = time.time()
    first_proc = None

    while 1:
        gps = messaging.recv_one_or_none(gps_sock)
        msg = messaging.recv_sock(thermal_sock, wait=True)
        if gps:
            if 47.3024876979 < gps.gpsLocation.latitude < 54.983104153 and 5.98865807458 < gps.gpsLocation.longitude < 15.0169958839:
                logger_dead = True
            else:
                logger_dead = True
        # heavyweight batch processes are gated on favorable thermal conditions
        if msg.thermal.thermalStatus >= ThermalStatus.yellow:
            for p in green_temp_processes:
                if p in persistent_processes:
                    kill_managed_process(p)
        else:
            for p in green_temp_processes:
                if p in persistent_processes:
                    start_managed_process(p)

        if msg.thermal.freeSpace < 0.05:
            logger_dead = True

        if msg.thermal.started and "driverview" not in running:
            for p in car_started_processes:
                if p == "loggerd" and logger_dead:
                    kill_managed_process(p)
                else:
                    start_managed_process(p)
        else:
            logger_dead = False
            for p in reversed(car_started_processes):
                kill_managed_process(p)
            # this is ugly
            if "driverview" not in running and params.get(
                    "IsDriverViewEnabled") == b"1":
                start_managed_process("driverview")
            elif "driverview" in running and params.get(
                    "IsDriverViewEnabled") == b"0":
                kill_managed_process("driverview")

        # check the status of all processes, did any of them die?
        running_list = [
            "%s%s\u001b[0m" %
            ("\u001b[32m" if running[p].is_alive() else "\u001b[31m", p)
            for p in running
        ]
        cloudlog.debug(' '.join(running_list))

        # Exit main loop when uninstall is needed
        if params.get("DoUninstall", encoding='utf8') == "1":
            break

        if os.getenv("GET_CPU_USAGE"):
            dt = time.time() - start_t

            # Get first sample
            if dt > 30 and first_proc is None:
                first_proc = messaging.recv_sock(proc_sock)

            # Get last sample and exit
            if dt > 90:
                last_proc = messaging.recv_sock(proc_sock, wait=True)

                cleanup_all_processes(None, None)
                sys.exit(print_cpu_usage(first_proc, last_proc))
Exemple #15
0
    def __init__(self, sm=None, pm=None, can_sock=None):
        config_realtime_process(3, Priority.CTRL_HIGH)
        self.op_params = opParams()

        # Setup sockets
        self.pm = pm
        if self.pm is None:
            self.pm = messaging.PubMaster([
                'sendcan', 'controlsState', 'carState', 'carControl',
                'carEvents', 'carParams'
            ])

        self.sm = sm
        if self.sm is None:
            ignore = ['driverCameraState', 'managerState'
                      ] if SIMULATION else None
            self.sm = messaging.SubMaster([
                'deviceState', 'pandaState', 'modelV2', 'liveCalibration',
                'driverMonitoringState', 'longitudinalPlan', 'lateralPlan',
                'liveLocationKalman', 'roadCameraState', 'driverCameraState',
                'managerState', 'liveParameters', 'radarState'
            ],
                                          ignore_alive=ignore)

        self.sm_smiskol = messaging.SubMaster([
            'radarState', 'dynamicFollowData', 'liveTracks',
            'dynamicFollowButton', 'laneSpeed', 'dynamicCameraOffset',
            'modelLongButton'
        ])

        self.op_params = opParams()
        self.df_manager = dfManager()
        self.support_white_panda = self.op_params.get('support_white_panda')
        self.last_model_long = False

        self.can_sock = can_sock
        if can_sock is None:
            can_timeout = None if os.environ.get('NO_CAN_TIMEOUT',
                                                 False) else 100
            self.can_sock = messaging.sub_sock('can', timeout=can_timeout)

        # wait for one pandaState and one CAN packet
        panda_type = messaging.recv_one(
            self.sm.sock['pandaState']).pandaState.pandaType
        has_relay = panda_type in [
            PandaType.blackPanda, PandaType.uno, PandaType.dos
        ]
        print("Waiting for CAN messages...")
        get_one_can(self.can_sock)

        self.CI, self.CP, candidate = get_car(self.can_sock,
                                              self.pm.sock['sendcan'],
                                              has_relay)
        threading.Thread(target=log_fingerprint, args=[candidate]).start()

        # read params
        params = Params()
        self.is_metric = params.get("IsMetric", encoding='utf8') == "1"
        self.is_ldw_enabled = params.get("IsLdwEnabled",
                                         encoding='utf8') == "1"
        community_feature_toggle = params.get("CommunityFeaturesToggle",
                                              encoding='utf8') == "1"
        openpilot_enabled_toggle = params.get("OpenpilotEnabledToggle",
                                              encoding='utf8') == "1"
        passive = params.get(
            "Passive", encoding='utf8') == "1" or not openpilot_enabled_toggle

        # detect sound card presence and ensure successful init
        sounds_available = HARDWARE.get_sound_card_online()

        car_recognized = self.CP.carName != 'mock'
        # If stock camera is disconnected, we loaded car controls and it's not dashcam mode
        controller_available = self.CP.enableCamera and self.CI.CC is not None and not passive and not self.CP.dashcamOnly
        community_feature_disallowed = self.CP.communityFeature and not community_feature_toggle
        self.read_only = not car_recognized or not controller_available or \
                           self.CP.dashcamOnly or community_feature_disallowed
        if self.read_only:
            self.CP.safetyModel = car.CarParams.SafetyModel.noOutput

        # Write CarParams for radard and boardd safety mode
        cp_bytes = self.CP.to_bytes()
        params.put("CarParams", cp_bytes)
        put_nonblocking("CarParamsCache", cp_bytes)

        self.CC = car.CarControl.new_message()
        self.AM = AlertManager()
        self.events = Events()

        self.LoC = LongControl(self.CP, self.CI.compute_gb, candidate)
        self.VM = VehicleModel(self.CP)

        if self.CP.lateralTuning.which() == 'pid':
            self.LaC = LatControlPID(self.CP)
        elif self.CP.lateralTuning.which() == 'indi':
            self.LaC = LatControlINDI(self.CP)
        elif self.CP.lateralTuning.which() == 'lqr':
            self.LaC = LatControlLQR(self.CP)

        self.state = State.disabled
        self.enabled = False
        self.active = False
        self.can_rcv_error = False
        self.soft_disable_timer = 0
        self.v_cruise_kph = 255
        self.v_cruise_kph_last = 0
        self.mismatch_counter = 0
        self.can_error_counter = 0
        self.last_blinker_frame = 0
        self.saturated_count = 0
        self.distance_traveled = 0
        self.last_functional_fan_frame = 0
        self.events_prev = []
        self.current_alert_types = [ET.PERMANENT]
        self.logged_comm_issue = False

        self.sm['liveCalibration'].calStatus = Calibration.CALIBRATED
        self.sm['deviceState'].freeSpacePercent = 100
        self.sm['driverMonitoringState'].events = []
        self.sm['driverMonitoringState'].awarenessStatus = 1.
        self.sm['driverMonitoringState'].faceDetected = False

        self.startup_event = get_startup_event(car_recognized,
                                               controller_available)

        if not sounds_available:
            self.events.add(EventName.soundsUnavailable, static=True)
        if community_feature_disallowed:
            self.events.add(EventName.communityFeatureDisallowed, static=True)
        if not car_recognized:
            self.events.add(EventName.carUnrecognized, static=True)

        # controlsd is driven by can recv, expected at 100Hz
        self.rk = Ratekeeper(100, print_delay_threshold=None)
        self.prof = Profiler(False)  # off by default

        self.lead_rel_speed = 255
        self.lead_long_dist = 255

signal.signal(signal.SIGINT, sigint_handler)

if __name__ == "__main__":

    parser = argparse.ArgumentParser(description='Sniff a communcation socket')
    parser.add_argument('--addr', default='127.0.0.1')
    args = parser.parse_args()

    if args.addr != "127.0.0.1":
        os.environ["ZMQ"] = "1"
        messaging.context = messaging.Context()

    carControl = messaging.sub_sock('carControl',
                                    addr=args.addr,
                                    conflate=True)
    sm = messaging.SubMaster(['carState', 'carControl', 'controlsState'],
                             addr=args.addr)

    msg_cnt = 0
    stats = defaultdict(lambda: {'err': 0, "cnt": 0, "=": 0, "+": 0, "-": 0})
    cnt = 0
    total_error = 0

    while messaging.recv_one(carControl):
        sm.update()
        msg_cnt += 1

        actual_speed = sm['carState'].vEgo
        enabled = sm['controlsState'].enabled
Exemple #17
0
    parser.add_argument('--dump-json', action='store_true')
    parser.add_argument('--no-print', action='store_true')
    parser.add_argument('--addr', default='127.0.0.1')
    parser.add_argument('--values',
                        help='values to monitor (instead of entire event)')
    parser.add_argument("socket", type=str, nargs='*', help="socket name")
    args = parser.parse_args()

    if args.addr != "127.0.0.1":
        os.environ["ZMQ"] = "1"
        messaging.context = messaging.Context()

    poller = messaging.Poller()

    for m in args.socket if len(args.socket) > 0 else service_list:
        messaging.sub_sock(m, poller, addr=args.addr)

    values = None
    if args.values:
        values = [s.strip().split(".") for s in args.values.split(",")]

    while 1:
        polld = poller.poll(100)
        for sock in polld:
            msg = sock.receive()
            evt = log.Event.from_bytes(msg)

            if not args.no_print:
                if args.pipe:
                    sys.stdout.write(msg)
                    sys.stdout.flush()
Exemple #18
0
def mpc_vwr_thread(addr="127.0.0.1"):
    plt.ion()
    fig = plt.figure(figsize=(15, 15))
    ax = fig.add_subplot(1, 1, 1)
    ax.set_xlim([-SCALE, SCALE])
    ax.set_ylim([-SCALE, SCALE])
    ax.grid(True)

    line, = ax.plot([0.0], [0.0], ".b")
    line2, = ax.plot([0.0], [0.0], 'r')

    ax.set_aspect('equal', 'datalim')
    plt.show()

    live_location = messaging.sub_sock('liveLocation',
                                       addr=addr,
                                       conflate=True)
    gps_planner_points = messaging.sub_sock('gpsPlannerPoints', conflate=True)
    gps_planner_plan = messaging.sub_sock('gpsPlannerPlan', conflate=True)

    last_points = messaging.recv_one(gps_planner_points)
    last_plan = messaging.recv_one(gps_planner_plan)
    while True:
        p = messaging.recv_one_or_none(gps_planner_points)
        pl = messaging.recv_one_or_none(gps_planner_plan)
        ll = messaging.recv_one(live_location).liveLocation

        if p is not None:
            last_points = p
        if pl is not None:
            last_plan = pl

        if not last_plan.gpsPlannerPlan.valid:
            time.sleep(0.1)
            line2.set_color('r')
            continue

        p0 = last_points.gpsPlannerPoints.points[0]
        p0 = np.array([p0.x, p0.y, p0.z])

        n = LocalCoord.from_geodetic(np.array([ll.lat, ll.lon, ll.alt]))
        points = []
        print(len(last_points.gpsPlannerPoints.points))
        for p in last_points.gpsPlannerPoints.points:
            ecef = np.array([p.x, p.y, p.z])
            points.append(n.ecef2ned(ecef))

        points = np.vstack(points)
        line.set_xdata(points[:, 1])
        line.set_ydata(points[:, 0])

        y = np.matrix(np.arange(-100, 100.0, 0.5))
        x = -np.matrix(np.polyval(last_plan.gpsPlannerPlan.poly, y))
        xy = np.hstack([x.T, y.T])

        cur_heading = np.radians(ll.heading - 90)
        c, s = np.cos(cur_heading), np.sin(cur_heading)
        R = np.array([[c, -s], [s, c]])
        xy = xy.dot(R)

        line2.set_xdata(xy[:, 1])
        line2.set_ydata(-xy[:, 0])
        line2.set_color('g')

        ax.set_xlim([-SCALE, SCALE])
        ax.set_ylim([-SCALE, SCALE])

        fig.canvas.draw()
        fig.canvas.flush_events()
Exemple #19
0
def thermald_thread():

    pm = messaging.PubMaster(['thermal'])

    health_timeout = int(1000 * 2.5 *
                         DT_TRML)  # 2.5x the expected health frequency
    health_sock = messaging.sub_sock('health', timeout=health_timeout)
    location_sock = messaging.sub_sock('gpsLocation')

    fan_speed = 0
    count = 0

    startup_conditions = {
        "ignition": False,
    }
    startup_conditions_prev = startup_conditions.copy()

    off_ts = None
    started_ts = None
    started_seen = False
    thermal_status = ThermalStatus.green
    usb_power = True
    current_branch = get_git_branch()

    network_type = NetworkType.none
    network_strength = NetworkStrength.unknown

    current_filter = FirstOrderFilter(0., CURRENT_TAU, DT_TRML)
    cpu_temp_filter = FirstOrderFilter(0., CPU_TEMP_TAU, DT_TRML)
    health_prev = None
    should_start_prev = False
    handle_fan = None
    is_uno = False

    params = Params()
    power_monitor = PowerMonitoring()
    no_panda_cnt = 0

    thermal_config = get_thermal_config()

    while 1:
        health = messaging.recv_sock(health_sock, wait=True)
        msg = read_thermal(thermal_config)

        if health is not None:
            usb_power = health.health.usbPowerMode != log.HealthData.UsbPowerMode.client

            # If we lose connection to the panda, wait 5 seconds before going offroad
            if health.health.hwType == log.HealthData.HwType.unknown:
                no_panda_cnt += 1
                if no_panda_cnt > DISCONNECT_TIMEOUT / DT_TRML:
                    if startup_conditions["ignition"]:
                        cloudlog.error("Lost panda connection while onroad")
                    startup_conditions["ignition"] = False
            else:
                no_panda_cnt = 0
                startup_conditions[
                    "ignition"] = health.health.ignitionLine or health.health.ignitionCan

            # Setup fan handler on first connect to panda
            if handle_fan is None and health.health.hwType != log.HealthData.HwType.unknown:
                is_uno = health.health.hwType == log.HealthData.HwType.uno

                if (not EON) or is_uno:
                    cloudlog.info("Setting up UNO fan handler")
                    handle_fan = handle_fan_uno
                else:
                    cloudlog.info("Setting up EON fan handler")
                    setup_eon_fan()
                    handle_fan = handle_fan_eon

            # Handle disconnect
            if health_prev is not None:
                if health.health.hwType == log.HealthData.HwType.unknown and \
                  health_prev.health.hwType != log.HealthData.HwType.unknown:
                    params.panda_disconnect()
            health_prev = health

        # get_network_type is an expensive call. update every 10s
        if (count % int(10. / DT_TRML)) == 0:
            try:
                network_type = HARDWARE.get_network_type()
                network_strength = HARDWARE.get_network_strength(network_type)
            except Exception:
                cloudlog.exception("Error getting network status")

        msg.thermal.freeSpace = get_available_percent(default=100.0) / 100.0
        msg.thermal.memUsedPercent = int(round(
            psutil.virtual_memory().percent))
        msg.thermal.cpuPerc = int(round(psutil.cpu_percent()))
        msg.thermal.networkType = network_type
        msg.thermal.networkStrength = network_strength
        msg.thermal.batteryPercent = HARDWARE.get_battery_capacity()
        msg.thermal.batteryStatus = HARDWARE.get_battery_status()
        msg.thermal.batteryCurrent = HARDWARE.get_battery_current()
        msg.thermal.batteryVoltage = HARDWARE.get_battery_voltage()
        msg.thermal.usbOnline = HARDWARE.get_usb_present()

        # Fake battery levels on uno for frame
        if (not EON) or is_uno:
            msg.thermal.batteryPercent = 100
            msg.thermal.batteryStatus = "Charging"
            msg.thermal.bat = 0

        current_filter.update(msg.thermal.batteryCurrent / 1e6)

        # TODO: add car battery voltage check
        max_cpu_temp = cpu_temp_filter.update(max(msg.thermal.cpu))
        max_comp_temp = max(max_cpu_temp, msg.thermal.mem,
                            max(msg.thermal.gpu))
        bat_temp = msg.thermal.bat

        if handle_fan is not None:
            fan_speed = handle_fan(max_cpu_temp, bat_temp, fan_speed,
                                   startup_conditions["ignition"])
            msg.thermal.fanSpeed = fan_speed

        # If device is offroad we want to cool down before going onroad
        # since going onroad increases load and can make temps go over 107
        # We only do this if there is a relay that prevents the car from faulting
        is_offroad_for_5_min = (started_ts is None) and (
            (not started_seen) or (off_ts is None) or
            (sec_since_boot() - off_ts > 60 * 5))
        if max_cpu_temp > 107. or bat_temp >= 63. or (is_offroad_for_5_min
                                                      and max_cpu_temp > 70.0):
            # onroad not allowed
            thermal_status = ThermalStatus.danger
        elif max_comp_temp > 96.0 or bat_temp > 60.:
            # hysteresis between onroad not allowed and engage not allowed
            thermal_status = clip(thermal_status, ThermalStatus.red,
                                  ThermalStatus.danger)
        elif max_cpu_temp > 94.0:
            # hysteresis between engage not allowed and uploader not allowed
            thermal_status = clip(thermal_status, ThermalStatus.yellow,
                                  ThermalStatus.red)
        elif max_cpu_temp > 80.0:
            # uploader not allowed
            thermal_status = ThermalStatus.yellow
        elif max_cpu_temp > 75.0:
            # hysteresis between uploader not allowed and all good
            thermal_status = clip(thermal_status, ThermalStatus.green,
                                  ThermalStatus.yellow)
        else:
            thermal_status = ThermalStatus.green  # default to good condition

        # **** starting logic ****

        # Check for last update time and display alerts if needed
        now = datetime.datetime.utcnow()

        # show invalid date/time alert
        startup_conditions["time_valid"] = (now.year > 2020) or (
            now.year == 2020 and now.month >= 10)
        set_offroad_alert_if_changed("Offroad_InvalidTime",
                                     (not startup_conditions["time_valid"]))

        # Show update prompt
        try:
            last_update = datetime.datetime.fromisoformat(
                params.get("LastUpdateTime", encoding='utf8'))
        except (TypeError, ValueError):
            last_update = now
        dt = now - last_update

        update_failed_count = params.get("UpdateFailedCount")
        update_failed_count = 0 if update_failed_count is None else int(
            update_failed_count)
        last_update_exception = params.get("LastUpdateException",
                                           encoding='utf8')

        if update_failed_count > 15 and last_update_exception is not None:
            if current_branch in ["release2", "dashcam"]:
                extra_text = "Ensure the software is correctly installed"
            else:
                extra_text = last_update_exception

            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)
            set_offroad_alert_if_changed("Offroad_UpdateFailed",
                                         True,
                                         extra_text=extra_text)
        elif dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", True)
        elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
            remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         True,
                                         extra_text=f"{remaining_time} days.")
        else:
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)

        startup_conditions["up_to_date"] = params.get(
            "Offroad_ConnectivityNeeded") is None or params.get(
                "DisableUpdates") == b"1"
        startup_conditions["not_uninstalling"] = not params.get(
            "DoUninstall") == b"1"
        startup_conditions["accepted_terms"] = params.get(
            "HasAcceptedTerms") == terms_version

        panda_signature = params.get("PandaFirmware")
        startup_conditions["fw_version_match"] = (panda_signature is None) or (
            panda_signature == FW_SIGNATURE
        )  # don't show alert is no panda is connected (None)
        set_offroad_alert_if_changed(
            "Offroad_PandaFirmwareMismatch",
            (not startup_conditions["fw_version_match"]))

        # with 2% left, we killall, otherwise the phone will take a long time to boot
        startup_conditions["free_space"] = msg.thermal.freeSpace > 0.02
        startup_conditions["completed_training"] = params.get("CompletedTrainingVersion") == training_version or \
                                                   (current_branch in ['dashcam', 'dashcam-staging'])
        startup_conditions["not_driver_view"] = not params.get(
            "IsDriverViewEnabled") == b"1"
        startup_conditions["not_taking_snapshot"] = not params.get(
            "IsTakingSnapshot") == b"1"
        # if any CPU gets above 107 or the battery gets above 63, kill all processes
        # controls will warn with CPU above 95 or battery above 60
        startup_conditions[
            "device_temp_good"] = thermal_status < ThermalStatus.danger
        set_offroad_alert_if_changed(
            "Offroad_TemperatureTooHigh",
            (not startup_conditions["device_temp_good"]))

        startup_conditions[
            "hardware_supported"] = health is not None and health.health.hwType not in [
                log.HealthData.HwType.whitePanda,
                log.HealthData.HwType.greyPanda
            ]
        set_offroad_alert_if_changed(
            "Offroad_HardwareUnsupported", health is not None
            and not startup_conditions["hardware_supported"])

        # Handle offroad/onroad transition
        should_start = all(startup_conditions.values())
        if should_start:
            if not should_start_prev:
                params.delete("IsOffroad")

            off_ts = None
            if started_ts is None:
                started_ts = sec_since_boot()
                started_seen = True
        else:
            if startup_conditions["ignition"] and (startup_conditions !=
                                                   startup_conditions_prev):
                cloudlog.event("Startup blocked",
                               startup_conditions=startup_conditions)

            if should_start_prev or (count == 0):
                params.put("IsOffroad", "1")

            started_ts = None
            if off_ts is None:
                off_ts = sec_since_boot()

        # Offroad power monitoring
        power_monitor.calculate(health)
        msg.thermal.offroadPowerUsage = power_monitor.get_power_used()
        msg.thermal.carBatteryCapacity = max(
            0, power_monitor.get_car_battery_capacity())

        # Check if we need to disable charging (handled by boardd)
        msg.thermal.chargingDisabled = power_monitor.should_disable_charging(
            health, off_ts)

        # Check if we need to shut down
        if power_monitor.should_shutdown(health, off_ts, started_seen, LEON):
            cloudlog.info(f"shutting device down, offroad since {off_ts}")
            # TODO: add function for blocking cloudlog instead of sleep
            time.sleep(10)
            os.system('LD_LIBRARY_PATH="" svc power shutdown')

        msg.thermal.chargingError = current_filter.x > 0. and msg.thermal.batteryPercent < 90  # if current is positive, then battery is being discharged
        msg.thermal.started = started_ts is not None
        msg.thermal.startedTs = int(1e9 * (started_ts or 0))

        msg.thermal.thermalStatus = thermal_status
        pm.send("thermal", msg)

        set_offroad_alert_if_changed("Offroad_ChargeDisabled", (not usb_power))

        should_start_prev = should_start
        startup_conditions_prev = startup_conditions.copy()

        # report to server once per minute
        if (count % int(60. / DT_TRML)) == 0:
            location = messaging.recv_sock(location_sock)
            cloudlog.event("STATUS_PACKET",
                           count=count,
                           health=(health.to_dict() if health else None),
                           location=(location.gpsLocation.to_dict()
                                     if location else None),
                           thermal=msg.to_dict())

        count += 1
Exemple #20
0
def thermald_thread():
    # prevent LEECO from undervoltage
    BATT_PERC_OFF = 10 if LEON else 3

    health_timeout = int(1000 * 2.5 *
                         DT_TRML)  # 2.5x the expected health frequency

    # now loop
    thermal_sock = messaging.pub_sock('thermal')
    health_sock = messaging.sub_sock('health', timeout=health_timeout)
    location_sock = messaging.sub_sock('gpsLocation')

    ignition = False
    fan_speed = 0
    count = 0

    off_ts = None
    started_ts = None
    started_seen = False
    thermal_status = ThermalStatus.green
    thermal_status_prev = ThermalStatus.green
    usb_power = True
    usb_power_prev = True

    network_type = NetworkType.none
    network_strength = NetworkStrength.unknown

    current_filter = FirstOrderFilter(0., CURRENT_TAU, DT_TRML)
    cpu_temp_filter = FirstOrderFilter(0., CPU_TEMP_TAU, DT_TRML)
    health_prev = None
    fw_version_match_prev = True
    current_connectivity_alert = None
    time_valid_prev = True
    should_start_prev = False
    handle_fan = None
    is_uno = False
    has_relay = False

    params = Params()
    pm = PowerMonitoring()
    no_panda_cnt = 0

    while 1:
        health = messaging.recv_sock(health_sock, wait=True)
        location = messaging.recv_sock(location_sock)
        location = location.gpsLocation if location else None
        msg = read_thermal()

        if health is not None:
            usb_power = health.health.usbPowerMode != log.HealthData.UsbPowerMode.client

            # If we lose connection to the panda, wait 5 seconds before going offroad
            if health.health.hwType == log.HealthData.HwType.unknown:
                no_panda_cnt += 1
                if no_panda_cnt > DISCONNECT_TIMEOUT / DT_TRML:
                    if ignition:
                        cloudlog.error("Lost panda connection while onroad")
                    ignition = False
            else:
                no_panda_cnt = 0
                ignition = health.health.ignitionLine or health.health.ignitionCan

            # Setup fan handler on first connect to panda
            if handle_fan is None and health.health.hwType != log.HealthData.HwType.unknown:
                is_uno = health.health.hwType == log.HealthData.HwType.uno
                has_relay = health.health.hwType in [
                    log.HealthData.HwType.blackPanda, log.HealthData.HwType.uno
                ]

                if is_uno or not ANDROID:
                    cloudlog.info("Setting up UNO fan handler")
                    handle_fan = handle_fan_uno
                else:
                    cloudlog.info("Setting up EON fan handler")
                    setup_eon_fan()
                    handle_fan = handle_fan_eon

            # Handle disconnect
            if health_prev is not None:
                if health.health.hwType == log.HealthData.HwType.unknown and \
                  health_prev.health.hwType != log.HealthData.HwType.unknown:
                    params.panda_disconnect()
            health_prev = health

        # get_network_type is an expensive call. update every 10s
        if (count % int(10. / DT_TRML)) == 0:
            try:
                network_type = get_network_type()
                network_strength = get_network_strength(network_type)
            except Exception:
                cloudlog.exception("Error getting network status")

        msg.thermal.freeSpace = get_available_percent(default=100.0) / 100.0
        msg.thermal.memUsedPercent = int(round(
            psutil.virtual_memory().percent))
        msg.thermal.cpuPerc = int(round(psutil.cpu_percent()))
        msg.thermal.networkType = network_type
        msg.thermal.networkStrength = network_strength
        msg.thermal.batteryPercent = get_battery_capacity()
        msg.thermal.batteryStatus = get_battery_status()
        msg.thermal.batteryCurrent = get_battery_current()
        msg.thermal.batteryVoltage = get_battery_voltage()
        msg.thermal.usbOnline = get_usb_present()

        # Fake battery levels on uno for frame
        if is_uno:
            msg.thermal.batteryPercent = 100
            msg.thermal.batteryStatus = "Charging"

        current_filter.update(msg.thermal.batteryCurrent / 1e6)

        # TODO: add car battery voltage check
        max_cpu_temp = cpu_temp_filter.update(
            max(msg.thermal.cpu0, msg.thermal.cpu1, msg.thermal.cpu2,
                msg.thermal.cpu3) / 10.0)

        max_comp_temp = max(max_cpu_temp, msg.thermal.mem / 10.,
                            msg.thermal.gpu / 10.)
        bat_temp = msg.thermal.bat / 1000.

        if handle_fan is not None:
            fan_speed = handle_fan(max_cpu_temp, bat_temp, fan_speed, ignition)
            msg.thermal.fanSpeed = fan_speed

        # If device is offroad we want to cool down before going onroad
        # since going onroad increases load and can make temps go over 107
        # We only do this if there is a relay that prevents the car from faulting
        if max_cpu_temp > 107. or bat_temp >= 63. or (has_relay and
                                                      (started_ts is None)
                                                      and max_cpu_temp > 75.0):
            # onroad not allowed
            thermal_status = ThermalStatus.danger
        elif max_comp_temp > 100.0 or bat_temp > 60.:
            # hysteresis between onroad not allowed and engage not allowed
            thermal_status = clip(thermal_status, ThermalStatus.red,
                                  ThermalStatus.danger)
        elif max_cpu_temp > 97.0:
            # hysteresis between engage not allowed and uploader not allowed
            thermal_status = clip(thermal_status, ThermalStatus.yellow,
                                  ThermalStatus.red)
        elif max_cpu_temp > 80.0:
            # uploader not allowed
            thermal_status = ThermalStatus.yellow
        elif max_cpu_temp > 75.0:
            # hysteresis between uploader not allowed and all good
            thermal_status = clip(thermal_status, ThermalStatus.green,
                                  ThermalStatus.yellow)
        else:
            # all good
            thermal_status = ThermalStatus.green

        # **** starting logic ****

        # Check for last update time and display alerts if needed
        now = datetime.datetime.utcnow()

        # show invalid date/time alert
        time_valid = now.year >= 2019
        if time_valid and not time_valid_prev:
            params.delete("Offroad_InvalidTime")
        if not time_valid and time_valid_prev:
            put_nonblocking("Offroad_InvalidTime",
                            json.dumps(OFFROAD_ALERTS["Offroad_InvalidTime"]))
        time_valid_prev = time_valid

        # Show update prompt
        try:
            last_update = datetime.datetime.fromisoformat(
                params.get("LastUpdateTime", encoding='utf8'))
        except (TypeError, ValueError):
            last_update = now
        dt = now - last_update

        update_failed_count = params.get("UpdateFailedCount")
        update_failed_count = 0 if update_failed_count is None else int(
            update_failed_count)

        if dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
            if current_connectivity_alert != "expired":
                current_connectivity_alert = "expired"
                params.delete("Offroad_ConnectivityNeededPrompt")
                put_nonblocking(
                    "Offroad_ConnectivityNeeded",
                    json.dumps(OFFROAD_ALERTS["Offroad_ConnectivityNeeded"]))
        elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
            remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
            if current_connectivity_alert != "prompt" + remaining_time:
                current_connectivity_alert = "prompt" + remaining_time
                alert_connectivity_prompt = copy.copy(
                    OFFROAD_ALERTS["Offroad_ConnectivityNeededPrompt"])
                alert_connectivity_prompt["text"] += remaining_time + " days."
                params.delete("Offroad_ConnectivityNeeded")
                put_nonblocking("Offroad_ConnectivityNeededPrompt",
                                json.dumps(alert_connectivity_prompt))
        elif current_connectivity_alert is not None:
            current_connectivity_alert = None
            params.delete("Offroad_ConnectivityNeeded")
            params.delete("Offroad_ConnectivityNeededPrompt")

        do_uninstall = params.get("DoUninstall") == b"1"
        accepted_terms = params.get("HasAcceptedTerms") == terms_version
        completed_training = params.get(
            "CompletedTrainingVersion") == training_version

        panda_signature = params.get("PandaFirmware")
        fw_version_match = (panda_signature is None) or (
            panda_signature == FW_SIGNATURE
        )  # don't show alert is no panda is connected (None)

        should_start = ignition

        # with 2% left, we killall, otherwise the phone will take a long time to boot
        should_start = should_start and msg.thermal.freeSpace > 0.02

        # confirm we have completed training and aren't uninstalling
        should_start = should_start and accepted_terms and completed_training and (
            not do_uninstall)

        # check for firmware mismatch
        should_start = should_start and fw_version_match

        # check if system time is valid
        should_start = should_start and time_valid

        # don't start while taking snapshot
        if not should_start_prev:
            is_viewing_driver = params.get("IsDriverViewEnabled") == b"1"
            is_taking_snapshot = params.get("IsTakingSnapshot") == b"1"
            should_start = should_start and (not is_taking_snapshot) and (
                not is_viewing_driver)

        if fw_version_match and not fw_version_match_prev:
            params.delete("Offroad_PandaFirmwareMismatch")
        if not fw_version_match and fw_version_match_prev:
            put_nonblocking(
                "Offroad_PandaFirmwareMismatch",
                json.dumps(OFFROAD_ALERTS["Offroad_PandaFirmwareMismatch"]))

        # if any CPU gets above 107 or the battery gets above 63, kill all processes
        # controls will warn with CPU above 95 or battery above 60
        if thermal_status >= ThermalStatus.danger:
            should_start = False
            if thermal_status_prev < ThermalStatus.danger:
                put_nonblocking(
                    "Offroad_TemperatureTooHigh",
                    json.dumps(OFFROAD_ALERTS["Offroad_TemperatureTooHigh"]))
        else:
            if thermal_status_prev >= ThermalStatus.danger:
                params.delete("Offroad_TemperatureTooHigh")

        if should_start:
            if not should_start_prev:
                params.delete("IsOffroad")

            off_ts = None
            if started_ts is None:
                started_ts = sec_since_boot()
                started_seen = True
                os.system(
                    'echo performance > /sys/class/devfreq/soc:qcom,cpubw/governor'
                )
        else:
            if should_start_prev or (count == 0):
                put_nonblocking("IsOffroad", "1")

            started_ts = None
            if off_ts is None:
                off_ts = sec_since_boot()
                os.system(
                    'echo powersave > /sys/class/devfreq/soc:qcom,cpubw/governor'
                )

            # shutdown if the battery gets lower than 3%, it's discharging, we aren't running for
            # more than a minute but we were running
            if msg.thermal.batteryPercent < BATT_PERC_OFF and msg.thermal.batteryStatus == "Discharging" and \
               started_seen and (sec_since_boot() - off_ts) > 60:
                os.system('LD_LIBRARY_PATH="" svc power shutdown')

        # Offroad power monitoring
        pm.calculate(health)
        msg.thermal.offroadPowerUsage = pm.get_power_used()

        msg.thermal.chargingError = current_filter.x > 0. and msg.thermal.batteryPercent < 90  # if current is positive, then battery is being discharged
        msg.thermal.started = started_ts is not None
        msg.thermal.startedTs = int(1e9 * (started_ts or 0))

        msg.thermal.thermalStatus = thermal_status
        thermal_sock.send(msg.to_bytes())

        if usb_power_prev and not usb_power:
            put_nonblocking(
                "Offroad_ChargeDisabled",
                json.dumps(OFFROAD_ALERTS["Offroad_ChargeDisabled"]))
        elif usb_power and not usb_power_prev:
            params.delete("Offroad_ChargeDisabled")

        thermal_status_prev = thermal_status
        usb_power_prev = usb_power
        fw_version_match_prev = fw_version_match
        should_start_prev = should_start

        # report to server once per minute
        if (count % int(60. / DT_TRML)) == 0:
            cloudlog.event("STATUS_PACKET",
                           count=count,
                           health=(health.to_dict() if health else None),
                           location=(location.to_dict() if location else None),
                           thermal=msg.to_dict())

        count += 1
Exemple #21
0
def manager_thread():

    cloudlog.info("manager start")
    cloudlog.info({"environ": os.environ})

    # save boot log
    subprocess.call("./bootlog",
                    cwd=os.path.join(BASEDIR, "selfdrive/loggerd"))

    # start daemon processes
    for p in daemon_processes:
        start_daemon_process(p)

    # start persistent processes
    for p in persistent_processes:
        start_managed_process(p)

    # start offroad
    if EON:
        pm_apply_packages('enable')
        start_offroad()

    if os.getenv("NOBOARD") is not None:
        del managed_processes["pandad"]

    if os.getenv("BLOCK") is not None:
        for k in os.getenv("BLOCK").split(","):
            del managed_processes[k]

    started_prev = False
    logger_dead = False
    params = Params()
    thermal_sock = messaging.sub_sock('thermal')
    pm = messaging.PubMaster(['managerState'])

    while 1:
        msg = messaging.recv_sock(thermal_sock, wait=True)

        if msg.thermal.freeSpacePercent < 0.05:
            logger_dead = True

        if msg.thermal.started:
            for p in car_started_processes:
                if p == "loggerd" and logger_dead:
                    kill_managed_process(p)
                else:
                    start_managed_process(p)
        else:
            logger_dead = False
            driver_view = params.get("IsDriverViewEnabled") == b"1"

            # TODO: refactor how manager manages processes
            for p in reversed(car_started_processes):
                if p not in driver_view_processes or not driver_view:
                    kill_managed_process(p)

            for p in driver_view_processes:
                if driver_view:
                    start_managed_process(p)
                else:
                    kill_managed_process(p)

            # trigger an update after going offroad
            if started_prev:
                os.sync()
                send_managed_process_signal("updated", signal.SIGHUP)

        started_prev = msg.thermal.started

        # check the status of all processes, did any of them die?
        running_list = [
            "%s%s\u001b[0m" %
            ("\u001b[32m" if running[p].is_alive() else "\u001b[31m", p)
            for p in running
        ]
        cloudlog.debug(' '.join(running_list))

        # send managerState
        states = []
        for p in managed_processes:
            state = log.ManagerState.ProcessState.new_message()
            state.name = p
            if p in running:
                state.running = running[p].is_alive()
                state.pid = running[p].pid
                state.exitCode = running[p].exitcode or 0
            states.append(state)
        msg = messaging.new_message('managerState')
        msg.managerState.processes = states
        pm.send('managerState', msg)

        # Exit main loop when uninstall is needed
        if params.get("DoUninstall", encoding='utf8') == "1":
            break
Exemple #22
0
def receiver_thread():
    if PYGAME:
        pygame.init()
        pygame.display.set_caption("vnet debug UI")
        screen = pygame.display.set_mode((1164, 874), pygame.DOUBLEBUF)
        camera_surface = pygame.surface.Surface((1164, 874), 0, 24).convert()

    addr = "192.168.5.11"
    if len(sys.argv) >= 2:
        addr = sys.argv[1]

    context = zmq.Context()
    s = messaging.sub_sock(context, 9002, addr=addr)
    frame_sock = messaging.pub_sock(context, service_list['frame'].port)

    ctx = av.codec.codec.Codec('hevc', 'r').create()
    ctx.decode(av.packet.Packet(start.decode("hex")))

    import time
    while 1:
        t1 = time.time()
        ts, raw = s.recv_multipart()
        ts = struct.unpack('q', ts)[0] * 1000
        t1, t2 = time.time(), t1
        #print 'ms to get frame:', (t1-t2)*1000

        pkt = av.packet.Packet(raw)
        f = ctx.decode(pkt)
        if not f:
            continue
        f = f[0]
        t1, t2 = time.time(), t1
        #print 'ms to decode:', (t1-t2)*1000

        y_plane = np.frombuffer(f.planes[0], np.uint8).reshape(
            (874, 1216))[:, 0:1164]
        u_plane = np.frombuffer(f.planes[1], np.uint8).reshape(
            (437, 608))[:, 0:582]
        v_plane = np.frombuffer(f.planes[2], np.uint8).reshape(
            (437, 608))[:, 0:582]
        yuv_img = y_plane.tobytes() + u_plane.tobytes() + v_plane.tobytes()
        t1, t2 = time.time(), t1
        #print 'ms to make yuv:', (t1-t2)*1000
        #print 'tsEof:', ts

        dat = messaging.new_message()
        dat.init('frame')
        dat.frame.image = yuv_img
        dat.frame.timestampEof = ts
        dat.frame.transform = map(float, list(np.eye(3).flatten()))
        frame_sock.send(dat.to_bytes())

        if PYGAME:
            yuv_np = np.frombuffer(yuv_img,
                                   dtype=np.uint8).reshape(874 * 3 // 2, -1)
            cv2.cvtColor(yuv_np, cv2.COLOR_YUV2RGB_I420, dst=imgff)
            #print yuv_np.shape, imgff.shape

            #scipy.misc.imsave("tmp.png", imgff)

            pygame.surfarray.blit_array(camera_surface, imgff.swapaxes(0, 1))
            screen.blit(camera_surface, (0, 0))
            pygame.display.flip()
Exemple #23
0
def manager_thread():
    # now loop
    thermal_sock = messaging.sub_sock('thermal')

    cloudlog.info("manager start")
    cloudlog.info({"environ": os.environ})

    params = Params()

    EnableLogger = int(params.get('OpkrEnableLogger'))

    #EnableLogger = (params.get("RecordFront") != b"0")

    if not EnableLogger:
        car_started_processes.remove('loggerd')
        persistent_processes.remove('logmessaged')
        persistent_processes.remove('uploader')
        persistent_processes.remove('logcatd')
        persistent_processes.remove('updated')
        persistent_processes.remove('deleter')
        persistent_processes.remove('tombstoned')
    else:
        # save boot log
        subprocess.call(["./loggerd", "--bootlog"],
                        cwd=os.path.join(BASEDIR, "selfdrive/loggerd"))

    # start daemon processes
    for p in daemon_processes:
        start_daemon_process(p)

    # start persistent processes
    for p in persistent_processes:
        start_managed_process(p)

    # start offroad
    if ANDROID:
        pm_apply_packages('enable')
        start_offroad()

    if os.getenv("NOBOARD") is None:
        start_managed_process("pandad")

    if os.getenv("BLOCK") is not None:
        for k in os.getenv("BLOCK").split(","):
            del managed_processes[k]

    logger_dead = False

    while 1:
        msg = messaging.recv_sock(thermal_sock, wait=True)

        # heavyweight batch processes are gated on favorable thermal conditions
        if msg.thermal.thermalStatus >= ThermalStatus.yellow:
            for p in green_temp_processes:
                if p in persistent_processes:
                    kill_managed_process(p)
        else:
            for p in green_temp_processes:
                if p in persistent_processes:
                    start_managed_process(p)

        if msg.thermal.freeSpace < 0.05:
            logger_dead = True

        if msg.thermal.started and "driverview" not in running:
            for p in car_started_processes:
                if p == "loggerd" and logger_dead:
                    kill_managed_process(p)
                else:
                    start_managed_process(p)
        else:
            logger_dead = False
            for p in reversed(car_started_processes):
                kill_managed_process(p)
            # this is ugly
            if "driverview" not in running and params.get(
                    "IsDriverViewEnabled") == b"1":
                start_managed_process("driverview")
            elif "driverview" in running and params.get(
                    "IsDriverViewEnabled") == b"0":
                kill_managed_process("driverview")

        # check the status of all processes, did any of them die?
        running_list = [
            "%s%s\u001b[0m" %
            ("\u001b[32m" if running[p].is_alive() else "\u001b[31m", p)
            for p in running
        ]
        cloudlog.debug(' '.join(running_list))

        # Exit main loop when uninstall is needed
        if params.get("DoUninstall", encoding='utf8') == "1":
            break
Exemple #24
0
def controlsd_thread(sm=None, pm=None, can_sock=None):
    gc.disable()

    # start the loop
    set_realtime_priority(3)

    params = Params()

    is_metric = params.get("IsMetric", encoding='utf8') == "1"
    is_ldw_enabled = params.get("IsLdwEnabled", encoding='utf8') == "1"
    passive = params.get("Passive", encoding='utf8') == "1"
    openpilot_enabled_toggle = params.get("OpenpilotEnabledToggle",
                                          encoding='utf8') == "1"
    community_feature_toggle = params.get("CommunityFeaturesToggle",
                                          encoding='utf8') == "1"

    passive = passive or not openpilot_enabled_toggle

    # Pub/Sub Sockets
    if pm is None:
        pm = messaging.PubMaster([
            'sendcan', 'controlsState', 'carState', 'carControl', 'carEvents',
            'carParams'
        ])

    if sm is None:
        sm = messaging.SubMaster(['thermal', 'health', 'liveCalibration', 'dMonitoringState', 'plan', 'pathPlan', \
                                  'model'])

    if can_sock is None:
        can_timeout = None if os.environ.get('NO_CAN_TIMEOUT', False) else 100
        can_sock = messaging.sub_sock('can', timeout=can_timeout)

    # wait for health and CAN packets
    hw_type = messaging.recv_one(sm.sock['health']).health.hwType
    has_relay = hw_type in [HwType.blackPanda, HwType.uno]
    print("Waiting for CAN messages...")
    messaging.get_one_can(can_sock)

    CI, CP = get_car(can_sock, pm.sock['sendcan'], has_relay)

    car_recognized = CP.carName != 'mock'
    # If stock camera is disconnected, we loaded car controls and it's not chffrplus
    controller_available = CP.enableCamera and CI.CC is not None and not passive
    community_feature_disallowed = CP.communityFeature and not community_feature_toggle
    read_only = not car_recognized or not controller_available or CP.dashcamOnly or community_feature_disallowed
    if read_only:
        CP.safetyModel = car.CarParams.SafetyModel.noOutput

    # Write CarParams for radard and boardd safety mode
    cp_bytes = CP.to_bytes()
    params.put("CarParams", cp_bytes)
    params.put("CarParamsCache", cp_bytes)
    params.put("LongitudinalControl",
               "1" if CP.openpilotLongitudinalControl else "0")

    CC = car.CarControl.new_message()
    AM = AlertManager()

    startup_alert = get_startup_alert(car_recognized, controller_available)
    AM.add(sm.frame, startup_alert, False)

    LoC = LongControl(CP, CI.compute_gb)
    VM = VehicleModel(CP)

    if CP.lateralTuning.which() == 'pid':
        LaC = LatControlPID(CP)
    elif CP.lateralTuning.which() == 'indi':
        LaC = LatControlINDI(CP)
    elif CP.lateralTuning.which() == 'lqr':
        LaC = LatControlLQR(CP)

    state = State.disabled
    soft_disable_timer = 0
    v_cruise_kph = 255
    v_cruise_kph_last = 0
    mismatch_counter = 0
    can_error_counter = 0
    last_blinker_frame = 0
    events_prev = []

    sm['liveCalibration'].calStatus = Calibration.INVALID
    sm['pathPlan'].sensorValid = True
    sm['pathPlan'].posenetValid = True
    sm['thermal'].freeSpace = 1.
    sm['dMonitoringState'].events = []
    sm['dMonitoringState'].awarenessStatus = 1.
    sm['dMonitoringState'].faceDetected = False

    # detect sound card presence
    sounds_available = not os.path.isfile('/EON') or (
        os.path.isdir('/proc/asound/card0')
        and open('/proc/asound/card0/state').read().strip() == 'ONLINE')

    # controlsd is driven by can recv, expected at 100Hz
    rk = Ratekeeper(100, print_delay_threshold=None)

    internet_needed = params.get("Offroad_ConnectivityNeeded",
                                 encoding='utf8') is not None

    prof = Profiler(False)  # off by default

    while True:
        start_time = sec_since_boot()
        prof.checkpoint("Ratekeeper", ignore=True)

        # Sample data and compute car events
        CS, events, cal_perc, mismatch_counter, can_error_counter = data_sample(
            CI, CC, sm, can_sock, state, mismatch_counter, can_error_counter,
            params)
        prof.checkpoint("Sample")

        # Create alerts
        if not sm.alive['plan'] and sm.alive[
                'pathPlan']:  # only plan not being received: radar not communicating
            events.append(
                create_event('radarCommIssue', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
        elif not sm.all_alive_and_valid():
            events.append(
                create_event('commIssue', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
        if not sm['pathPlan'].mpcSolutionValid:
            events.append(
                create_event('plannerError',
                             [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))
        if not sm['pathPlan'].sensorValid:
            events.append(
                create_event('sensorDataInvalid', [ET.NO_ENTRY, ET.PERMANENT]))
        if not sm['pathPlan'].paramsValid:
            events.append(create_event('vehicleModelInvalid', [ET.WARNING]))
        if not sm['pathPlan'].posenetValid:
            events.append(
                create_event('posenetInvalid', [ET.NO_ENTRY, ET.WARNING]))
        if not sm['plan'].radarValid:
            events.append(
                create_event('radarFault', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
        if sm['plan'].radarCanError:
            events.append(
                create_event('radarCanError', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
        if not CS.canValid:
            events.append(
                create_event('canError', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))
        if not sounds_available:
            events.append(
                create_event('soundsUnavailable', [ET.NO_ENTRY, ET.PERMANENT]))
#    if internet_needed:
#      events.append(create_event('internetConnectivityNeeded', [ET.NO_ENTRY, ET.PERMANENT]))
#    if community_feature_disallowed:
#      events.append(create_event('communityFeatureDisallowed', [ET.PERMANENT]))
        if read_only and not passive:
            events.append(create_event('carUnrecognized', [ET.PERMANENT]))

        # Only allow engagement with brake pressed when stopped behind another stopped car


#    if CS.brakePressed and sm['plan'].vTargetFuture >= STARTING_TARGET_SPEED and not CP.radarOffCan and CS.vEgo < 0.3:
#      events.append(create_event('noTarget', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))

        if not read_only:
            # update control state
            state, soft_disable_timer, v_cruise_kph, v_cruise_kph_last = \
              state_transition(sm.frame, CS, CP, state, events, soft_disable_timer, v_cruise_kph, AM)
            prof.checkpoint("State transition")

        # Compute actuators (runs PID loops and lateral MPC)
        actuators, v_cruise_kph, v_acc, a_acc, lac_log, last_blinker_frame = \
          state_control(sm.frame, sm.rcv_frame, sm['plan'], sm['pathPlan'], CS, CP, state, events, v_cruise_kph, v_cruise_kph_last, AM, rk,
                        LaC, LoC, read_only, is_metric, cal_perc, last_blinker_frame)

        prof.checkpoint("State Control")

        # Publish data
        CC, events_prev = data_send(sm, pm, CS, CI, CP, VM, state, events,
                                    actuators, v_cruise_kph, rk, AM, LaC, LoC,
                                    read_only, start_time, v_acc, a_acc,
                                    lac_log, events_prev, last_blinker_frame,
                                    is_ldw_enabled, can_error_counter)
        prof.checkpoint("Sent")

        rk.monitor_time()
        prof.display()
Exemple #25
0
 def __init__(self):
     self.ubloxRaw = messaging.sub_sock('ubloxRaw')
     self.buf = ""
Exemple #26
0
def manager_thread():
    # now loop
    thermal_sock = messaging.sub_sock('thermal')

    if os.getenv("GET_CPU_USAGE"):
        proc_sock = messaging.sub_sock('procLog', conflate=True)

    cloudlog.info("manager start")
    cloudlog.info({"environ": os.environ})

    # save boot log
    subprocess.call(["./loggerd", "--bootlog"],
                    cwd=os.path.join(BASEDIR, "selfdrive/loggerd"))

    params = Params()

    # start daemon processes
    for p in daemon_processes:
        start_daemon_process(p)

    # start persistent processes
    for p in persistent_processes:
        start_managed_process(p)

    # start offroad
    if ANDROID:
        pm_apply_packages('enable')
        start_offroad()

    if os.getenv("NOBOARD") is None:
        start_managed_process("pandad")

    if os.getenv("BLOCK") is not None:
        for k in os.getenv("BLOCK").split(","):
            del managed_processes[k]

    logger_dead = False

    # Tinkla interface
    last_tinklad_send_attempt_time = 0
    tinklaClient = TinklaClient()
    sendUserInfoToTinkla(params=params, tinklaClient=tinklaClient)
    start_t = time.time()
    first_proc = None

    while 1:
        msg = messaging.recv_sock(thermal_sock, wait=True)

        # heavyweight batch processes are gated on favorable thermal conditions
        if msg.thermal.thermalStatus >= ThermalStatus.yellow:
            for p in green_temp_processes:
                if p in persistent_processes:
                    kill_managed_process(p)
        else:
            for p in green_temp_processes:
                if p in persistent_processes:
                    start_managed_process(p)

        # Attempt to send pending messages if there's any that queued while offline
        # Seems this loop runs every second or so, throttle to once every 30s
        now = time.time()
        if now - last_tinklad_send_attempt_time >= 30:
            tinklaClient.attemptToSendPendingMessages()
            last_tinklad_send_attempt_time = now

        if msg.thermal.freeSpace < 0.05:
            logger_dead = True

        if msg.thermal.started:
            for p in car_started_processes:
                if p == "loggerd" and logger_dead:
                    kill_managed_process(p)
                else:
                    start_managed_process(p)
        else:
            logger_dead = False
            for p in reversed(car_started_processes):
                kill_managed_process(p)

        # check the status of all processes, did any of them die?
        running_list = [
            "%s%s\u001b[0m" %
            ("\u001b[32m" if running[p].is_alive() else "\u001b[31m", p)
            for p in running
        ]
        cloudlog.debug(' '.join(running_list))

        # Exit main loop when uninstall is needed
        if params.get("DoUninstall", encoding='utf8') == "1":
            break

        if os.getenv("GET_CPU_USAGE"):
            dt = time.time() - start_t

            # Get first sample
            if dt > 30 and first_proc is None:
                first_proc = messaging.recv_sock(proc_sock)

            # Get last sample and exit
            if dt > 90:
                first_proc = first_proc
                last_proc = messaging.recv_sock(proc_sock, wait=True)

                cleanup_all_processes(None, None)
                sys.exit(print_cpu_usage(first_proc, last_proc))
Exemple #27
0
def radard_thread(sm=None, pm=None, can_sock=None):
    config_realtime_process(5 if TICI else 1 if JETSON else 2,
                            Priority.CTRL_LOW)

    # wait for stats about the car to come in from controls
    cloudlog.info("radard is waiting for CarParams")
    CP = car.CarParams.from_bytes(Params().get("CarParams", block=True))
    cloudlog.info("radard got CarParams")

    # import the radar from the fingerprint
    cloudlog.info("radard is importing %s", CP.carName)
    RadarInterface = importlib.import_module(
        'selfdrive.car.%s.radar_interface' % CP.carName).RadarInterface

    # *** setup messaging
    if can_sock is None:
        can_sock = messaging.sub_sock('can')
    if sm is None:
        sm = messaging.SubMaster(
            ['modelV2', 'carState'], ignore_avg_freq=[
                'modelV2', 'carState'
            ])  # Can't check average frequency, since radar determines timing
    if pm is None:
        pm = messaging.PubMaster(['radarState', 'liveTracks'])

    RI = RadarInterface(CP)

    rk = Ratekeeper(1.0 / CP.radarTimeStep, print_delay_threshold=None)
    RD = RadarD(CP.radarTimeStep, RI.delay)

    # TODO: always log leads once we can hide them conditionally
    enable_lead = True  #CP.openpilotLongitudinalControl or not CP.radarOffCan

    while 1:
        can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True)
        rr = RI.update(can_strings)

        if rr is None:
            continue

        sm.update(0)

        dat = RD.update(sm, rr, enable_lead)
        dat.radarState.cumLagMs = -rk.remaining * 1000.

        pm.send('radarState', dat)

        # *** publish tracks for UI debugging (keep last) ***
        tracks = RD.tracks
        dat = messaging.new_message('liveTracks', len(tracks))

        for cnt, ids in enumerate(sorted(tracks.keys())):
            dat.liveTracks[cnt] = {
                "trackId": ids,
                "dRel": float(tracks[ids].dRel),
                "yRel": float(tracks[ids].yRel),
                "vRel": float(tracks[ids].vRel),
            }
        pm.send('liveTracks', dat)

        rk.monitor_time()
Exemple #28
0
    return car_fw


if __name__ == "__main__":
    import time
    import argparse
    import cereal.messaging as messaging
    from selfdrive.car.vin import get_vin

    parser = argparse.ArgumentParser(
        description='Get firmware version of ECUs')
    parser.add_argument('--scan', action='store_true')
    parser.add_argument('--debug', action='store_true')
    args = parser.parse_args()

    logcan = messaging.sub_sock('can')
    sendcan = messaging.pub_sock('sendcan')

    extra: Any = None
    if args.scan:
        extra = {}
        # Honda
        for i in range(256):
            extra[(Ecu.unknown, 0x18da00f1 + (i << 8), None)] = []
            extra[(Ecu.unknown, 0x700 + i, None)] = []
            extra[(Ecu.unknown, 0x750, i)] = []
        extra = {"any": {"debug": extra}}

    time.sleep(1.)

    t = time.time()
Exemple #29
0
#!/usr/bin/env python3
import os
import time
import numpy as np
import cereal.messaging as messaging
import selfdrive.manager as manager

N = int(os.getenv("N", "5"))
TIME = int(os.getenv("TIME", "30"))

if __name__ == "__main__":
    sock = messaging.sub_sock('modelV2', conflate=False, timeout=1000)

    execution_times = []

    for _ in range(N):
        os.environ['LOGPRINT'] = 'debug'
        manager.start_managed_process('modeld')
        time.sleep(5)

        t = []
        start = time.monotonic()
        while time.monotonic() - start < TIME:
            msgs = messaging.drain_sock(sock, wait_for_one=True)
            for m in msgs:
                t.append(m.modelV2.modelExecutionTime)

        execution_times.append(np.array(t[10:]) * 1000)
        manager.kill_managed_process('modeld')

    print("\n\n")
Exemple #30
0
from cereal import log
import cereal.messaging as messaging

if __name__ == "__main__":

  parser = argparse.ArgumentParser(description='Sniff a communcation socket')
  parser.add_argument('--addr', default='127.0.0.1')
  args = parser.parse_args()

  if args.addr != "127.0.0.1":
    os.environ["ZMQ"] = "1"
    messaging.context = messaging.Context()

  poller = messaging.Poller()
  messaging.sub_sock('can', poller, addr=args.addr)

  active = 0
  start_t = 0
  start_v = 0
  max_v = 0
  max_t = 0
  window = deque(maxlen=10)
  avg = 0
  while 1:
    polld = poller.poll(1000)
    for sock in polld:
      msg = sock.receive()
      evt = log.Event.from_bytes(msg)

      for item in evt.can: