Ejemplo n.º 1
0
def thermald_thread():

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

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

    fan_speed = 0
    count = 0

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

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

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

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

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

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

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

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

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

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

        msg = read_thermal(thermal_config)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # **** starting logic ****

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

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

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

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

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

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

        startup_conditions["up_to_date"] = params.get(
            "Offroad_ConnectivityNeeded") is None or params.get_bool(
                "DisableUpdates") 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
        startup_conditions[
            "device_temp_good"] = thermal_status < ThermalStatus.danger
        set_offroad_alert_if_changed(
            "Offroad_TemperatureTooHigh",
            (not startup_conditions["device_temp_good"]))

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

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

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

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

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

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

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

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

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

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

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

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

        should_start_prev = should_start
        startup_conditions_prev = startup_conditions.copy()

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

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

        count += 1
Ejemplo n.º 2
0
def python_replay_process(cfg, lr):
    sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub]
    pub_sockets = [s for s in cfg.pub_sub.keys() if s != 'can']

    fsm = FakeSubMaster(pub_sockets)
    fpm = FakePubMaster(sub_sockets)
    args = (fsm, fpm)
    if 'can' in list(cfg.pub_sub.keys()):
        can_sock = FakeSocket()
        args = (fsm, fpm, can_sock)

    all_msgs = sorted(lr, key=lambda msg: msg.logMonoTime)
    pub_msgs = [
        msg for msg in all_msgs if msg.which() in list(cfg.pub_sub.keys())
    ]

    params = Params()
    params.clear_all()
    params.manager_start()
    params.put_bool("OpenpilotEnabledToggle", True)
    params.put_bool("Passive", False)
    params.put_bool("CommunityFeaturesToggle", True)

    os.environ['NO_RADAR_SLEEP'] = "1"
    os.environ['SKIP_FW_QUERY'] = ""
    os.environ['FINGERPRINT'] = ""
    for msg in lr:
        if msg.which() == 'carParams':
            if len(msg.carParams.carFw) and (msg.carParams.carFingerprint
                                             in FW_VERSIONS):
                params.put("CarParamsCache",
                           msg.carParams.as_builder().to_bytes())
            else:
                os.environ['SKIP_FW_QUERY'] = "1"
                os.environ['FINGERPRINT'] = msg.carParams.carFingerprint

    assert (type(managed_processes[cfg.proc_name]) is PythonProcess)
    managed_processes[cfg.proc_name].prepare()
    mod = importlib.import_module(managed_processes[cfg.proc_name].module)

    thread = threading.Thread(target=mod.main, args=args)
    thread.daemon = True
    thread.start()

    if cfg.init_callback is not None:
        if 'can' not in list(cfg.pub_sub.keys()):
            can_sock = None
        cfg.init_callback(all_msgs, fsm, can_sock)

    CP = car.CarParams.from_bytes(params.get("CarParams", block=True))

    # wait for started process to be ready
    if 'can' in list(cfg.pub_sub.keys()):
        can_sock.wait_for_recv()
    else:
        fsm.wait_for_update()

    log_msgs, msg_queue = [], []
    for msg in tqdm(pub_msgs, disable=CI):
        if cfg.should_recv_callback is not None:
            recv_socks, should_recv = cfg.should_recv_callback(
                msg, CP, cfg, fsm)
        else:
            recv_socks = [
                s for s in cfg.pub_sub[msg.which()]
                if (fsm.frame + 1) % int(service_list[msg.which()].frequency /
                                         service_list[s].frequency) == 0
            ]
            should_recv = bool(len(recv_socks))

        if msg.which() == 'can':
            can_sock.send(msg.as_builder().to_bytes())
        else:
            msg_queue.append(msg.as_builder())

        if should_recv:
            fsm.update_msgs(0, msg_queue)
            msg_queue = []

            recv_cnt = len(recv_socks)
            while recv_cnt > 0:
                m = fpm.wait_for_msg()
                log_msgs.append(m)
                recv_cnt -= m.which() in recv_socks
    return log_msgs
Ejemplo n.º 3
0
def thermald_thread():

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

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

    fan_speed = 0
    count = 0

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

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

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

    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)

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

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

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

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

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

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

            # Handle disconnect
            if pandaState_prev is not None:
                if pandaState.pandaState.pandaType == log.PandaState.PandaType.unknown and \
                  pandaState_prev.pandaState.pandaType != log.PandaState.PandaType.unknown:
                    params.clear_all(ParamKeyType.CLEAR_ON_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)
                network_info = HARDWARE.get_network_info()  # pylint: disable=assignment-from-none

                wifiIpAddress = HARDWARE.get_ip_address()

                # 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(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.wifiIpAddress = wifiIpAddress
        if network_info is not None:
            msg.deviceState.networkInfo = network_info

        msg.deviceState.batteryPercent = HARDWARE.get_battery_capacity()
        msg.deviceState.batteryStatus = HARDWARE.get_battery_status()
        msg.deviceState.batteryCurrent = HARDWARE.get_battery_current()
        msg.deviceState.batteryVoltage = HARDWARE.get_battery_voltage()
        msg.deviceState.usbOnline = HARDWARE.get_usb_present()

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

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

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

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

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

        # **** starting logic ****

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

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

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

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

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

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

        #startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get_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()

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

        # Set EON charging disable
        # based on kegman, 차량 저압배터리의 전압, 이온 배터리 퍼센티지,
        if EON:
            from selfdrive.thermald.eon_battery_manager import setEONChargingStatus
            setEONChargingStatus(power_monitor.car_voltage_mV,
                                 msg.deviceState.batteryPercent)

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

        # dp - auto shutdown
        if off_ts is not None:
            shutdown_sec = 240
            sec_now = sec_since_boot() - off_ts
            if (shutdown_sec - 5) < sec_now:
                msg.deviceState.chargingDisabled = True
            if shutdown_sec < sec_now:
                time.sleep(5)
                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()

        # 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
