Beispiel #1
0
def hw_state_thread(end_event, hw_queue):
    """Handles non critical hardware state, and sends over queue"""
    count = 0
    registered_count = 0

    while not end_event.is_set():
        # these are expensive calls. update every 10s
        if (count % int(10. / DT_TRML)) == 0:
            try:
                network_type = HARDWARE.get_network_type()

                hw_state = HardwareState(
                    network_type=network_type,
                    network_strength=HARDWARE.get_network_strength(
                        network_type),
                    network_info=HARDWARE.get_network_info(),
                    nvme_temps=HARDWARE.get_nvme_temperatures(),
                    modem_temps=HARDWARE.get_modem_temperatures(),
                    wifi_address=HARDWARE.get_ip_address(),
                )

                try:
                    hw_queue.put_nowait(hw_state)
                except queue.Full:
                    pass

                if TICI and (hw_state.network_info
                             is not None) and (hw_state.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 {hw_state.network_info}. nmcli conn up lte"
                    )
                    os.system("nmcli conn up lte")
                    registered_count = 0

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

        count += 1
        time.sleep(DT_TRML)
def main():
    clear_apport_folder(
    )  # Clear apport folder on start, otherwise duplicate crashes won't register
    initial_tombstones = set(get_tombstones())

    sentry_sdk.utils.MAX_STRING_LENGTH = 8192
    sentry_sdk.init(
        "https://*****:*****@sentry.io/1488600",
        default_integrations=False,
        release=version)

    dongle_id = Params().get("DongleId", encoding='utf-8')
    gitname = Params().get("GithubUsername", encoding='utf-8')
    sentry_sdk.set_user({"id": dongle_id})
    sentry_sdk.set_user({"name": gitname})
    sentry_sdk.set_tag("dirty", dirty)
    sentry_sdk.set_tag("origin", origin)
    sentry_sdk.set_tag("branch", branch)
    sentry_sdk.set_tag("commit", commit)
    sentry_sdk.set_tag("device", HARDWARE.get_device_type())

    while True:
        now_tombstones = set(get_tombstones())

        for fn, _ in (now_tombstones - initial_tombstones):
            try:
                cloudlog.info(f"reporting new tombstone {fn}")
                if fn.endswith(".crash"):
                    report_tombstone_apport(fn)
                else:
                    report_tombstone_android(fn)
            except Exception:
                cloudlog.exception(f"Error reporting tombstone {fn}")

        initial_tombstones = now_tombstones
        time.sleep(5)
def setEONChargingStatus(car_voltage_mV, batteryPercent):
    if EON:
        if car_voltage_mV is None or batteryPercent is None:
            HARDWARE.set_battery_charging(True)
            return
        #print( "car_voltage_mV:",car_voltage_mV)
        #print( "batteryPercent:",batteryPercent)
        #print( "VBATT_PAUSE_CHARGING:",VBATT_PAUSE_CHARGING)
        #print("VBATT_PAUSE_CHARGING * 1e3:", VBATT_PAUSE_CHARGING * 1e3)
        if HARDWARE.get_battery_charging():
            #print("log purpose : HARDWARE.get_battery_charging()  True ")
            # if batteryPercent > BATT_PERC_MAX or car_voltage_mV  < VBATT_PAUSE_CHARGING * 1e3 :
            if batteryPercent > BATT_PERC_MAX:  #or car_voltage_mV < VBATT_PAUSE_CHARGING * 1e3:
                #print("log purpose : HARDWARE.set_battery_charging(False)  False ")
                HARDWARE.set_battery_charging(False)
                return
        else:
            #print("log purpose : HARDWARE.get_battery_charging()  False ")
            #if batteryPercent < BATT_PERC_MIN and car_voltage_mV  > VBATT_PAUSE_CHARGING * 1e3:
            if batteryPercent < BATT_PERC_MIN:  #and car_voltage_mV > VBATT_PAUSE_CHARGING * 1e3:
                #print("log purpose : HARDWARE.set_battery_charging(True)  True ")
                HARDWARE.set_battery_charging(True)
                return
          def perform_pulse_measurement(now):
            try:
              HARDWARE.set_battery_charging(False)
              time.sleep(5)

              # Measure for a few sec to get a good average
              voltages = []
              currents = []
              for _ in range(6):
                voltages.append(HARDWARE.get_battery_voltage())
                currents.append(HARDWARE.get_battery_current())
                time.sleep(1)
              current_power = ((mean(voltages) / 1000000) * (mean(currents) / 1000000))

              self._perform_integration(now, current_power * FUDGE_FACTOR)

              # Enable charging again
              HARDWARE.set_battery_charging(True)
            except Exception:
              cloudlog.exception("Pulsed power measurement failed")