Ejemplo n.º 4
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 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())
Ejemplo n.º 5
0
def main() -> NoReturn:
    first_run = True
    params = Params()

    while True:
        try:
            params.delete("PandaSignatures")

            # Flash all Pandas in DFU mode
            for p in PandaDFU.list():
                cloudlog.info(
                    f"Panda in DFU mode found, flashing recovery {p}")
                PandaDFU(p).recover()
            time.sleep(1)

            panda_serials = Panda.list()
            if len(panda_serials) == 0:
                if first_run:
                    cloudlog.info("Resetting internal panda")
                    HARDWARE.reset_internal_panda()
                    time.sleep(2)  # wait to come back up
                continue

            cloudlog.info(
                f"{len(panda_serials)} panda(s) found, connecting - {panda_serials}"
            )

            # Flash pandas
            pandas = []
            for serial in panda_serials:
                pandas.append(flash_panda(serial))

            # check health for lost heartbeat
            for panda in pandas:
                health = panda.health()
                if health["heartbeat_lost"]:
                    params.put_bool("PandaHeartbeatLost", True)
                    cloudlog.event("heartbeat lost",
                                   deviceState=health,
                                   serial=panda.get_usb_serial())

                #if first_run:
                #  cloudlog.info(f"Resetting panda {panda.get_usb_serial()}")
                #  panda.reset()

            # sort pandas to have deterministic order
            pandas.sort(key=cmp_to_key(panda_sort_cmp))
            panda_serials = list(map(lambda p: p.get_usb_serial(), pandas))

            # log panda fw versions
            params.put("PandaSignatures",
                       b','.join(p.get_signature() for p in pandas))

            # close all pandas
            for p in pandas:
                p.close()
        except (usb1.USBErrorNoDevice, usb1.USBErrorPipe):
            # a panda was disconnected while setting everything up. let's try again
            cloudlog.exception("Panda USB exception while setting up")
            continue

        first_run = False

        # run boardd with all connected serials as arguments
        os.environ['MANAGER_DAEMON'] = 'boardd'
        os.chdir(os.path.join(BASEDIR, "selfdrive/boardd"))
        subprocess.run(["./boardd", *panda_serials], check=True)
Ejemplo n.º 6
0
def manager_init():

    # update system time from panda
    set_time(cloudlog)

    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 TICI:
        default_params.append(("EnableLteOnroad", "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
    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())
Ejemplo n.º 7
0
def regen_segment(lr, frs=None, outdir=FAKEDATA):
    lr = list(lr)
    if frs is None:
        frs = dict()

    # setup env
    params = Params()
    params.clear_all()
    params.put_bool("Passive", False)
    params.put_bool("OpenpilotEnabledToggle", True)

    os.environ["LOG_ROOT"] = outdir
    os.environ["REPLAY"] = "1"

    os.environ['SKIP_FW_QUERY'] = ""
    os.environ['FINGERPRINT'] = ""

    # TODO: remove after getting new route for mazda
    migration = {
        "Mazda CX-9 2021": "MAZDA CX-9 2021",
    }

    for msg in lr:
        if msg.which() == 'carParams':
            car_fingerprint = migration.get(msg.carParams.carFingerprint,
                                            msg.carParams.carFingerprint)
            if len(msg.carParams.carFw) and (car_fingerprint in FW_VERSIONS):
                params.put("CarParamsCache",
                           msg.carParams.as_builder().to_bytes())
            else:
                os.environ['SKIP_FW_QUERY'] = "1"
                os.environ['FINGERPRINT'] = car_fingerprint
        elif msg.which() == 'liveCalibration':
            params.put("CalibrationParams", msg.as_builder().to_bytes())

    vs, cam_procs = replay_cameras(lr, frs)

    fake_daemons = {
        'sensord': [
            multiprocessing.Process(target=replay_sensor_events,
                                    args=('sensorEvents', lr)),
        ],
        'pandad': [
            multiprocessing.Process(target=replay_service, args=('can', lr)),
            multiprocessing.Process(target=replay_service,
                                    args=('ubloxRaw', lr)),
            multiprocessing.Process(target=replay_panda_states,
                                    args=('pandaStates', lr)),
        ],
        'managerState': [
            multiprocessing.Process(target=replay_manager_state,
                                    args=('managerState', lr)),
        ],
        'thermald': [
            multiprocessing.Process(target=replay_device_state,
                                    args=('deviceState', lr)),
        ],
        'camerad': [
            *cam_procs,
        ],
    }

    try:
        # start procs up
        ignore = list(
            fake_daemons.keys()) + ['ui', 'manage_athenad', 'uploader']
        ensure_running(managed_processes.values(),
                       started=True,
                       not_run=ignore)
        for procs in fake_daemons.values():
            for p in procs:
                p.start()

        for _ in tqdm(range(60)):
            # ensure all procs are running
            for d, procs in fake_daemons.items():
                for p in procs:
                    if not p.is_alive():
                        raise Exception(f"{d}'s {p.name} died")
            time.sleep(1)
    finally:
        # kill everything
        for p in managed_processes.values():
            p.stop()
        for procs in fake_daemons.values():
            for p in procs:
                p.terminate()

    del vs

    r = params.get("CurrentRoute", encoding='utf-8')
    return os.path.join(outdir, r + "--0")
Ejemplo n.º 8
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"),
        ("HasAcceptedTerms", "0"),
        ("OpenpilotEnabledToggle", "1"),
        ("CommunityFeaturesToggle", "1"),
        ("IsMetric", "1"),

        # HKG
        ("UseClusterSpeed", "0"),
        ("LongControlEnabled", "0"),
        ("MadModeEnabled", "1"),
        ("IsLdwsCar", "0"),
        ("LaneChangeEnabled", "0"),
        ("AutoLaneChangeEnabled", "0"),
        ("SccSmootherSlowOnCurves", "0"),
        ("SccSmootherSyncGasPressed", "0"),
        ("StockNaviDecelEnabled", "0"),
        ("KeepSteeringTurnSignals", "0"),
        ("WarningOverSpeedLimit", "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())
Ejemplo n.º 9
0
class TestUpdated(unittest.TestCase):
    def setUp(self):
        self.updated_proc = None

        self.tmp_dir = tempfile.TemporaryDirectory()
        org_dir = os.path.join(self.tmp_dir.name, "commaai")

        self.basedir = os.path.join(org_dir, "openpilot")
        self.git_remote_dir = os.path.join(org_dir, "openpilot_remote")
        self.staging_dir = os.path.join(org_dir, "safe_staging")
        for d in [
                org_dir, self.basedir, self.git_remote_dir, self.staging_dir
        ]:
            os.mkdir(d)

        self.neos_version = os.path.join(org_dir, "neos_version")
        self.neosupdate_dir = os.path.join(org_dir, "neosupdate")
        with open(self.neos_version, "w") as f:
            v = subprocess.check_output(
                r"bash -c 'source launch_env.sh && echo $REQUIRED_NEOS_VERSION'",
                cwd=BASEDIR,
                shell=True,
                encoding='utf8').strip()
            f.write(v)

        self.upper_dir = os.path.join(self.staging_dir, "upper")
        self.merged_dir = os.path.join(self.staging_dir, "merged")
        self.finalized_dir = os.path.join(self.staging_dir, "finalized")

        # setup local submodule remotes
        submodules = subprocess.check_output(
            "git submodule --quiet foreach 'echo $name'",
            shell=True,
            cwd=BASEDIR,
            encoding='utf8').split()
        for s in submodules:
            sub_path = os.path.join(org_dir, s.split("_repo")[0])
            self._run(f"git clone {s} {sub_path}.git", cwd=BASEDIR)

        # setup two git repos, a remote and one we'll run updated in
        self._run([
            f"git clone {BASEDIR} {self.git_remote_dir}",
            f"git clone {self.git_remote_dir} {self.basedir}",
            f"cd {self.basedir} && git submodule init && git submodule update",
            f"cd {self.basedir} && scons -j{os.cpu_count()} cereal/ common/"
        ])

        self.params = Params(os.path.join(self.basedir, "persist/params"))
        self.params.clear_all()
        os.sync()

    def tearDown(self):
        try:
            if self.updated_proc is not None:
                self.updated_proc.terminate()
                self.updated_proc.wait(30)
        except Exception as e:
            print(e)
        self.tmp_dir.cleanup()

    # *** test helpers ***

    def _run(self, cmd, cwd=None):
        if not isinstance(cmd, list):
            cmd = (cmd, )

        for c in cmd:
            subprocess.check_output(c, cwd=cwd, shell=True)

    def _get_updated_proc(self):
        os.environ["PYTHONPATH"] = self.basedir
        os.environ["GIT_AUTHOR_NAME"] = "testy tester"
        os.environ["GIT_COMMITTER_NAME"] = "testy tester"
        os.environ["GIT_AUTHOR_EMAIL"] = "*****@*****.**"
        os.environ["GIT_COMMITTER_EMAIL"] = "*****@*****.**"
        os.environ["UPDATER_TEST_IP"] = "localhost"
        os.environ["UPDATER_LOCK_FILE"] = os.path.join(self.tmp_dir.name,
                                                       "updater.lock")
        os.environ["UPDATER_STAGING_ROOT"] = self.staging_dir
        os.environ["UPDATER_NEOS_VERSION"] = self.neos_version
        os.environ["UPDATER_NEOSUPDATE_DIR"] = self.neosupdate_dir
        updated_path = os.path.join(self.basedir, "selfdrive/updated.py")
        return subprocess.Popen(updated_path, env=os.environ)

    def _start_updater(self, offroad=True, nosleep=False):
        self.params.put_bool("IsOffroad", offroad)
        self.updated_proc = self._get_updated_proc()
        if not nosleep:
            time.sleep(1)

    def _update_now(self):
        self.updated_proc.send_signal(signal.SIGHUP)

    # TODO: this should be implemented in params
    def _read_param(self, key, timeout=1):
        ret = None
        start_time = time.monotonic()
        while ret is None:
            ret = self.params.get(key, encoding='utf8')
            if time.monotonic() - start_time > timeout:
                break
            time.sleep(0.01)
        return ret

    def _wait_for_update(self, timeout=30, clear_param=False):
        if clear_param:
            self.params.delete("LastUpdateTime")

        self._update_now()
        t = self._read_param("LastUpdateTime", timeout=timeout)
        if t is None:
            raise Exception("timed out waiting for update to complete")

    def _make_commit(self):
        all_dirs, all_files = [], []
        for root, dirs, files in os.walk(self.git_remote_dir):
            if ".git" in root:
                continue
            for d in dirs:
                all_dirs.append(os.path.join(root, d))
            for f in files:
                all_files.append(os.path.join(root, f))

        # make a new dir and some new files
        new_dir = os.path.join(self.git_remote_dir, "this_is_a_new_dir")
        os.mkdir(new_dir)
        for _ in range(random.randrange(5, 30)):
            for d in (new_dir, random.choice(all_dirs)):
                with tempfile.NamedTemporaryFile(dir=d, delete=False) as f:
                    f.write(os.urandom(random.randrange(1, 1000000)))

        # modify some files
        for f in random.sample(all_files, random.randrange(5, 50)):
            with open(f, "w+") as ff:
                txt = ff.readlines()
                ff.seek(0)
                for line in txt:
                    ff.write(line[::-1])

        # remove some files
        for f in random.sample(all_files, random.randrange(5, 50)):
            os.remove(f)

        # remove some dirs
        for d in random.sample(all_dirs, random.randrange(1, 10)):
            shutil.rmtree(d)

        # commit the changes
        self._run([
            "git add -A",
            "git commit -m 'an update'",
        ],
                  cwd=self.git_remote_dir)

    def _check_update_state(self, update_available):
        # make sure LastUpdateTime is recent
        t = self._read_param("LastUpdateTime")
        last_update_time = datetime.datetime.fromisoformat(t)
        td = datetime.datetime.utcnow() - last_update_time
        self.assertLess(td.total_seconds(), 10)
        self.params.delete("LastUpdateTime")

        # wait a bit for the rest of the params to be written
        time.sleep(0.1)

        # check params
        update = self._read_param("UpdateAvailable")
        self.assertEqual(update == "1", update_available,
                         f"UpdateAvailable: {repr(update)}")
        self.assertEqual(self._read_param("UpdateFailedCount"), "0")

        # TODO: check that the finalized update actually matches remote
        # check the .overlay_init and .overlay_consistent flags
        self.assertTrue(
            os.path.isfile(os.path.join(self.basedir, ".overlay_init")))
        self.assertEqual(
            os.path.isfile(
                os.path.join(self.finalized_dir, ".overlay_consistent")),
            update_available)

    # *** test cases ***

    # Run updated for 100 cycles with no update
    def test_no_update(self):
        self._start_updater()
        for _ in range(100):
            self._wait_for_update(clear_param=True)
            self._check_update_state(False)

    # Let the updater run with no update for a cycle, then write an update
    def test_update(self):
        self._start_updater()

        # run for a cycle with no update
        self._wait_for_update(clear_param=True)
        self._check_update_state(False)

        # write an update to our remote
        self._make_commit()

        # run for a cycle to get the update
        self._wait_for_update(timeout=60, clear_param=True)
        self._check_update_state(True)

        # run another cycle with no update
        self._wait_for_update(clear_param=True)
        self._check_update_state(True)

    # Let the updater run for 10 cycles, and write an update every cycle
    @unittest.skip("need to make this faster")
    def test_update_loop(self):
        self._start_updater()

        # run for a cycle with no update
        self._wait_for_update(clear_param=True)
        for _ in range(10):
            time.sleep(0.5)
            self._make_commit()
            self._wait_for_update(timeout=90, clear_param=True)
            self._check_update_state(True)

    # Test overlay re-creation after tracking a new file in basedir's git
    def test_overlay_reinit(self):
        self._start_updater()

        overlay_init_fn = os.path.join(self.basedir, ".overlay_init")

        # run for a cycle with no update
        self._wait_for_update(clear_param=True)
        self.params.delete("LastUpdateTime")
        first_mtime = os.path.getmtime(overlay_init_fn)

        # touch a file in the basedir
        self._run("touch new_file && git add new_file", cwd=self.basedir)

        # run another cycle, should have a new mtime
        self._wait_for_update(clear_param=True)
        second_mtime = os.path.getmtime(overlay_init_fn)
        self.assertTrue(first_mtime != second_mtime)

        # run another cycle, mtime should be same as last cycle
        self._wait_for_update(clear_param=True)
        new_mtime = os.path.getmtime(overlay_init_fn)
        self.assertTrue(second_mtime == new_mtime)

    # Make sure updated exits if another instance is running
    def test_multiple_instances(self):
        # start updated and let it run for a cycle
        self._start_updater()
        time.sleep(1)
        self._wait_for_update(clear_param=True)

        # start another instance
        second_updated = self._get_updated_proc()
        ret_code = second_updated.wait(timeout=5)
        self.assertTrue(ret_code is not None)

    # *** test cases with NEOS updates ***

    # Run updated with no update, make sure it clears the old NEOS update
    def test_clear_neos_cache(self):
        # make the dir and some junk files
        os.mkdir(self.neosupdate_dir)
        for _ in range(15):
            with tempfile.NamedTemporaryFile(dir=self.neosupdate_dir,
                                             delete=False) as f:
                f.write(os.urandom(random.randrange(1, 1000000)))

        self._start_updater()
        self._wait_for_update(clear_param=True)
        self._check_update_state(False)
        self.assertFalse(os.path.isdir(self.neosupdate_dir))

    # Let the updater run with no update for a cycle, then write an update
    @unittest.skip("TODO: only runs on device")
    def test_update_with_neos_update(self):
        # bump the NEOS version and commit it
        self._run([
            "echo 'export REQUIRED_NEOS_VERSION=3' >> launch_env.sh",
            "git -c user.name='testy' -c user.email='*****@*****.**' \
       commit -am 'a neos update'",
        ],
                  cwd=self.git_remote_dir)

        # run for a cycle to get the update
        self._start_updater()
        self._wait_for_update(timeout=60, clear_param=True)
        self._check_update_state(True)

        # TODO: more comprehensive check
        self.assertTrue(os.path.isdir(self.neosupdate_dir))
Ejemplo n.º 10
0
class TestParams(unittest.TestCase):
    def setUp(self):
        self.tmpdir = tempfile.mkdtemp()
        print("using", self.tmpdir)
        self.params = Params(self.tmpdir)

    def tearDown(self):
        shutil.rmtree(self.tmpdir)

    def test_params_put_and_get(self):
        self.params.put("DongleId", "cb38263377b873ee")
        assert self.params.get("DongleId") == b"cb38263377b873ee"

    def test_params_non_ascii(self):
        st = b"\xe1\x90\xff"
        self.params.put("CarParams", st)
        assert self.params.get("CarParams") == st

    def test_params_get_cleared_manager_start(self):
        self.params.put("CarParams", "test")
        self.params.put("DongleId", "cb38263377b873ee")
        assert self.params.get("CarParams") == b"test"
        self.params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START)
        assert self.params.get("CarParams") is None
        assert self.params.get("DongleId") is not None

    def test_params_two_things(self):
        self.params.put("DongleId", "bob")
        self.params.put("AthenadPid", "123")
        assert self.params.get("DongleId") == b"bob"
        assert self.params.get("AthenadPid") == b"123"

    def test_params_get_block(self):
        def _delayed_writer():
            time.sleep(0.1)
            self.params.put("CarParams", "test")

        threading.Thread(target=_delayed_writer).start()
        assert self.params.get("CarParams") is None
        assert self.params.get("CarParams", True) == b"test"

    def test_params_unknown_key_fails(self):
        with self.assertRaises(UnknownKeyName):
            self.params.get("swag")

        with self.assertRaises(UnknownKeyName):
            self.params.get_bool("swag")

        with self.assertRaises(UnknownKeyName):
            self.params.put("swag", "abc")

        with self.assertRaises(UnknownKeyName):
            self.params.put_bool("swag", True)

    def test_delete_not_there(self):
        assert self.params.get("CarParams") is None
        self.params.delete("CarParams")
        assert self.params.get("CarParams") is None

    def test_get_bool(self):
        self.params.delete("IsMetric")
        self.assertFalse(self.params.get_bool("IsMetric"))

        self.params.put_bool("IsMetric", True)
        self.assertTrue(self.params.get_bool("IsMetric"))

        self.params.put_bool("IsMetric", False)
        self.assertFalse(self.params.get_bool("IsMetric"))

        self.params.put("IsMetric", "1")
        self.assertTrue(self.params.get_bool("IsMetric"))

        self.params.put("IsMetric", "0")
        self.assertFalse(self.params.get_bool("IsMetric"))

    def test_put_non_blocking_with_get_block(self):
        q = Params(self.tmpdir)

        def _delayed_writer():
            time.sleep(0.1)
            put_nonblocking("CarParams", "test", self.tmpdir)

        threading.Thread(target=_delayed_writer).start()
        assert q.get("CarParams") is None
        assert q.get("CarParams", True) == b"test"
Ejemplo n.º 11
0
    def test_loopback(self):
        # wait for boardd to init
        time.sleep(2)

        with Timeout(60, "boardd didn't start"):
            sm = messaging.SubMaster(['pandaStates'])
            while sm.rcv_frame['pandaStates'] < 1 and len(
                    sm['pandaStates']) == 0:
                sm.update(1000)

        num_pandas = len(sm['pandaStates'])
        if TICI:
            self.assertGreater(num_pandas, 1,
                               "connect another panda for multipanda tests")

        # boardd blocks on CarVin and CarParams
        cp = car.CarParams.new_message()

        safety_config = car.CarParams.SafetyConfig.new_message()
        safety_config.safetyModel = car.CarParams.SafetyModel.allOutput
        cp.safetyConfigs = [safety_config] * num_pandas

        params = Params()
        params.put("CarVin", b"0" * 17)
        params.put_bool("ControlsReady", True)
        params.put("CarParams", cp.to_bytes())

        sendcan = messaging.pub_sock('sendcan')
        can = messaging.sub_sock('can', conflate=False, timeout=100)
        time.sleep(0.2)

        n = 1000
        for i in range(n):
            self.spinner.update(f"boardd loopback {i}/{n}")

            sent_msgs = defaultdict(set)
            for _ in range(random.randrange(10)):
                to_send = []
                for __ in range(random.randrange(100)):
                    bus = random.choice(
                        [b for b in range(3 * num_pandas) if b % 4 != 3])
                    addr = random.randrange(1, 1 << 29)
                    dat = bytes([
                        random.getrandbits(8)
                        for _ in range(random.randrange(1, 9))
                    ])
                    sent_msgs[bus].add((addr, dat))
                    to_send.append(make_can_msg(addr, dat, bus))
                sendcan.send(can_list_to_can_capnp(to_send, msgtype='sendcan'))

            for _ in range(100 * 2):
                recvd = messaging.drain_sock(can, wait_for_one=True)
                for msg in recvd:
                    for m in msg.can:
                        if m.src >= 128:
                            key = (m.address, m.dat)
                            assert key in sent_msgs[
                                m.src -
                                128], f"got unexpected msg: {m.src=} {m.address=} {m.dat=}"
                            sent_msgs[m.src - 128].discard(key)

                if all(len(v) == 0 for v in sent_msgs.values()):
                    break

            # if a set isn't empty, messages got dropped
            for bus in sent_msgs.keys():
                assert not len(
                    sent_msgs[bus]
                ), f"loop {i}: bus {bus} missing {len(sent_msgs[bus])} messages"
Ejemplo n.º 12
0
def manager_init():

    # update system time from panda
    set_time(cloudlog)

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

    default_params = [
        ("CompletedTrainingVersion", "0"),
        ("HasAcceptedTerms", "0"),
        ("HandsOnWheelMonitoring", "0"),
        ("OpenpilotEnabledToggle", "1"),
        ("ShowDebugUI", "1"),
        ("SpeedLimitControl", "1"),
        ("SpeedLimitPercOffset", "1"),
        ("TurnSpeedControl", "1"),
        ("TurnVisionControl", "1"),
        ("GMAutoHold", "1"),
        ("CruiseSpeedOffset", "1"),
        ("StockSpeedAdjust", "1"),
        ("CustomSounds", "0"),
        ("SilentEngageDisengage", "0"),
        ("AccelModeButton", "0"),
        ("AccelMode", "0"),
        ("EndToEndToggle", "1"),
        ("LanelessMode", "2"),
        ("NudgelessLaneChange", "0"),
        ("Coasting", "0"),
        ("RegenBraking", "0"),
        ("OnePedalMode", "0"),
        ("OnePedalModeSimple", "0"),
        ("OnePedalModeEngageOnGas", "0"),
        ("OnePedalBrakeMode", "0"),
        ("OnePedalPauseBlinkerSteering", "1"),
        ("FollowLevel", "2"),
        ("CoastingBrakeOverSpeed", "0"),
        ("FrictionBrakePercent", "0"),
        ("BrakeIndicator", "1"),
        ("DisableOnroadUploads", "0"),
        ("MeasureNumSlots", "0"),
        ("MeasureSlot00", "12"),  # right column: percent grade
        ("MeasureSlot01", "10"),  # altitude
        ("MeasureSlot02", "2"),  # steering torque
        ("MeasureSlot03", "3"),  # engine rpm
        ("MeasureSlot04", "7"),  # engine coolant temperature
        ("MeasureSlot05", "16"),  # lead dist [s]
        ("MeasureSlot06", "15"),  # lead dist [m]
        ("MeasureSlot07", "20"),  # lead rel spd [mph]
        ("MeasureSlot08", "21"),  # lead spd [mph]
        ("MeasureSlot09", "23"),  # device cpu percent and temp
    ]
    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)

    # parameters set by Enviroment Varables
    if os.getenv("HANDSMONITORING") is not None:
        params.put_bool("HandsOnWheelMonitoring",
                        bool(int(os.getenv("HANDSMONITORING"))))

    # 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())