Beispiel #5
0
def thermald_thread(end_event, hw_queue):
    pm = messaging.PubMaster(['deviceState'])
    sm = messaging.SubMaster([
        "peripheralState", "gpsLocationExternal", "controlsState",
        "pandaStates"
    ],
                             poll=["pandaStates"])

    count = 0

    onroad_conditions: Dict[str, bool] = {
        "ignition": False,
    }
    startup_conditions: Dict[str, bool] = {}
    startup_conditions_prev: Dict[str, bool] = {}

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

    last_hw_state = HardwareState(
        network_type=NetworkType.none,
        network_metered=False,
        network_strength=NetworkStrength.unknown,
        network_info=None,
        nvme_temps=[],
        modem_temps=[],
        wifi_address='N/A',
    )

    current_filter = FirstOrderFilter(0., CURRENT_TAU, DT_TRML)
    temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_TRML)
    should_start_prev = False
    in_car = False
    engaged_prev = False

    params = Params()
    power_monitor = PowerMonitoring()

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

    fan_controller = None

    restart_triggered_ts = 0.
    panda_state_ts = 0.

    while not end_event.is_set():
        sm.update(PANDA_STATES_TIMEOUT)

        pandaStates = sm['pandaStates']
        peripheralState = sm['peripheralState']

        msg = read_thermal(thermal_config)

        # neokii
        if sec_since_boot() - restart_triggered_ts < 5.:
            onroad_conditions["not_restart_triggered"] = False
        else:
            onroad_conditions["not_restart_triggered"] = True

            if params.get_bool("SoftRestartTriggered"):
                params.put_bool("SoftRestartTriggered", False)
                restart_triggered_ts = sec_since_boot()

        if sm.updated['pandaStates'] and len(pandaStates) > 0:

            # Set ignition based on any panda connected
            onroad_conditions["ignition"] = any(
                ps.ignitionLine or ps.ignitionCan for ps in pandaStates
                if ps.pandaType != log.PandaState.PandaType.unknown)

            pandaState = pandaStates[0]

            if pandaState.pandaType != log.PandaState.PandaType.unknown:
                panda_state_ts = sec_since_boot()

            in_car = pandaState.harnessStatus != log.PandaState.HarnessStatus.notConnected

            # Setup fan handler on first connect to panda
            if fan_controller is None and peripheralState.pandaType != log.PandaState.PandaType.unknown:
                if TICI:
                    fan_controller = TiciFanController()

        try:
            last_hw_state = hw_queue.get_nowait()
        except queue.Empty:
            pass

        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 = last_hw_state.network_type
        msg.deviceState.networkMetered = last_hw_state.network_metered
        msg.deviceState.networkStrength = last_hw_state.network_strength
        if last_hw_state.network_info is not None:
            msg.deviceState.networkInfo = last_hw_state.network_info

        msg.deviceState.nvmeTempC = last_hw_state.nvme_temps
        msg.deviceState.modemTempC = last_hw_state.modem_temps
        msg.deviceState.wifiIpAddress = last_hw_state.wifi_address

        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 fan_controller is not None:
            msg.deviceState.fanSpeedPercentDesired = fan_controller.update(
                max_comp_temp, onroad_conditions["ignition"])

        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 ****

        # Ensure date/time are valid
        now = datetime.datetime.utcnow()
        startup_conditions[
            "time_valid"] = True  #(now.year > 2020) or (now.year == 2020 and now.month >= 10)
        set_offroad_alert_if_changed("Offroad_InvalidTime",
                                     (not startup_conditions["time_valid"]))

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

        # 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
        onroad_conditions[
            "device_temp_good"] = thermal_status < ThermalStatus.danger
        set_offroad_alert_if_changed(
            "Offroad_TemperatureTooHigh",
            (not onroad_conditions["device_temp_good"]))

        # TODO: this should move to TICI.initialize_hardware, but we currently can't import params there
        if TICI:
            if not os.path.isfile("/persist/comma/living-in-the-moment"):
                if not Path("/data/media").is_mount():
                    set_offroad_alert_if_changed("Offroad_StorageMissing",
                                                 True)
                else:
                    # check for bad NVMe
                    try:
                        with open("/sys/block/nvme0n1/device/model") as f:
                            model = f.read().strip()
                        if not model.startswith(
                                "Samsung SSD 980") and params.get(
                                    "Offroad_BadNvme") is None:
                            set_offroad_alert_if_changed(
                                "Offroad_BadNvme", True)
                            cloudlog.event("Unsupported NVMe",
                                           model=model,
                                           error=True)
                    except Exception:
                        pass

        # Handle offroad/onroad transition
        should_start = all(onroad_conditions.values())
        if started_ts is None:
            should_start = should_start and 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)

            params.put_bool("IsEngaged", False)
            engaged_prev = False
            HARDWARE.set_power_save(not should_start)

        if sm.updated['controlsState']:
            engaged = sm['controlsState'].enabled
            if engaged != engaged_prev:
                params.put_bool("IsEngaged", engaged)
                engaged_prev = engaged

            try:
                with open('/dev/kmsg', 'w') as kmsg:
                    kmsg.write(f"<3>[thermald] engaged: {engaged}\n")
            except Exception:
                pass

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

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

        # Offroad power monitoring
        power_monitor.calculate(peripheralState, onroad_conditions["ignition"])
        msg.deviceState.offroadPowerUsageUwh = power_monitor.get_power_used()
        msg.deviceState.carBatteryCapacityUwh = max(
            0, power_monitor.get_car_battery_capacity())
        current_power_draw = HARDWARE.get_current_power_draw()  # pylint: disable=assignment-from-none
        if current_power_draw is not None:
            statlog.sample("power_draw", current_power_draw)
            msg.deviceState.powerDrawW = current_power_draw
        else:
            msg.deviceState.powerDrawW = 0

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

        # Check if we need to shut down
        if power_monitor.should_shutdown(peripheralState,
                                         onroad_conditions["ignition"], in_car,
                                         off_ts, started_seen):
            cloudlog.warning(f"shutting device down, offroad since {off_ts}")
            params.put_bool("DoShutdown", True)

        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)

        should_start_prev = should_start
        startup_conditions_prev = startup_conditions.copy()

        # Log to statsd
        statlog.gauge("free_space_percent", msg.deviceState.freeSpacePercent)
        statlog.gauge("gpu_usage_percent", msg.deviceState.gpuUsagePercent)
        statlog.gauge("memory_usage_percent",
                      msg.deviceState.memoryUsagePercent)
        for i, usage in enumerate(msg.deviceState.cpuUsagePercent):
            statlog.gauge(f"cpu{i}_usage_percent", usage)
        for i, temp in enumerate(msg.deviceState.cpuTempC):
            statlog.gauge(f"cpu{i}_temperature", temp)
        for i, temp in enumerate(msg.deviceState.gpuTempC):
            statlog.gauge(f"gpu{i}_temperature", temp)
        statlog.gauge("memory_temperature", msg.deviceState.memoryTempC)
        statlog.gauge("ambient_temperature", msg.deviceState.ambientTempC)
        for i, temp in enumerate(msg.deviceState.pmicTempC):
            statlog.gauge(f"pmic{i}_temperature", temp)
        for i, temp in enumerate(last_hw_state.nvme_temps):
            statlog.gauge(f"nvme_temperature{i}", temp)
        for i, temp in enumerate(last_hw_state.modem_temps):
            statlog.gauge(f"modem_temperature{i}", temp)
        statlog.gauge("fan_speed_percent_desired",
                      msg.deviceState.fanSpeedPercentDesired)
        statlog.gauge("screen_brightness_percent",
                      msg.deviceState.screenBrightnessPercent)

        # report to server once every 10 minutes
        if (count % int(600. / DT_TRML)) == 0:
            cloudlog.event(
                "STATUS_PACKET",
                count=count,
                pandaStates=[
                    strip_deprecated_keys(p.to_dict()) for p in pandaStates
                ],
                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
Beispiel #6
0
def getNetworks():
    return HARDWARE.get_networks()
Beispiel #7
0
def getSimInfo():
    return HARDWARE.get_sim_info()
Beispiel #8
0
def is_on_wifi():
  return HARDWARE.get_network_type() == NetworkType.wifi
Beispiel #9
0
def thermald_thread() -> NoReturn:

  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

  onroad_conditions: Dict[str, bool] = {
    "ignition": False,
  }
  startup_conditions: Dict[str, bool] = {}
  startup_conditions_prev: Dict[str, bool] = {}

  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 onroad_conditions["ignition"]:
            cloudlog.error("Lost panda connection while onroad")
          onroad_conditions["ignition"] = False
      else:
        no_panda_cnt = 0
        onroad_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, onroad_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 ****

    # Ensure date/time are valid
    now = datetime.datetime.utcnow()
    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"]))

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

    # 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
    onroad_conditions["device_temp_good"] = thermal_status < ThermalStatus.danger
    set_offroad_alert_if_changed("Offroad_TemperatureTooHigh", (not onroad_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(onroad_conditions.values())
    if started_ts is None:
      should_start = should_start and 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 onroad_conditions["ignition"] and (startup_conditions != startup_conditions_prev):
        cloudlog.event("Startup blocked", startup_conditions=startup_conditions, onroad_conditions=onroad_conditions)

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

    # Offroad power monitoring
    power_monitor.calculate(peripheralState, onroad_conditions["ignition"])
    msg.deviceState.offroadPowerUsageUwh = power_monitor.get_power_used()
    msg.deviceState.carBatteryCapacityUwh = max(0, power_monitor.get_car_battery_capacity())
    current_power_draw = HARDWARE.get_current_power_draw()  # pylint: disable=assignment-from-none
    msg.deviceState.powerDrawW = current_power_draw if current_power_draw is not None else 0

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

    # Check if we need to shut down
    if power_monitor.should_shutdown(peripheralState, onroad_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
Beispiel #10
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')

    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)
    pandaState_prev = None
    should_start_prev = False
    handle_fan = None
    is_uno = False
    has_relay = False

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

    thermal_config = HARDWARE.get_thermal_config()

    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

            # 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
                has_relay = pandaState.pandaState.pandaType in [
                    log.PandaState.PandaType.blackPanda,
                    log.PandaState.PandaType.uno, log.PandaState.PandaType.dos
                ]

                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 (has_relay
                                                      and 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"]))

        startup_conditions["hardware_supported"] = pandaState is not None
        set_offroad_alert_if_changed(
            "Offroad_HardwareUnsupported", pandaState 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(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,
                                         LEON):
            cloudlog.info(f"shutting device down, offroad since {off_ts}")
            # TODO: add function for blocking cloudlog instead of sleep
            time.sleep(10)
            HARDWARE.shutdown()

        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)

        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:
            location = messaging.recv_sock(location_sock)
            cloudlog.event(
                "STATUS_PACKET",
                count=count,
                pandaState=(pandaState.to_dict() if pandaState else None),
                location=(location.gpsLocationExternal.to_dict()
                          if location else None),
                deviceState=msg.to_dict())

        count += 1
Beispiel #11
0
def main():
    params = Params()
    params.manager_start()

    default_params = [
        ("CommunityFeaturesToggle", "0"),
        ("CompletedTrainingVersion", "0"),
        ("IsRHD", "0"),
        ("IsMetric", "1"),
        ("RecordFront", "0"),
        ("HasAcceptedTerms", "0"),
        ("HasCompletedSetup", "0"),
        ("IsUploadRawEnabled", "1"),
        ("IsLdwEnabled", "1"),
        ("IsGeofenceEnabled", "-1"),
        ("SpeedLimitOffset", "0"),
        ("LimitSetSpeed", "0"),
        ("LimitSetSpeedNeural", "0"),
        ("LastUpdateTime",
         datetime.datetime.utcnow().isoformat().encode('utf8')),
        ("OpenpilotEnabledToggle", "1"),
        ("LaneChangeEnabled", "1"),
        ("IsDriverViewEnabled", "0"),
        ("IsOpenpilotViewEnabled", "0"),
        ("OpkrAutoShutdown", "2"),
        ("OpkrAutoScreenOff", "0"),
        ("OpkrUIBrightness", "0"),
        ("OpkrEnableDriverMonitoring", "1"),
        ("OpkrEnableLogger", "0"),
        ("OpkrEnableGetoffAlert", "1"),
        ("OpkrAutoResume", "1"),
        ("OpkrVariableCruise", "0"),
        ("OpkrLaneChangeSpeed", "60"),
        ("OpkrAutoLaneChangeDelay", "0"),
        ("OpkrSteerAngleCorrection", "0"),
        ("PutPrebuiltOn", "0"),
        ("FingerprintIssuedFix", "0"),
        ("LdwsCarFix", "0"),
        ("LateralControlMethod", "0"),
        ("InnerLoopGain", "30"),
        ("OuterLoopGain", "20"),
        ("TimeConstant", "10"),
        ("ActuatorEffectiveness", "15"),
        ("Scale", "1750"),
        ("LqrKi", "10"),
        ("DcGain", "30"),
        ("IgnoreZone", "1"),
        ("PidKp", "20"),
        ("PidKi", "40"),
        ("PidKd", "150"),
        ("PidKf", "5"),
        ("CameraOffsetAdj", "60"),
        ("SteerRatioAdj", "140"),
        ("SteerActuatorDelayAdj", "35"),
        ("SteerRateCostAdj", "45"),
        ("SteerLimitTimerAdj", "40"),
        ("TireStiffnessFactorAdj", "85"),
        ("SteerMaxAdj", "380"),
        ("SteerMaxBaseAdj", "275"),
        ("SteerDeltaUpAdj", "3"),
        ("SteerDeltaDownAdj", "7"),
        ("SteerMaxvAdj", "10"),
        ("OpkrBatteryChargingControl", "1"),
        ("OpkrBatteryChargingMin", "70"),
        ("OpkrBatteryChargingMax", "80"),
        ("OpkrUiOpen", "0"),
        ("OpkrDriveOpen", "0"),
        ("OpkrTuneOpen", "0"),
        ("OpkrControlOpen", "0"),
        ("LeftCurvOffsetAdj", "0"),
        ("RightCurvOffsetAdj", "0"),
        ("DebugUi1", "0"),
        ("DebugUi2", "0"),
        ("OpkrBlindSpotDetect", "1"),
        ("OpkrMaxAngleLimit", "90"),
        ("OpkrAngleOffsetSelect", "0"),
        ("OpkrCruiseGapSet", "3"),
        ("OpkrLatMode", "0"),
        ("OpkrAccMode", "1"),
        ("LimitSetSpeedCamera", "0"),
        ("LimitSetSpeedCurv", "1"),
        ("OpkrLiveSteerRatio", "0"),
        ("OpkrVariableSteerMax", "1"),
        ("OpkrVariableSteerDelta", "0"),
        ("FingerprintTwoSet", "1"),
        ("OpkrVariableCruiseProfile", "0"),
        ("OpkrLiveTune", "0"),
        ("OpkrEnableMap", "1"),
        ("OpkrDrivingRecord", "0"),
    ]

    # set unset params
    for k, v in default_params:
        if params.get(k) is None:
            params.put(k, v)

    # is this dashcam?
    if os.getenv("PASSIVE") is not None:
        params.put("Passive", str(int(os.getenv("PASSIVE"))))

    if params.get("Passive") is None:
        raise Exception("Passive must be set to continue")

    if EON:
        update_apks()
    manager_init()
    manager_prepare(spinner)
    spinner.close()

    if os.getenv("PREPAREONLY") is not None:
        return

    # SystemExit on sigterm
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit(1))

    try:
        manager_thread()
    except Exception:
        traceback.print_exc()
        crash.capture_exception()
    finally:
        cleanup_all_processes(None, None)

    if params.get("DoUninstall", encoding='utf8') == "1":
        cloudlog.warning("uninstalling")
        HARDWARE.uninstall()
Beispiel #12
0
def manager_init():

    # update system time from panda
    set_time(cloudlog)

    params = Params()
    params.manager_start()

    default_params = [
        ("CompletedTrainingVersion", "0"),
        ("HasAcceptedTerms", "0"),
        ("LastUpdateTime",
         datetime.datetime.utcnow().isoformat().encode('utf8')),
        ("OpenpilotEnabledToggle", "1"),
        ("IsMetric", "1"),

        # HKG
        ("UseClusterSpeed", "1"),
        ("LongControlEnabled", "0"),
        ("MadModeEnabled", "1"),
        ("AutoLaneChangeEnabled", "0"),
        ("SccSmootherSlowOnCurves", "0"),
        ("SccSmootherSyncGasPressed", "0"),
        ("ShowDebugUI", "0")
    ]

    if params.get_bool("RecordFrontLock"):
        params.put_bool("RecordFront", True)

    # set unset params
    for k, v in default_params:
        if params.get(k) is None:
            params.put(k, v)

    # is this dashcam?
    if os.getenv("PASSIVE") is not None:
        params.put_bool("Passive", bool(int(os.getenv("PASSIVE"))))

    if params.get("Passive") is None:
        raise Exception("Passive must be set to continue")

    os.umask(0)  # Make sure we can create files with 777 permissions

    # Create folders needed for msgq
    try:
        os.mkdir("/dev/shm")
    except FileExistsError:
        pass
    except PermissionError:
        print("WARNING: failed to make /dev/shm")

    # set dongle id
    reg_res = register(show_spinner=True)
    if reg_res:
        dongle_id = reg_res
    else:
        raise Exception("server registration failed")
    os.environ['DONGLE_ID'] = dongle_id  # Needed for swaglog and loggerd

    if not dirty:
        os.environ['CLEAN'] = '1'

    cloudlog.bind_global(dongle_id=dongle_id,
                         version=version,
                         dirty=dirty,
                         device=HARDWARE.get_device_type())
    crash.bind_user(id=dongle_id)
    crash.bind_extra(version=version,
                     dirty=dirty,
                     device=HARDWARE.get_device_type())
Beispiel #13
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

  network_type = NetworkType.none
  network_strength = NetworkStrength.unknown
  network_info = None
  modem_version = None
  registered_count = 0
  wifiIpAddress = "N/A"
  wifi_ssid = "---"

  current_filter = FirstOrderFilter(0., CURRENT_TAU, DT_TRML)
  cpu_temp_filter = FirstOrderFilter(0., CPU_TEMP_TAU, DT_TRML)
  pandaState_prev = None
  should_start_prev = 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()

  if params.get_bool("IsOnroad"):
    cloudlog.event("onroad flag not cleared")

  # 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_files = ["/sys/kernel/debug/regulator/pm8994_s11/voltage"] + cpr_files
    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)

  # 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_bool("OpkrEnableGetoffAlert")

  hotspot_on_boot = params.get_bool("OpkrHotspotOnBoot")
  hotspot_run = False

  if int(params.get("OpkrAutoShutdown", encoding="utf8")) == 0:
    opkrAutoShutdown = 0
  elif int(params.get("OpkrAutoShutdown", encoding="utf8")) == 1:
    opkrAutoShutdown = 5
  elif int(params.get("OpkrAutoShutdown", encoding="utf8")) == 2:
    opkrAutoShutdown = 30
  elif int(params.get("OpkrAutoShutdown", encoding="utf8")) == 3:
    opkrAutoShutdown = 60
  elif int(params.get("OpkrAutoShutdown", encoding="utf8")) == 4:
    opkrAutoShutdown = 180
  elif int(params.get("OpkrAutoShutdown", encoding="utf8")) == 5:
    opkrAutoShutdown = 300
  elif int(params.get("OpkrAutoShutdown", encoding="utf8")) == 6:
    opkrAutoShutdown = 600
  elif int(params.get("OpkrAutoShutdown", encoding="utf8")) == 7:
    opkrAutoShutdown = 1800
  elif int(params.get("OpkrAutoShutdown", encoding="utf8")) == 8:
    opkrAutoShutdown = 3600
  elif int(params.get("OpkrAutoShutdown", encoding="utf8")) == 9:
    opkrAutoShutdown = 10800
  else:
    opkrAutoShutdown = 18000

  battery_charging_control = params.get_bool("OpkrBatteryChargingControl")
  battery_charging_min = int(params.get("OpkrBatteryChargingMin", encoding="utf8"))
  battery_charging_max = int(params.get("OpkrBatteryChargingMax", encoding="utf8"))

  is_openpilot_dir = True

  while 1:
    ts = sec_since_boot()
    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
          shutdown_trigger = 1
      else:
        no_panda_cnt = 0
        startup_conditions["ignition"] = pandaState.pandaState.ignitionLine or pandaState.pandaState.ignitionCan
        sound_trigger == 1
      #startup_conditions["hardware_supported"] = pandaState.pandaState.pandaType not in [log.PandaState.PandaType.whitePanda,
      #                                                                                   log.PandaState.PandaType.greyPanda]
      #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.clear_all(ParamKeyType.CLEAR_ON_PANDA_DISCONNECT)
      pandaState_prev = pandaState
    elif params.get_bool("IsOpenpilotViewEnabled") and not params.get_bool("IsDriverViewEnabled") and is_openpilot_view_enabled == 0:
      is_openpilot_view_enabled = 1
      startup_conditions["ignition"] = True
    elif not params.get_bool("IsOpenpilotViewEnabled") and not params.get_bool("IsDriverViewEnabled") 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, wifi_ssid = HARDWARE.get_network_strength(network_type)
        network_info = HARDWARE.get_network_info()  # pylint: disable=assignment-from-none

        # 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

        wifiIpAddress = HARDWARE.get_ip_address()
        try:
          ping_test = subprocess.check_output(["ping", "-c", "1", "-W", "1", "google.com"])
          Params().put("LastAthenaPingTime", str(int(sec_since_boot() * 1e9))) if ping_test else False
        except Exception:
          Params().delete("LastAthenaPingTime")
      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.gpuUsagePercent = int(round(HARDWARE.get_gpu_usage_percent()))
    msg.deviceState.networkType = network_type
    msg.deviceState.networkStrength = network_strength
    msg.deviceState.wifiSSID = wifi_ssid
    if network_info is not None:
      msg.deviceState.networkInfo = network_info
    msg.deviceState.wifiIpAddress = wifiIpAddress
    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"] = True if ((now.year > 2020) or (now.year == 2020 and now.month >= 10)) else True # set True for battery less EON otherwise, set False.
    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_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_NvmeMissing", (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()

      if shutdown_trigger == 1 and sound_trigger == 1 and msg.deviceState.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.deviceState.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')

      if (count % int(1. / DT_TRML)) == 0:
        if int(params.get("OpkrForceShutdown", encoding="utf8")) != 0 and not started_seen and msg.deviceState.batteryStatus == "Discharging":
          shutdown_option = int(params.get("OpkrForceShutdown", encoding="utf8"))
          if shutdown_option == 1:
            opkrForceShutdown = 60
          elif shutdown_option == 2:
            opkrForceShutdown = 180
          elif shutdown_option == 3:
            opkrForceShutdown = 300
          elif shutdown_option == 4:
            opkrForceShutdown = 600
          else:
            opkrForceShutdown = 1800
          if (sec_since_boot() - off_ts) > opkrForceShutdown and params.get_bool("OpkrForceShutdownTrigger"):
            os.system('LD_LIBRARY_PATH="" svc power shutdown')
          elif not params.get_bool("OpkrForceShutdownTrigger"):
            off_ts = sec_since_boot()


    # opkr
    prebuiltlet = params.get_bool("PutPrebuiltOn")
    if not os.path.isdir("/data/openpilot"):
      if is_openpilot_dir:
        os.system("cd /data/params/d; rm -f DongleId") # Delete DongleID if the Openpilot directory disappears, Seems you want to switch fork/branch.
      is_openpilot_dir = False
    elif not os.path.isfile(prebuiltfile) and prebuiltlet and is_openpilot_dir:
      os.system("cd /data/openpilot; touch prebuilt")
    elif os.path.isfile(prebuiltfile) and not prebuiltlet:
      os.system("cd /data/openpilot; rm -f prebuilt")

    # opkr
    sshkeylet = params.get_bool("OpkrSSHLegacy")
    if not os.path.isfile(sshkeyfile) and sshkeylet:
      os.system("cp -f /data/openpilot/selfdrive/assets/addon/key/GithubSshKeys_legacy /data/params/d/GithubSshKeys; chmod 600 /data/params/d/GithubSshKeys; touch /data/public_key")
    elif os.path.isfile(sshkeyfile) and not sshkeylet:
      os.system("cp -f /data/openpilot/selfdrive/assets/addon/key/GithubSshKeys_new /data/params/d/GithubSshKeys; chmod 600 /data/params/d/GithubSshKeys; rm -f /data/public_key")

    # opkr hotspot
    if hotspot_on_boot and not hotspot_run and sec_since_boot() > 80:
      os.system("service call wifi 37 i32 0 i32 1 &")
      hotspot_run = True

    # 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))

    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()

    # atom
    if usb_power and battery_charging_control:
      power_monitor.charging_ctrl( msg, ts, battery_charging_max, battery_charging_min )    

    # 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)

      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
Beispiel #14
0
def main():
    params = Params()
    params.manager_start()

    default_params = [
        ("CommunityFeaturesToggle", "0"),
        ("CompletedTrainingVersion", "0"),
        ("IsRHD", "0"),
        ("IsMetric", "1"),
        ("RecordFront", "0"),
        ("HasAcceptedTerms", "0"),
        ("HasCompletedSetup", "0"),
        ("IsUploadRawEnabled", "1"),
        ("IsLdwEnabled", "1"),
        ("LastUpdateTime",
         datetime.datetime.utcnow().isoformat().encode('utf8')),
        ("OpenpilotEnabledToggle", "1"),
        ("LaneChangeEnabled", "1"),
        ("LongControlEnabled", "0"),
        ("MadModeEnabled", "1"),
        ("AutoLaneChangeEnabled", "0"),
        ("IsDriverViewEnabled", "0"),

        # scc smoother
        ("SccSmootherState", "0"),
        ("SccSmootherEnabled", "0"),
        ("SccSmootherSlowOnCurves", "0"),
        ("SccSmootherSyncGasPressed", "0"),
        ("SccSmootherSwitchGapOnly", "0"),
    ]

    # set unset params
    for k, v in default_params:
        if params.get(k) is None:
            params.put(k, v)

    # is this dashcam?
    if os.getenv("PASSIVE") is not None:
        params.put("Passive", str(int(os.getenv("PASSIVE"))))

    if params.get("Passive") is None:
        raise Exception("Passive must be set to continue")

    if EON:
        update_apks()
    manager_init()
    manager_prepare()
    spinner.close()

    if os.getenv("PREPAREONLY") is not None:
        return

    # SystemExit on sigterm
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit(1))

    try:
        manager_thread()
    except Exception:
        traceback.print_exc()
        crash.capture_exception()
    finally:
        cleanup_all_processes(None, None)

    if params.get("DoUninstall", encoding='utf8') == "1":
        cloudlog.warning("uninstalling")
        HARDWARE.uninstall()
Beispiel #15
0
 def test_sound_card_init(self):
     assert HARDWARE.get_sound_card_online()
Beispiel #16
0
def manager_init():
  # update system time from panda
  set_time(cloudlog)

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

  params = Params()
  params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START)

  default_params = [
    ("CompletedTrainingVersion", "0"),
    ("HasAcceptedTerms", "0"),
    ("OpenpilotEnabledToggle", "1"),
  ]
  if not PC:
    default_params.append(("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8')))

  if params.get_bool("RecordFrontLock"):
    params.put_bool("RecordFront", True)

  if not params.get_bool("DisableRadar_Allow"):
    params.delete("DisableRadar")

  # set unset params
  for k, v in default_params:
    if params.get(k) is None:
      params.put(k, v)

  # is this dashcam?
  if os.getenv("PASSIVE") is not None:
    params.put_bool("Passive", bool(int(os.getenv("PASSIVE"))))

  if params.get("Passive") is None:
    raise Exception("Passive must be set to continue")

  # Create folders needed for msgq
  try:
    os.mkdir("/dev/shm")
  except FileExistsError:
    pass
  except PermissionError:
    print("WARNING: failed to make /dev/shm")

  # set version params
  params.put("Version", version)
  params.put("TermsVersion", terms_version)
  params.put("TrainingVersion", training_version)
  params.put("GitCommit", get_git_commit(default=""))
  params.put("GitBranch", get_git_branch(default=""))
  params.put("GitRemote", get_git_remote(default=""))

  # set dongle id
  reg_res = register(show_spinner=True)
  if reg_res:
    dongle_id = reg_res
  else:
    serial = params.get("HardwareSerial")
    raise Exception(f"Registration failed for device {serial}")
  os.environ['DONGLE_ID'] = dongle_id  # Needed for swaglog

  if not dirty:
    os.environ['CLEAN'] = '1'

  cloudlog.bind_global(dongle_id=dongle_id, version=version, dirty=dirty,
                       device=HARDWARE.get_device_type())

  if comma_remote and not (os.getenv("NOLOG") or os.getenv("NOCRASH") or PC):
    crash.init()
  crash.bind_user(id=dongle_id)
  crash.bind_extra(dirty=dirty, origin=origin, branch=branch, commit=commit,
                   device=HARDWARE.get_device_type())
Beispiel #17
0
def manager_init(spinner=None):
    params = Params()
    params.manager_start()

    default_params = [
        ("CommunityFeaturesToggle", "0"),
        ("CompletedTrainingVersion", "0"),
        ("IsRHD", "0"),
        ("IsMetric", "0"),
        ("RecordFront", "0"),
        ("HasAcceptedTerms", "0"),
        ("HasCompletedSetup", "0"),
        ("IsUploadRawEnabled", "1"),
        ("IsLdwEnabled", "1"),
        ("LastUpdateTime",
         datetime.datetime.utcnow().isoformat().encode('utf8')),
        ("OpenpilotEnabledToggle", "1"),
        ("VisionRadarToggle", "0"),
        ("LaneChangeEnabled", "1"),
        ("IsDriverViewEnabled", "0"),
    ]

    # set unset params
    for k, v in default_params:
        if params.get(k) is None:
            params.put(k, v)

    # is this dashcam?
    if os.getenv("PASSIVE") is not None:
        params.put("Passive", str(int(os.getenv("PASSIVE"))))

    if params.get("Passive") is None:
        raise Exception("Passive must be set to continue")

    if EON:
        update_apks()

    os.umask(0)  # Make sure we can create files with 777 permissions

    # Create folders needed for msgq
    try:
        os.mkdir("/dev/shm")
    except FileExistsError:
        pass
    except PermissionError:
        print("WARNING: failed to make /dev/shm")

    # set dongle id
    reg_res = register(spinner)
    if reg_res:
        dongle_id = reg_res
    else:
        raise Exception("server registration failed")
    os.environ['DONGLE_ID'] = dongle_id  # Needed for swaglog and loggerd

    if not dirty:
        os.environ['CLEAN'] = '1'

    cloudlog.bind_global(dongle_id=dongle_id,
                         version=version,
                         dirty=dirty,
                         device=HARDWARE.get_device_type())
    crash.bind_user(id=dongle_id)
    crash.bind_extra(version=version,
                     dirty=dirty,
                     device=HARDWARE.get_device_type())

    # ensure shared libraries are readable by apks
    if EON:
        os.chmod(BASEDIR, 0o755)
        os.chmod("/dev/shm", 0o777)
        os.chmod(os.path.join(BASEDIR, "cereal"), 0o755)
        os.chmod(os.path.join(BASEDIR, "cereal", "libmessaging_shared.so"),
                 0o755)
Beispiel #18
0
def manager_init():

    # update system time from panda
    set_time(cloudlog)

    params = Params()
    params.manager_start()

    default_params = [
        ("CompletedTrainingVersion", "0"),
        ("HasAcceptedTerms", "0"),
        ("LastUpdateTime",
         datetime.datetime.utcnow().isoformat().encode('utf8')),
        ("OpenpilotEnabledToggle", "1"),
    ]

    if TICI:
        default_params.append(("IsUploadRawEnabled", "1"))

    if params.get_bool("RecordFrontLock"):
        params.put_bool("RecordFront", True)

    # set unset params
    for k, v in default_params:
        if params.get(k) is None:
            params.put(k, v)

    # is this dashcam?
    if os.getenv("PASSIVE") is not None:
        params.put_bool("Passive", bool(int(os.getenv("PASSIVE"))))

    if params.get("Passive") is None:
        raise Exception("Passive must be set to continue")

    os.umask(0)  # Make sure we can create files with 777 permissions

    # Create folders needed for msgq
    try:
        os.mkdir("/dev/shm")
    except FileExistsError:
        pass
    except PermissionError:
        print("WARNING: failed to make /dev/shm")

    # set version params
    params.put("Version", version)
    params.put("TermsVersion", terms_version)
    params.put("TrainingVersion", training_version)
    params.put("GitCommit", get_git_commit(default=""))
    params.put("GitBranch", get_git_branch(default=""))
    params.put("GitRemote", get_git_remote(default=""))

    # set dongle id
    dongle_id = register(show_spinner=True)
    if dongle_id is not None:
        os.environ['DONGLE_ID'] = dongle_id  # Needed for swaglog

    if not dirty:
        os.environ['CLEAN'] = '1'

    cloudlog.bind_global(dongle_id=dongle_id,
                         version=version,
                         dirty=dirty,
                         device=HARDWARE.get_device_type())

    if not (dongle_id is None or os.getenv("NOLOG") or os.getenv("NOCRASH")
            or PC):
        crash.init()
    crash.bind_user(id=dongle_id)
    crash.bind_extra(dirty=dirty,
                     origin=origin,
                     branch=branch,
                     commit=commit,
                     device=HARDWARE.get_device_type())
Beispiel #19
0
def manager_init():

    # update system time from panda
    set_time(cloudlog)

    params = Params()
    params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START)

    default_params = [
        ("OpenpilotEnabledToggle", "1"),
        ("CommunityFeaturesToggle", "1"),
        ("IsMetric", "1"),

        # HKG
        ("UseClusterSpeed", "1"),
        ("LongControlEnabled", "0"),
        ("MadModeEnabled", "1"),
        ("IsLdwsCar", "0"),
        ("LaneChangeEnabled", "0"),
        ("AutoLaneChangeEnabled", "0"),
        ("SccSmootherSlowOnCurves", "0"),
        ("SccSmootherSyncGasPressed", "0"),
        ("StockNaviDecelEnabled", "0"),
        ("ShowDebugUI", "0"),
        ("CustomLeadMark", "0")
    ]
    if not PC:
        default_params.append(
            ("LastUpdateTime",
             datetime.datetime.utcnow().isoformat().encode('utf8')))

    if params.get_bool("RecordFrontLock"):
        params.put_bool("RecordFront", True)

    # set unset params
    for k, v in default_params:
        if params.get(k) is None:
            params.put(k, v)

    # is this dashcam?
    if os.getenv("PASSIVE") is not None:
        params.put_bool("Passive", bool(int(os.getenv("PASSIVE"))))

    if params.get("Passive") is None:
        raise Exception("Passive must be set to continue")

    # Create folders needed for msgq
    try:
        os.mkdir("/dev/shm")
    except FileExistsError:
        pass
    except PermissionError:
        print("WARNING: failed to make /dev/shm")

    # set version params
    params.put("Version", version)
    params.put("TermsVersion", terms_version)
    params.put("TrainingVersion", training_version)
    params.put("GitCommit", get_git_commit(default=""))
    params.put("GitBranch", get_git_branch(default=""))
    params.put("GitRemote", get_git_remote(default=""))

    # set dongle id
    reg_res = register(show_spinner=True)
    if reg_res:
        dongle_id = reg_res
    else:
        serial = params.get("HardwareSerial")
        raise Exception(f"Registration failed for device {serial}")
    os.environ['DONGLE_ID'] = dongle_id  # Needed for swaglog

    if not dirty:
        os.environ['CLEAN'] = '1'

    cloudlog.bind_global(dongle_id=dongle_id,
                         version=version,
                         dirty=dirty,
                         device=HARDWARE.get_device_type())

    if comma_remote and not (os.getenv("NOLOG") or os.getenv("NOCRASH") or PC):
        crash.init()
    crash.bind_user(id=dongle_id)
    crash.bind_extra(dirty=dirty,
                     origin=origin,
                     branch=branch,
                     commit=commit,
                     device=HARDWARE.get_device_type())
Beispiel #20
0
def main() -> NoReturn:
    dongle_id = Params().get("DongleId", encoding='utf-8')

    def get_influxdb_line(measurement: str, value: Union[float, Dict[str,
                                                                     float]],
                          timestamp: datetime, tags: dict) -> str:
        res = f"{measurement}"
        for k, v in tags.items():
            res += f",{k}={str(v)}"
        res += " "

        if isinstance(value, float):
            value = {'value': value}

        for k, v in value.items():
            res += f"{k}={v},"

        res += f"dongle_id=\"{dongle_id}\" {int(timestamp.timestamp() * 1e9)}\n"
        return res

    # open statistics socket
    ctx = zmq.Context().instance()
    sock = ctx.socket(zmq.PULL)
    sock.bind(STATS_SOCKET)

    # initialize stats directory
    Path(STATS_DIR).mkdir(parents=True, exist_ok=True)

    # initialize tags
    tags = {
        'started': False,
        'version': get_short_version(),
        'branch': get_short_branch(),
        'dirty': is_dirty(),
        'origin': get_normalized_origin(),
        'deviceType': HARDWARE.get_device_type(),
    }

    # subscribe to deviceState for started state
    sm = SubMaster(['deviceState'])

    idx = 0
    last_flush_time = time.monotonic()
    gauges = {}
    samples: Dict[str, List[float]] = defaultdict(list)
    while True:
        started_prev = sm['deviceState'].started
        sm.update()

        # Update metrics
        while True:
            try:
                metric = sock.recv_string(zmq.NOBLOCK)
                try:
                    metric_type = metric.split('|')[1]
                    metric_name = metric.split(':')[0]
                    metric_value = float(metric.split('|')[0].split(':')[1])

                    if metric_type == METRIC_TYPE.GAUGE:
                        gauges[metric_name] = metric_value
                    elif metric_type == METRIC_TYPE.SAMPLE:
                        samples[metric_name].append(metric_value)
                    else:
                        cloudlog.event("unknown metric type",
                                       metric_type=metric_type)
                except Exception:
                    cloudlog.event("malformed metric", metric=metric)
            except zmq.error.Again:
                break

        # flush when started state changes or after FLUSH_TIME_S
        if (time.monotonic() > last_flush_time + STATS_FLUSH_TIME_S) or (
                sm['deviceState'].started != started_prev):
            result = ""
            current_time = datetime.utcnow().replace(tzinfo=timezone.utc)
            tags['started'] = sm['deviceState'].started

            for key, value in gauges.items():
                result += get_influxdb_line(f"gauge.{key}", value,
                                            current_time, tags)

            for key, values in samples.items():
                values.sort()
                sample_count = len(values)
                sample_sum = sum(values)

                stats = {
                    'count': sample_count,
                    'min': values[0],
                    'max': values[-1],
                    'mean': sample_sum / sample_count,
                }
                for percentile in [0.05, 0.5, 0.95]:
                    value = values[int(round(percentile * (sample_count - 1)))]
                    stats[f"p{int(percentile * 100)}"] = value

                result += get_influxdb_line(f"sample.{key}", stats,
                                            current_time, tags)

            # clear intermediate data
            gauges.clear()
            samples.clear()
            last_flush_time = time.monotonic()

            # check that we aren't filling up the drive
            if len(os.listdir(STATS_DIR)) < STATS_DIR_FILE_LIMIT:
                if len(result) > 0:
                    stats_path = os.path.join(
                        STATS_DIR, f"{current_time.timestamp():.0f}_{idx}")
                    with atomic_write_in_dir(stats_path) as f:
                        f.write(result)
                    idx += 1
            else:
                cloudlog.error("stats dir full")
Beispiel #21
0
def register(show_spinner=False) -> str:
    params = Params()
    params.put("SubscriberInfo", HARDWARE.get_subscriber_info())

    IMEI = params.get("IMEI", encoding='utf8')
    HardwareSerial = params.get("HardwareSerial", encoding='utf8')
    dongle_id = params.get("DongleId", encoding='utf8')
    needs_registration = None in (IMEI, HardwareSerial, dongle_id)

    # create a key for auth
    # your private key is kept on your device persist partition and never sent to our servers
    # do not erase your persist partition
    if not os.path.isfile(PERSIST + "/comma/id_rsa.pub"):
        needs_registration = True
        cloudlog.warning("generating your personal RSA key")
        mkdirs_exists_ok(PERSIST + "/comma")
        assert os.system("openssl genrsa -out " + PERSIST +
                         "/comma/id_rsa.tmp 2048") == 0
        assert os.system("openssl rsa -in " + PERSIST +
                         "/comma/id_rsa.tmp -pubout -out " + PERSIST +
                         "/comma/id_rsa.tmp.pub") == 0
        os.rename(PERSIST + "/comma/id_rsa.tmp", PERSIST + "/comma/id_rsa")
        os.rename(PERSIST + "/comma/id_rsa.tmp.pub",
                  PERSIST + "/comma/id_rsa.pub")

    if needs_registration:
        if show_spinner:
            spinner = Spinner()
            spinner.update("registering device")

        # Create registration token, in the future, this key will make JWTs directly
        with open(PERSIST +
                  "/comma/id_rsa.pub") as f1, open(PERSIST +
                                                   "/comma/id_rsa") as f2:
            public_key = f1.read()
            private_key = f2.read()

        # Block until we get the imei
        serial = HARDWARE.get_serial()
        start_time = time.monotonic()
        imei1, imei2 = None, None
        while imei1 is None and imei2 is None:
            try:
                imei1, imei2 = HARDWARE.get_imei(0), HARDWARE.get_imei(1)
            except Exception:
                cloudlog.exception("Error getting imei, trying again...")
                time.sleep(1)

            if time.monotonic() - start_time > 60 and show_spinner:
                spinner.update(
                    f"registering device - serial: {serial}, IMEI: ({imei1}, {imei2})"
                )

        params.put("IMEI", imei1)
        params.put("HardwareSerial", serial)

        backoff = 0
        start_time = time.monotonic()
        while True:
            try:
                register_token = jwt.encode(
                    {
                        'register': True,
                        'exp': datetime.utcnow() + timedelta(hours=1)
                    },
                    private_key,
                    algorithm='RS256')
                cloudlog.info("getting pilotauth")
                resp = api_get("v2/pilotauth/",
                               method='POST',
                               timeout=15,
                               imei=imei1,
                               imei2=imei2,
                               serial=serial,
                               public_key=public_key,
                               register_token=register_token)

                if resp.status_code in (402, 403):
                    cloudlog.info(
                        f"Unable to register device, got {resp.status_code}")
                    dongle_id = UNREGISTERED_DONGLE_ID
                else:
                    dongleauth = json.loads(resp.text)
                    dongle_id = dongleauth["dongle_id"]
                break
            except Exception:
                cloudlog.exception("failed to authenticate")
                backoff = min(backoff + 1, 15)
                time.sleep(backoff)

            if time.monotonic() - start_time > 60 and show_spinner:
                spinner.update(
                    f"registering device - serial: {serial}, IMEI: ({imei1}, {imei2})"
                )

        if show_spinner:
            spinner.close()

    if dongle_id:
        params.put("DongleId", dongle_id)
        set_offroad_alert("Offroad_UnofficialHardware",
                          dongle_id == UNREGISTERED_DONGLE_ID)
    return dongle_id
Beispiel #22
0
def main():
  def get_influxdb_line(measurement: str, value: float, timestamp: datetime, tags: dict):
    res = f"{measurement}"
    for k, v in tags.items():
      res += f",{k}={str(v)}"
    res += f" value={value} {int(timestamp.timestamp() * 1e9)}\n"
    return res

  # open statistics socket
  ctx = zmq.Context().instance()
  sock = ctx.socket(zmq.PULL)
  sock.bind(STATS_SOCKET)

  # initialize stats directory
  Path(STATS_DIR).mkdir(parents=True, exist_ok=True)

  # initialize tags
  tags = {
    'dongleId': Params().get("DongleId", encoding='utf-8'),
    'started': False,
    'version': get_short_version(),
    'branch': get_short_branch(),
    'dirty': is_dirty(),
    'origin': get_normalized_origin(),
    'deviceType': HARDWARE.get_device_type(),
  }

  # subscribe to deviceState for started state
  sm = SubMaster(['deviceState'])

  last_flush_time = time.monotonic()
  gauges = {}
  while True:
    started_prev = sm['deviceState'].started
    sm.update()

    # Update metrics
    while True:
      try:
        metric = sock.recv_string(zmq.NOBLOCK)
        try:
          metric_type = metric.split('|')[1]
          metric_name = metric.split(':')[0]
          metric_value = metric.split('|')[0].split(':')[1]

          if metric_type == METRIC_TYPE.GAUGE:
            gauges[metric_name] = metric_value
          else:
            cloudlog.event("unknown metric type", metric_type=metric_type)
        except Exception:
          cloudlog.event("malformed metric", metric=metric)
      except zmq.error.Again:
        break

    # flush when started state changes or after FLUSH_TIME_S
    if (time.monotonic() > last_flush_time + STATS_FLUSH_TIME_S) or (sm['deviceState'].started != started_prev):
      result = ""
      current_time = datetime.utcnow().replace(tzinfo=timezone.utc)
      tags['started'] = sm['deviceState'].started

      for gauge_key in gauges:
        result += get_influxdb_line(f"gauge.{gauge_key}", gauges[gauge_key], current_time, tags)

      # clear intermediate data
      gauges = {}
      last_flush_time = time.monotonic()

      # check that we aren't filling up the drive
      if len(os.listdir(STATS_DIR)) < STATS_DIR_FILE_LIMIT:
        if len(result) > 0:
          stats_path = os.path.join(STATS_DIR, str(int(current_time.timestamp())))
          with atomic_write_in_dir(stats_path) as f:
            f.write(result)
      else:
        cloudlog.error("stats dir full")
Beispiel #23
0
 def do_reboot():
     time.sleep(2)
     HARDWARE.reboot()
Beispiel #24
0
def manager_init() -> None:
  # update system time from panda
  set_time(cloudlog)

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

  params = Params()
  params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START)

  default_params: List[Tuple[str, Union[str, bytes]]] = [
    ("CompletedTrainingVersion", "0"),
    ("DisengageOnAccelerator", "0"),
    ("HasAcceptedTerms", "0"),
    ("OpenpilotEnabledToggle", "1"),
    ("IsMetric", "1"),

    # HKG
    ("LateralControl", "TORQUE"),
    ("UseClusterSpeed", "0"),
    ("LongControlEnabled", "0"),
    ("MadModeEnabled", "1"),
    ("IsLdwsCar", "0"),
    ("LaneChangeEnabled", "0"),
    ("AutoLaneChangeEnabled", "0"),

    ("SccSmootherSlowOnCurves", "0"),
    ("SccSmootherSyncGasPressed", "0"),
    ("StockNaviDecelEnabled", "0"),
    ("KeepSteeringTurnSignals", "0"),
    ("HapticFeedbackWhenSpeedCamera", "0"),
    ("DisableOpFcw", "0"),
    ("ShowDebugUI", "0"),
    ("NewRadarInterface", "0"),
  ]
  if not PC:
    default_params.append(("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8')))

  if params.get_bool("RecordFrontLock"):
    params.put_bool("RecordFront", True)

  if not params.get_bool("DisableRadar_Allow"):
    params.delete("DisableRadar")

  # set unset params
  for k, v in default_params:
    if params.get(k) is None:
      params.put(k, v)

  # is this dashcam?
  if os.getenv("PASSIVE") is not None:
    params.put_bool("Passive", bool(int(os.getenv("PASSIVE", "0"))))

  if params.get("Passive") is None:
    raise Exception("Passive must be set to continue")

  # Create folders needed for msgq
  try:
    os.mkdir("/dev/shm")
  except FileExistsError:
    pass
  except PermissionError:
    print("WARNING: failed to make /dev/shm")

  # set version params
  params.put("Version", get_version())
  params.put("TermsVersion", terms_version)
  params.put("TrainingVersion", training_version)
  params.put("GitCommit", get_commit(default=""))
  params.put("GitBranch", get_short_branch(default=""))
  params.put("GitRemote", get_origin(default=""))

  # set dongle id
  reg_res = register(show_spinner=True)
  if reg_res:
    dongle_id = reg_res
  else:
    serial = params.get("HardwareSerial")
    raise Exception(f"Registration failed for device {serial}")
  os.environ['DONGLE_ID'] = dongle_id  # Needed for swaglog

  if not is_dirty():
    os.environ['CLEAN'] = '1'

  # init logging
  sentry.init(sentry.SentryProject.SELFDRIVE)
  cloudlog.bind_global(dongle_id=dongle_id, version=get_version(), dirty=is_dirty(),
                       device=HARDWARE.get_device_type())
Beispiel #25
0
def getNetworkType():
    return HARDWARE.get_network_type()
Beispiel #26
0
    def calculate(self, health):
        try:
            now = sec_since_boot()

            # If health is None, we're probably not in a car, so we don't care
            if health is None or health.health.hwType == log.HealthData.HwType.unknown:
                with self.integration_lock:
                    self.last_measurement_time = None
                    self.next_pulsed_measurement_time = None
                    self.power_used_uWh = 0
                return

            # Low-pass battery voltage
            self.car_voltage_mV = (
                (health.health.voltage * CAR_VOLTAGE_LOW_PASS_K) +
                (self.car_voltage_mV * (1 - CAR_VOLTAGE_LOW_PASS_K)))

            # Cap the car battery power and save it in a param every 10-ish seconds
            self.car_battery_capacity_uWh = max(self.car_battery_capacity_uWh,
                                                0)
            self.car_battery_capacity_uWh = min(self.car_battery_capacity_uWh,
                                                CAR_BATTERY_CAPACITY_uWh)
            if now - self.last_save_time >= 10:
                put_nonblocking("CarBatteryCapacity",
                                str(int(self.car_battery_capacity_uWh)))
                self.last_save_time = now

            # First measurement, set integration time
            with self.integration_lock:
                if self.last_measurement_time is None:
                    self.last_measurement_time = now
                    return

            if (health.health.ignitionLine or health.health.ignitionCan):
                # If there is ignition, we integrate the charging rate of the car
                with self.integration_lock:
                    self.power_used_uWh = 0
                    integration_time_h = (now -
                                          self.last_measurement_time) / 3600
                    if integration_time_h < 0:
                        raise ValueError(
                            f"Negative integration time: {integration_time_h}h"
                        )
                    self.car_battery_capacity_uWh += (CAR_CHARGING_RATE_W *
                                                      1e6 * integration_time_h)
                    self.last_measurement_time = now
            else:
                # No ignition, we integrate the offroad power used by the device
                is_uno = health.health.hwType == log.HealthData.HwType.uno
                # Get current power draw somehow
                current_power = HARDWARE.get_current_power_draw()
                if current_power is not None:
                    pass
                elif HARDWARE.get_battery_status() == 'Discharging':
                    # If the battery is discharging, we can use this measurement
                    # On C2: this is low by about 10-15%, probably mostly due to UNO draw not being factored in
                    current_power = ((get_battery_voltage() / 1000000) *
                                     (get_battery_current() / 1000000))
                elif (health.health.hwType in [
                        log.HealthData.HwType.whitePanda,
                        log.HealthData.HwType.greyPanda
                ]) and (health.health.current > 1):
                    # If white/grey panda, use the integrated current measurements if the measurement is not 0
                    # If the measurement is 0, the current is 400mA or greater, and out of the measurement range of the panda
                    # This seems to be accurate to about 5%
                    current_power = (
                        PANDA_OUTPUT_VOLTAGE *
                        panda_current_to_actual_current(health.health.current))
                elif (self.next_pulsed_measurement_time is not None) and (
                        self.next_pulsed_measurement_time <= now):
                    # TODO: Figure out why this is off by a factor of 3/4???
                    FUDGE_FACTOR = 1.33

                    # Turn off charging for about 10 sec in a thread that does not get killed on SIGINT, and perform measurement here to avoid blocking thermal
                    def perform_pulse_measurement(now):
                        try:
                            HARDWARE.set_battery_charging(False)
                            time.sleep(5)

                            # Measure for a few sec to get a good average
                            voltages = []
                            currents = []
                            for _ in range(6):
                                voltages.append(HARDWARE.get_battery_voltage())
                                currents.append(HARDWARE.get_battery_current())
                                time.sleep(1)
                            current_power = ((mean(voltages) / 1000000) *
                                             (mean(currents) / 1000000))

                            self._perform_integration(
                                now, current_power * FUDGE_FACTOR)

                            # Enable charging again
                            HARDWARE.set_battery_charging(True)
                        except Exception:
                            cloudlog.exception(
                                "Pulsed power measurement failed")

                    # Start pulsed measurement and return
                    threading.Thread(target=perform_pulse_measurement,
                                     args=(now, )).start()
                    self.next_pulsed_measurement_time = None
                    return

                elif self.next_pulsed_measurement_time is None and not is_uno:
                    # On a charging EON with black panda, or drawing more than 400mA out of a white/grey one
                    # Only way to get the power draw is to turn off charging for a few sec and check what the discharging rate is
                    # We shouldn't do this very often, so make sure it has been some long-ish random time interval
                    self.next_pulsed_measurement_time = now + random.randint(
                        120, 180)
                    return
                else:
                    # Do nothing
                    return

                # Do the integration
                self._perform_integration(now, current_power)
        except Exception:
            cloudlog.exception("Power monitoring calculation failed")
Beispiel #27
0
def hw_state_thread(end_event, hw_queue):
    """Handles non critical hardware state, and sends over queue"""
    count = 0
    registered_count = 0
    prev_hw_state = None

    modem_version = None
    modem_nv = None
    modem_configured = False

    while not end_event.is_set():
        # these are expensive calls. update every 10s
        if (count % int(10. / DT_TRML)) == 0:
            try:
                network_type = HARDWARE.get_network_type()
                modem_temps = HARDWARE.get_modem_temperatures()
                if len(modem_temps) == 0 and prev_hw_state is not None:
                    modem_temps = prev_hw_state.modem_temps

                # Log modem version once
                if TICI and ((modem_version is None) or (modem_nv is None)):
                    modem_version = HARDWARE.get_modem_version()  # pylint: disable=assignment-from-none
                    modem_nv = HARDWARE.get_modem_nv()  # pylint: disable=assignment-from-none

                    if (modem_version is not None) and (modem_nv is not None):
                        cloudlog.event("modem version",
                                       version=modem_version,
                                       nv=modem_nv)

                hw_state = HardwareState(
                    network_type=network_type,
                    network_metered=HARDWARE.get_network_metered(network_type),
                    network_strength=HARDWARE.get_network_strength(
                        network_type),
                    network_info=HARDWARE.get_network_info(),
                    nvme_temps=HARDWARE.get_nvme_temperatures(),
                    modem_temps=modem_temps,
                    wifi_address=HARDWARE.get_ip_address(),
                )

                try:
                    hw_queue.put_nowait(hw_state)
                except queue.Full:
                    pass

                if TICI and (hw_state.network_info
                             is not None) and (hw_state.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 {hw_state.network_info}. nmcli conn up lte"
                    )
                    os.system("nmcli conn up lte")
                    registered_count = 0

                # TODO: remove this once the config is in AGNOS
                if not modem_configured and len(HARDWARE.get_sim_info().get(
                        'sim_id', '')) > 0:
                    cloudlog.warning("configuring modem")
                    HARDWARE.configure_modem()
                    modem_configured = True

                prev_hw_state = hw_state
            except Exception:
                cloudlog.exception("Error getting hardware state")

        count += 1
        time.sleep(DT_TRML)
Beispiel #28
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.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
        }

        # 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)
        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
Beispiel #29
0
  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',
                                     '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, HwType.dos]
    print("Waiting for CAN messages...")
    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) 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, 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 not car_recognized:
      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
Beispiel #30
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.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.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
        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_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'
        # 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.steerControlType == car.CarParams.SteerControlType.angle:
            self.LaC = LatControlAngle(self.CP)
        elif 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.sm['liveParameters'].valid = True

        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)
        elif self.read_only:
            self.events.add(EventName.dashcamMode, 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