Ejemplo n.º 13
0
def regen_segment(lr, frs=None, outdir=FAKEDATA):

    lr = list(lr)
    if frs is None:
        frs = dict()

    # setup env
    params = Params()
    params.clear_all()
    params.put_bool("Passive", False)
    params.put_bool("OpenpilotEnabledToggle", True)
    params.put_bool("CommunityFeaturesToggle", True)
    params.put_bool("CommunityFeaturesToggle", True)
    cal = messaging.new_message('liveCalibration')
    cal.liveCalibration.validBlocks = 20
    cal.liveCalibration.rpyCalib = [0.0, 0.0, 0.0]
    params.put("CalibrationParams", cal.to_bytes())

    os.environ["LOG_ROOT"] = outdir
    os.environ["SIMULATION"] = "1"

    os.environ['SKIP_FW_QUERY'] = ""
    os.environ['FINGERPRINT'] = ""
    for msg in lr:
        if msg.which() == 'carParams':
            car_fingerprint = msg.carParams.carFingerprint
            if len(msg.carParams.carFw) and (car_fingerprint in FW_VERSIONS):
                params.put("CarParamsCache",
                           msg.carParams.as_builder().to_bytes())
            else:
                os.environ['SKIP_FW_QUERY'] = "1"
                os.environ['FINGERPRINT'] = car_fingerprint

    #TODO: init car, make sure starts engaged when segment is engaged

    fake_daemons = {
        'sensord': [
            multiprocessing.Process(target=replay_service,
                                    args=('sensorEvents', lr)),
        ],
        'pandad': [
            multiprocessing.Process(target=replay_service, args=('can', lr)),
            multiprocessing.Process(target=replay_service,
                                    args=('pandaStates', lr)),
        ],
        #'managerState': [
        #  multiprocessing.Process(target=replay_service, args=('managerState', lr)),
        #],
        'thermald': [
            multiprocessing.Process(target=replay_service,
                                    args=('deviceState', lr)),
        ],
        'camerad': [
            *replay_cameras(lr, frs),
        ],

        # TODO: fix these and run them
        'paramsd': [
            multiprocessing.Process(target=replay_service,
                                    args=('liveParameters', lr)),
        ],
        'locationd': [
            multiprocessing.Process(target=replay_service,
                                    args=('liveLocationKalman', lr)),
        ],
    }

    try:
        # start procs up
        ignore = list(
            fake_daemons.keys()) + ['ui', 'manage_athenad', 'uploader']
        ensure_running(managed_processes.values(),
                       started=True,
                       not_run=ignore)
        for procs in fake_daemons.values():
            for p in procs:
                p.start()

        for _ in tqdm(range(60)):
            # ensure all procs are running
            for d, procs in fake_daemons.items():
                for p in procs:
                    if not p.is_alive():
                        raise Exception(f"{d}'s {p.name} died")
            time.sleep(1)
    finally:
        # kill everything
        for p in managed_processes.values():
            p.stop()
        for procs in fake_daemons.values():
            for p in procs:
                p.terminate()

    r = params.get("CurrentRoute", encoding='utf-8')
    return os.path.join(outdir, r + "--0")
Ejemplo n.º 14
0
def manager_init():

  # update system time from panda
  set_time(cloudlog)

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

  default_params = [
    ("CompletedTrainingVersion", "0"),
    ("HasAcceptedTerms", "0"),
    ("OpenpilotEnabledToggle", "1"),
    ("IsMetric", "1"),
    ("CommunityFeaturesToggle", "1"),
    ("EndToEndToggle", "1"),
    ("IsOpenpilotViewEnabled", "0"),
    ("OpkrAutoShutdown", "2"),
    ("OpkrForceShutdown", "5"),
    ("OpkrAutoScreenOff", "0"),
    ("OpkrUIBrightness", "0"),
    ("OpkrUIBrightness", "0"),
    ("OpkrUIVolumeBoost", "0"),
    ("OpkrEnableDriverMonitoring", "1"),
    ("OpkrEnableLogger", "0"),
    ("OpkrEnableUploader", "0"),
    ("OpkrEnableGetoffAlert", "1"),
    ("OpkrAutoResume", "1"),
    ("OpkrVariableCruise", "1"),
    ("OpkrLaneChangeSpeed", "45"),
    ("OpkrAutoLaneChangeDelay", "0"),
    ("OpkrSteerAngleCorrection", "0"),
    ("PutPrebuiltOn", "1"),
    ("LdwsCarFix", "0"),
    ("LateralControlMethod", "0"),
    ("CruiseStatemodeSelInit", "1"),
    ("InnerLoopGain", "35"),
    ("OuterLoopGain", "20"),
    ("TimeConstant", "14"),
    ("ActuatorEffectiveness", "20"),
    ("Scale", "1500"),
    ("LqrKi", "15"),
    ("DcGain", "27"),
    ("IgnoreZone", "0"),
    ("PidKp", "20"),
    ("PidKi", "40"),
    ("PidKd", "150"),
    ("PidKf", "7"),
    ("CameraOffsetAdj", "60"),
    ("SteerRatioAdj", "155"),
    ("SteerRatioMaxAdj", "175"),
    ("SteerActuatorDelayAdj", "20"),
    ("SteerRateCostAdj", "35"),
    ("SteerLimitTimerAdj", "80"),
    ("TireStiffnessFactorAdj", "100"),
    ("SteerMaxBaseAdj", "384"),
    ("SteerMaxAdj", "384"),
    ("SteerDeltaUpBaseAdj", "3"),
    ("SteerDeltaUpAdj", "3"),
    ("SteerDeltaDownBaseAdj", "7"),
    ("SteerDeltaDownAdj", "7"),
    ("SteerMaxvAdj", "10"),
    ("OpkrBatteryChargingControl", "1"),
    ("OpkrBatteryChargingMin", "70"),
    ("OpkrBatteryChargingMax", "80"),
    ("LeftCurvOffsetAdj", "0"),
    ("RightCurvOffsetAdj", "0"),
    ("DebugUi1", "0"),
    ("DebugUi2", "0"),
    ("LongLogDisplay", "0"),
    ("OpkrBlindSpotDetect", "1"),
    ("OpkrMaxAngleLimit", "90"),
    ("OpkrSpeedLimitOffset", "0"),
    ("OpkrLiveSteerRatio", "1"),
    ("OpkrVariableSteerMax", "1"),
    ("OpkrVariableSteerDelta", "0"),
    ("FingerprintTwoSet", "0"),
    ("OpkrVariableCruiseProfile", "1"),
    ("OpkrLiveTune", "0"),
    ("OpkrDrivingRecord", "0"),
    ("OpkrTurnSteeringDisable", "0"),
    ("CarModel", ""),
    ("CarModelAbb", ""),
    ("OpkrHotspotOnBoot", "0"),
    ("OpkrSSHLegacy", "1"),
    ("ShaneFeedForward", "0"),
    ("CruiseOverMaxSpeed", "0"),
    ("JustDoGearD", "0"),
    ("LanelessMode", "0"),
    ("ComIssueGone", "0"),
    ("MaxSteer", "384"),
    ("MaxRTDelta", "112"),
    ("MaxRateUp", "3"),
    ("MaxRateDown", "7"),
    ("SteerThreshold", "150"),
    ("RecordingCount", "100"),
    ("RecordingQuality", "1"),
    ("CruiseGapAdjust", "0"),
    ("AutoEnable", "1"),
    ("CruiseAutoRes", "0"),
    ("AutoResOption", "0"),
    ("SteerWindDown", "0"),
    ("OpkrMonitoringMode", "0"),
    ("OpkrMonitorEyesThreshold", "75"),
    ("OpkrMonitorNormalEyesThreshold", "50"),
    ("OpkrMonitorBlinkThreshold", "50"),
    ("MadModeEnabled", "1"),
    ("OpkrFanSpeedGain", "0"),
    ("WhitePandaSupport", "0"),
    ("SteerWarningFix", "0"),
    ("OpkrRunNaviOnBoot", "0"),
    ("OpkrApksEnable", "0"),
    ("CruiseGap1", "10"),
    ("CruiseGap2", "12"),
    ("CruiseGap3", "15"),
    ("CruiseGap4", "20"),
    ("DynamicTR", "2"),
    ("OpkrBattLess", "0"),
    ("LCTimingFactorUD", "0"),
    ("LCTimingFactor30", "10"),
    ("LCTimingFactor60", "20"),
    ("LCTimingFactor80", "70"),
    ("LCTimingFactor110", "110"),
  ]
  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")

  if EON and params.get_bool("OpkrApksEnable"):
    update_apks(show_spinner=True)

  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
  reg_res = register(show_spinner=True)
  if reg_res:
    dongle_id = reg_res
  elif not reg_res:
    dongle_id = "maintenance"
  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()

  # ensure shared libraries are readable by apks
  if EON and params.get_bool("OpkrApksEnable"):
    os.chmod(BASEDIR, 0o755)
    os.chmod("/dev/shm", 0o777)
    os.chmod(os.path.join(BASEDIR, "cereal"), 0o755)

  crash.bind_user(id=dongle_id)
  crash.bind_extra(dirty=dirty, origin=origin, branch=branch, commit=commit,
                   device=HARDWARE.get_device_type())

  os.system("/data/openpilot/gitcommit.sh")
Ejemplo n.º 15
0
    def update(self, c, can_strings):
        self.cp.update_strings(can_strings)

        ret = self.CS.update(self.cp)

        t = sec_since_boot()

        cruiseEnabled = self.CS.pcm_acc_status != AccState.OFF
        ret.cruiseState.enabled = cruiseEnabled

        ret.canValid = self.cp.can_valid
        ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False

        ret.engineRPM = self.CS.engineRPM

        buttonEvents = []

        if self.CS.cruise_buttons != self.CS.prev_cruise_buttons and self.CS.prev_cruise_buttons != CruiseButtons.INIT:
            be = car.CarState.ButtonEvent.new_message()
            be.type = ButtonType.unknown
            if self.CS.cruise_buttons != CruiseButtons.UNPRESS:
                be.pressed = True
                but = self.CS.cruise_buttons
            else:
                be.pressed = False
                but = self.CS.prev_cruise_buttons
            if but == CruiseButtons.RES_ACCEL:
                if not (ret.cruiseState.enabled and ret.standstill):
                    be.type = ButtonType.accelCruise  # Suppress resume button if we're resuming from stop so we don't adjust speed.
            elif but == CruiseButtons.DECEL_SET:
                if not cruiseEnabled and not self.CS.lkMode:
                    self.lkMode = True
                be.type = ButtonType.decelCruise
            elif but == CruiseButtons.CANCEL:
                be.type = ButtonType.cancel
            elif but == CruiseButtons.MAIN:
                be.type = ButtonType.altButton3
            buttonEvents.append(be)

        ret.buttonEvents = buttonEvents

        if cruiseEnabled and self.CS.lka_button and self.CS.lka_button != self.CS.prev_lka_button:
            self.CS.lkMode = not self.CS.lkMode
            cloudlog.info("button press event: LKA button. new value: %i" %
                          self.CS.lkMode)

        if t - self.params_check_last_t >= self.params_check_freq:
            self.params_check_last_t = t
            self.one_pedal_mode = self.CS._params.get_bool("OnePedalMode")

        # distance button is also used to toggle braking modes when in one-pedal-mode
        if self.CS.one_pedal_mode_active or self.CS.coast_one_pedal_mode_active:
            if self.CS.distance_button != self.CS.prev_distance_button:
                if not self.CS.distance_button and self.CS.one_pedal_mode_engaged_with_button and t - self.CS.distance_button_last_press_t < 0.8:  #user just engaged one-pedal with distance button hold and immediately let off the button, so default to regen/engine braking. If they keep holding, it does hard braking
                    cloudlog.info(
                        "button press event: Engaging one-pedal mode with distance button."
                    )
                    self.CS.one_pedal_brake_mode = 0
                    self.one_pedal_last_brake_mode = self.CS.one_pedal_brake_mode
                    self.CS.one_pedal_mode_enabled = False
                    self.CS.one_pedal_mode_active = False
                    self.CS.coast_one_pedal_mode_active = True
                    tmp_params = Params()
                    tmp_params.put("OnePedalBrakeMode",
                                   str(self.CS.one_pedal_brake_mode))
                    tmp_params.put_bool("OnePedalMode",
                                        self.CS.one_pedal_mode_enabled)
                else:
                    if not self.one_pedal_mode and self.CS.distance_button:  # user lifted press of distance button while in coast-one-pedal mode, so turn on braking
                        cloudlog.info(
                            "button press event: Engaging one-pedal braking.")
                        self.CS.one_pedal_last_switch_to_friction_braking_t = t
                        self.CS.distance_button_last_press_t = t + 0.5
                        self.CS.one_pedal_brake_mode = 0
                        self.one_pedal_last_brake_mode = self.CS.one_pedal_brake_mode
                        self.CS.one_pedal_mode_enabled = True
                        self.CS.one_pedal_mode_active = True
                        tmp_params = Params()
                        tmp_params.put("OnePedalBrakeMode",
                                       str(self.CS.one_pedal_brake_mode))
                        tmp_params.put_bool("OnePedalMode",
                                            self.CS.one_pedal_mode_enabled)
                    elif self.CS.distance_button and (
                            self.CS.pause_long_on_gas_press
                            or self.CS.out.standstill
                    ) and t - self.CS.distance_button_last_press_t < 0.4 and t - self.CS.one_pedal_last_switch_to_friction_braking_t > 1.:  # on the second press of a double tap while the gas is pressed, turn off one-pedal braking
                        # cycle the brake mode back to nullify the first press
                        cloudlog.info(
                            "button press event: Disengaging one-pedal mode with distace button double-press."
                        )
                        self.CS.distance_button_last_press_t = t + 0.5
                        self.CS.one_pedal_brake_mode = 0
                        self.one_pedal_last_brake_mode = self.CS.one_pedal_brake_mode
                        self.CS.one_pedal_mode_enabled = False
                        self.CS.one_pedal_mode_active = False
                        self.CS.coast_one_pedal_mode_active = True
                        tmp_params = Params()
                        tmp_params.put("OnePedalBrakeMode",
                                       str(self.CS.one_pedal_brake_mode))
                        tmp_params.put_bool("OnePedalMode",
                                            self.CS.one_pedal_mode_enabled)
                    else:
                        if self.CS.distance_button:
                            self.CS.distance_button_last_press_t = t
                            cloudlog.info(
                                "button press event: Distance button pressed in one-pedal mode."
                            )
                        else:  # only make changes when user lifts press
                            if self.CS.one_pedal_brake_mode == 2:
                                cloudlog.info(
                                    "button press event: Disengaging one-pedal hard braking. Switching to moderate braking"
                                )
                                self.CS.one_pedal_brake_mode = 1
                                tmp_params = Params()
                                tmp_params.put(
                                    "OnePedalBrakeMode",
                                    str(self.CS.one_pedal_brake_mode))
                            elif t - self.CS.distance_button_last_press_t > 0. and t - self.CS.distance_button_last_press_t < 0.4:  # only switch braking on a single tap (also allows for ignoring presses by setting last_press_t to be greater than t)
                                self.CS.one_pedal_brake_mode = (
                                    self.CS.one_pedal_brake_mode + 1) % 2
                                cloudlog.info(
                                    f"button press event: one-pedal braking. New value: {self.CS.one_pedal_brake_mode}"
                                )
                                tmp_params = Params()
                                tmp_params.put(
                                    "OnePedalBrakeMode",
                                    str(self.CS.one_pedal_brake_mode))
                    self.CS.one_pedal_mode_engaged_with_button = False
            elif self.CS.distance_button and t - self.CS.distance_button_last_press_t > 0.3:
                if self.CS.one_pedal_brake_mode < 2:
                    cloudlog.info(
                        "button press event: Engaging one-pedal hard braking.")
                    self.one_pedal_last_brake_mode = self.CS.one_pedal_brake_mode
                self.CS.one_pedal_brake_mode = 2
            self.CS.follow_level = self.CS.one_pedal_brake_mode + 1
        else:  # cruis is active, so just modify follow distance
            if self.CS.distance_button != self.CS.prev_distance_button:
                if self.CS.distance_button:
                    self.CS.distance_button_last_press_t = t
                    cloudlog.info(
                        "button press event: Distance button pressed in cruise mode."
                    )
                else:  # apply change on button lift
                    self.CS.follow_level -= 1
                    if self.CS.follow_level < 1:
                        self.CS.follow_level = 3
                    tmp_params = Params()
                    tmp_params.put("FollowLevel", str(self.CS.follow_level))
                    cloudlog.info(
                        "button press event: cruise follow distance button. new value: %r"
                        % self.CS.follow_level)
            elif self.CS.distance_button and t - self.CS.distance_button_last_press_t > 0.5 and not (
                    self.CS.one_pedal_mode_active
                    or self.CS.coast_one_pedal_mode_active):
                # user held follow button while in normal cruise, so engage one-pedal mode
                cloudlog.info(
                    "button press event: distance button hold to engage one-pedal mode."
                )
                self.CS.one_pedal_mode_engage_on_gas = True
                self.CS.one_pedal_mode_engaged_with_button = True
                self.CS.distance_button_last_press_t = t + 0.2  # gives the user X+0.3 seconds to release the distance button before hard braking is applied (which they may want, so don't want too long of a delay)

        ret.readdistancelines = self.CS.follow_level

        events = self.create_common_events(ret, pcm_enable=False)

        if ret.vEgo < self.CP.minEnableSpeed:
            events.add(EventName.belowEngageSpeed)
        if self.CS.pause_long_on_gas_press:
            events.add(EventName.gasPressed)
        if self.CS.park_brake:
            events.add(EventName.parkBrake)
        steer_paused = False
        if cruiseEnabled:
            if t - self.CS.last_pause_long_on_gas_press_t < 0.5 and t - self.CS.sessionInitTime > 10.:
                events.add(car.CarEvent.EventName.pauseLongOnGasPress)
            if not ret.standstill and self.CS.lkMode and self.CS.lane_change_steer_factor < 1.:
                events.add(car.CarEvent.EventName.blinkerSteeringPaused)
                steer_paused = True
        if ret.vEgo < self.CP.minSteerSpeed:
            if ret.standstill and cruiseEnabled and not ret.brakePressed and not self.CS.pause_long_on_gas_press and not self.CS.autoHoldActivated and not self.CS.disengage_on_gas and t - self.CS.sessionInitTime > 10.:
                events.add(car.CarEvent.EventName.stoppedWaitForGas)
            elif not steer_paused and self.CS.lkMode:
                events.add(car.CarEvent.EventName.belowSteerSpeed)
        if self.CS.autoHoldActivated:
            self.CS.lastAutoHoldTime = t
            events.add(car.CarEvent.EventName.autoHoldActivated)
        if self.CS.pcm_acc_status == AccState.FAULTED and t - self.CS.sessionInitTime > 10.0 and t - self.CS.lastAutoHoldTime > 1.0:
            events.add(EventName.accFaulted)

        # handle button presses
        for b in ret.buttonEvents:
            # do enable on both accel and decel buttons
            # The ECM will fault if resume triggers an enable while speed is set to 0
            if b.type == ButtonType.accelCruise and c.hudControl.setSpeed > 0 and c.hudControl.setSpeed < 70 and not b.pressed:
                events.add(EventName.buttonEnable)
            if b.type == ButtonType.decelCruise and not b.pressed:
                events.add(EventName.buttonEnable)
            # do disable on button down
            if b.type == ButtonType.cancel and b.pressed:
                events.add(EventName.buttonCancel)
            # The ECM independently tracks a ‘speed is set’ state that is reset on main off.
            # To keep controlsd in sync with the ECM state, generate a RESET_V_CRUISE event on main cruise presses.
            if b.type == ButtonType.altButton3 and b.pressed:
                events.add(EventName.buttonMainCancel)

        ret.events = events.to_msg()

        # copy back carState packet to CS
        self.CS.out = ret.as_reader()

        return self.CS.out
Ejemplo n.º 16
0
def thermald_thread():

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

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

    fan_speed = 0
    count = 0

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

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

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

    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 = 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
        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"):
            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
Ejemplo n.º 17
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", 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 get_dirty():
        os.environ['CLEAN'] = '1'

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

    if get_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=get_dirty(),
                     origin=get_origin(),
                     branch=get_short_branch(),
                     commit=get_commit(),
                     device=HARDWARE.get_device_type())
Ejemplo n.º 18
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()

        elif (sec_since_boot() -
              sm.rcv_time['pandaStates'] / 1e9) > DISCONNECT_TIMEOUT:
            if onroad_conditions["ignition"]:
                onroad_conditions["ignition"] = False
                cloudlog.error("panda timed out onroad")

        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.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), max(msg.deviceState.pmicTempC)))

        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
Ejemplo n.º 19
0
def init_overlay() -> None:

    overlay_init_file = Path(os.path.join(BASEDIR, ".overlay_init"))

    # Re-create the overlay if BASEDIR/.git has changed since we created the overlay
    if overlay_init_file.is_file():
        git_dir_path = os.path.join(BASEDIR, ".git")
        new_files = run(
            ["find", git_dir_path, "-newer",
             str(overlay_init_file)])
        if not len(new_files.splitlines()):
            # A valid overlay already exists
            return
        else:
            cloudlog.info(".git directory changed, recreating overlay")

    cloudlog.info("preparing new safe staging area")

    params = Params()
    params.put_bool("UpdateAvailable", False)
    set_consistent_flag(False)
    dismount_overlay()
    if TICI:
        run(["sudo", "rm", "-rf", STAGING_ROOT])
    if os.path.isdir(STAGING_ROOT):
        shutil.rmtree(STAGING_ROOT)

    for dirname in [
            STAGING_ROOT, OVERLAY_UPPER, OVERLAY_METADATA, OVERLAY_MERGED
    ]:
        os.mkdir(dirname, 0o755)

    if os.lstat(BASEDIR).st_dev != os.lstat(OVERLAY_MERGED).st_dev:
        raise RuntimeError(
            "base and overlay merge directories are on different filesystems; not valid for overlay FS!"
        )

    # Leave a timestamped canary in BASEDIR to check at startup. The device clock
    # should be correct by the time we get here. If the init file disappears, or
    # critical mtimes in BASEDIR are newer than .overlay_init, continue.sh can
    # assume that BASEDIR has used for local development or otherwise modified,
    # and skips the update activation attempt.
    consistent_file = Path(os.path.join(BASEDIR, ".overlay_consistent"))
    if consistent_file.is_file():
        consistent_file.unlink()
    overlay_init_file.touch()

    os.sync()
    overlay_opts = f"lowerdir={BASEDIR},upperdir={OVERLAY_UPPER},workdir={OVERLAY_METADATA}"

    mount_cmd = [
        "mount", "-t", "overlay", "-o", overlay_opts, "none", OVERLAY_MERGED
    ]
    if TICI:
        run(["sudo"] + mount_cmd)
        run(["sudo", "chmod", "755", os.path.join(OVERLAY_METADATA, "work")])
    else:
        run(mount_cmd)

    git_diff = run(["git", "diff"], OVERLAY_MERGED, low_priority=True)
    params.put("GitDiff", git_diff)
    cloudlog.info(f"git diff output:\n{git_diff}")
Ejemplo n.º 20
0
from common.basedir import BASEDIR
from common.params import Params
from selfdrive.controls.lib.alertmanager import set_offroad_alert

if __name__ == "__main__":
    params = Params()

    with open(
            os.path.join(BASEDIR,
                         "selfdrive/controls/lib/alerts_offroad.json")) as f:
        offroad_alerts = json.load(f)

    t = 10 if len(sys.argv) < 2 else int(sys.argv[1])
    while True:
        print("setting alert update")
        params.put_bool("UpdateAvailable", True)
        r = open(os.path.join(BASEDIR, "RELEASES.md")).read()
        r = r[:r.find('\n\n')]  # Slice latest release notes
        params.put("ReleaseNotes", r + "\n")

        time.sleep(t)
        params.put_bool("UpdateAvailable", False)

        # cycle through normal alerts
        for a in offroad_alerts:
            print("setting alert:", a)
            set_offroad_alert(a, True)
            time.sleep(t)
            set_offroad_alert(a, False)

        print("no alert")