mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-09-30 10:33:42 +08:00
Merge branch 'master' into mads-hkg-available-fix
# Conflicts: # SConstruct # selfdrive/ui/SConscript # selfdrive/ui/sunnypilot/SConscript
This commit is contained in:
+2
-2
@@ -29,13 +29,13 @@ default:
|
||||
- 'git config --global user.name "${GIT_CONFIG_USER_NAME}"'
|
||||
|
||||
|
||||
workflow: # If running on any branch other than main, use the `aws-datacontracts-dev` account; otherwise use `aws-datacontracts`
|
||||
workflow: # If running on any branch other than main.
|
||||
rules:
|
||||
# We are an MR, but it's a draft, we won't proceed with anything.
|
||||
- if: '$CI_MERGE_REQUEST_TITLE =~ /^wip:/i || $CI_MERGE_REQUEST_TITLE =~ /^draft:/i'
|
||||
when: never
|
||||
# We are a merge request
|
||||
- if: $CI_MERGE_REQUEST_IID #|| $CI_COMMIT_REF_NAME == "gitlab-pipelines" # TBD once merged
|
||||
- if: $CI_MERGE_REQUEST_IID
|
||||
variables:
|
||||
EXTRA_VERSION_IDENTIFIER: "-${CI_PIPELINE_IID}"
|
||||
NEW_BRANCH: ${CI_COMMIT_REF_NAME}-prebuilt
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[submodule "panda"]
|
||||
path = panda
|
||||
url = ../../sunnyhaibin/panda-special.git
|
||||
url = ../../sunnyhaibin/panda.git
|
||||
[submodule "opendbc"]
|
||||
path = opendbc
|
||||
url = https://github.com/sunnyhaibin/opendbc.git
|
||||
|
||||
+5
-3
@@ -32,14 +32,16 @@ sunnypilot - 0.9.8.0 (2024-xx-xx)
|
||||
* In response to the official deprecation of support for Smart DSU (SDSU) and Radar CAN Filter in the upstream ([commaai/openpilot#32777](https://github.com/commaai/openpilot/pull/32777)), sunnypilot will continue maintaining software support for Smart DSU (SDSU) and Radar CAN Filter
|
||||
* UPDATED: Continued support for Mapbox navigation
|
||||
* In response to the official temporary deprecation of support for Mapbox navigation in the upstream ([commaai/openpilot#32773](https://github.com/commaai/openpilot/pull/32773)), sunnypilot will continue maintaining software support for Mapbox navigation
|
||||
* NEW❗: Toyota - Automatic Brake Hold (AHB) thanks to AlexandreSato!
|
||||
* When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold
|
||||
* NOTE: Only for Toyota/Lexus vehicles with TSS2/LSS2
|
||||
* NEW❗: Toyota - Automatic Door Locking and Unlocking thanks to AlexandreSato, cydia2020, and dragonpilot-community!
|
||||
* Auto Lock by Speed: All doors are automatically locked when vehicle speed is approximately 6 mph (10 km/h) or higher
|
||||
* Auto Unlock by Shift to P: All doors are automatically unlocked when shifting the shift lever to P
|
||||
* FIXED: Driving Personality:
|
||||
* Maniac mode now correctly enforced when selected
|
||||
* UI Updates
|
||||
* Display Metrics Below Chevron
|
||||
* NEW❗: Time to Lead Car
|
||||
* Displays the time to reach the position previously occupied by the lead car
|
||||
* NEW❗: Display Distance, Speed, and Time to Lead Car simultaneously
|
||||
* Kia Ceed Plug-in Hybrid Non-SCC 2022 support thanks to TerminatorNL!
|
||||
|
||||
sunnypilot - 0.9.7.1 (2024-06-13)
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
# Custom MIT License
|
||||
|
||||
Copyright 2024 Haibin Wen, SUNNYPILOT LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to view and modify the Software, subject to the following conditions:
|
||||
|
||||
1. **Permission Required**: Use of the Software, in whole or in part, for any purpose requires explicit written permission from the original author(s).
|
||||
|
||||
2. **Redistribution**: Any redistribution of the Software, modified or unmodified, must retain this license notice and the following acknowledgment:
|
||||
"This software is licensed under a custom license requiring permission for use."
|
||||
|
||||
3. **Visibility**: Any project that uses the Software must visibly mention the following acknowledgment:
|
||||
"This project uses software from Haibin Wen and SUNNYPILOT LLC and is licensed under a custom license requiring permission for use."
|
||||
|
||||
4. **No Warranty**: The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
|
||||
|
||||
Contact sunnypilot Support <support@sunnypilot> for permission requests.
|
||||
|
||||
---
|
||||
|
||||
Haibin Wen, SUNNYPILOT LLC
|
||||
+8
-4
@@ -113,11 +113,11 @@ AddOption('--minimal',
|
||||
default=os.path.exists(File('#.lfsconfig').abspath), # minimal by default on release branch (where there's no LFS)
|
||||
help='the minimum build to run openpilot. no tests, tools, etc.')
|
||||
|
||||
AddOption('--sunnypilot',
|
||||
AddOption('--stock-ui',
|
||||
action='store_true',
|
||||
dest='sunnypilot',
|
||||
default=is_internal_developer(_DEBUG) or True, # check if the current user is a sunnypilot developer. TODO: Remove the 'or True' part once the GPG keys are available.
|
||||
help='build sunnypilot elements and other sunnypilot-specific items that are meant for internal development')
|
||||
dest='stock_ui',
|
||||
default=False,
|
||||
help='Build stock UI instead of sunnypilot UI')
|
||||
|
||||
## Architecture name breakdown (arch)
|
||||
## - larch64: linux tici aarch64
|
||||
@@ -222,6 +222,10 @@ if arch != "Darwin":
|
||||
cflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
|
||||
cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
|
||||
|
||||
if not GetOption('stock_ui'):
|
||||
cflags += ["-DSUNNYPILOT"]
|
||||
cxxflags += ["-DSUNNYPILOT"]
|
||||
|
||||
ccflags_option = GetOption('ccflags')
|
||||
if ccflags_option:
|
||||
ccflags += ccflags_option.split(' ')
|
||||
|
||||
@@ -137,7 +137,6 @@ struct CarEvent @0x9b1657f34caf3ad3 {
|
||||
speedLimitPreActive @139;
|
||||
speedLimitConfirmed @140;
|
||||
torqueNNLoad @141;
|
||||
spAutoBrakeHold @142;
|
||||
|
||||
radarCanErrorDEPRECATED @15;
|
||||
communityFeatureDisallowedDEPRECATED @62;
|
||||
|
||||
+2
-1
@@ -318,7 +318,6 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"TorqueFriction", PERSISTENT | BACKUP},
|
||||
{"TorqueMaxLatAccel", PERSISTENT | BACKUP},
|
||||
{"TorquedOverride", PERSISTENT | BACKUP},
|
||||
{"ToyotaAutoHold", PERSISTENT | BACKUP},
|
||||
{"ToyotaAutoLockBySpeed", PERSISTENT | BACKUP},
|
||||
{"ToyotaAutoUnlockByShifter", PERSISTENT | BACKUP},
|
||||
{"ToyotaEnhancedBsm", PERSISTENT | BACKUP},
|
||||
@@ -336,6 +335,8 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
|
||||
{"SunnylinkCache_Users", PERSISTENT},
|
||||
{"SunnylinkCache_Roles", PERSISTENT},
|
||||
{"EnableGitlabRunner", PERSISTENT | BACKUP},
|
||||
{"EnableSunnylinkUploader", PERSISTENT | BACKUP},
|
||||
|
||||
// PFEIFER - MAPD {{
|
||||
{"MapdVersion", PERSISTENT},
|
||||
|
||||
+1
-1
Submodule panda updated: ff1ef85735...5d92bdc6de
@@ -43,10 +43,28 @@ def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: dict[int, ca
|
||||
return events
|
||||
|
||||
|
||||
def create_mads_event(mads_event_lock: bool) -> capnp.lib.capnp._DynamicStructBuilder:
|
||||
be = car.CarState.ButtonEvent(pressed=mads_event_lock)
|
||||
be.type = ButtonType.altButton1
|
||||
return be
|
||||
class ButtonEvents:
|
||||
def __init__(self) -> None:
|
||||
self.is_mads: bool = False
|
||||
|
||||
@staticmethod
|
||||
def create_cancel_event(long_enabled: bool, prev_long_enabled: bool) -> list[capnp.lib.capnp._DynamicStructBuilder]:
|
||||
events: list[capnp.lib.capnp._DynamicStructBuilder] = []
|
||||
|
||||
if not long_enabled and prev_long_enabled:
|
||||
events.append(car.CarState.ButtonEvent(pressed=True,
|
||||
type=ButtonType.cancel))
|
||||
return events
|
||||
|
||||
def create_mads_event(self, mads_enabled: bool, prev_mads_enabled: bool) -> list[capnp.lib.capnp._DynamicStructBuilder]:
|
||||
events: list[capnp.lib.capnp._DynamicStructBuilder] = []
|
||||
|
||||
mads_changed = prev_mads_enabled != mads_enabled
|
||||
if (mads_changed and not self.is_mads) or (not mads_changed and self.is_mads):
|
||||
events.append(car.CarState.ButtonEvent(pressed=mads_changed, type=ButtonType.altButton1))
|
||||
self.is_mads = not self.is_mads
|
||||
|
||||
return events
|
||||
|
||||
|
||||
def gen_empty_fingerprint():
|
||||
|
||||
@@ -56,7 +56,6 @@ class Car:
|
||||
self.mads_disengage_lateral_on_brake = self.params.get_bool("DisengageLateralOnBrake")
|
||||
self.mads_dlob = self.enable_mads and self.mads_disengage_lateral_on_brake
|
||||
self.mads_ndlob = self.enable_mads and not self.mads_disengage_lateral_on_brake
|
||||
self.sp_toyota_auto_brake_hold = self.params.get_bool("ToyotaAutoHold")
|
||||
self.CP.alternativeExperience = 0
|
||||
if not self.disengage_on_accelerator:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
|
||||
@@ -64,8 +63,6 @@ class Car:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.ENABLE_MADS
|
||||
elif self.mads_ndlob:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.MADS_DISABLE_DISENGAGE_LATERAL_ON_BRAKE
|
||||
if self.sp_toyota_auto_brake_hold:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.ALLOW_AEB
|
||||
|
||||
if self.CP.customStockLongAvailable and self.CP.pcmCruise and self.params.get_bool("CustomStockLong"):
|
||||
self.CP.pcmCruiseSpeed = False
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from cereal import car
|
||||
|
||||
import cereal.messaging as messaging
|
||||
from common.conversions import Conversions as CV
|
||||
from opendbc.can.packer import CANPacker
|
||||
@@ -9,7 +11,7 @@ from openpilot.selfdrive.car.chrysler.values import RAM_CARS, RAM_DT, CarControl
|
||||
from openpilot.selfdrive.car.interfaces import CarControllerBase, FORWARD_GEARS
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import FCA_V_CRUISE_MIN
|
||||
|
||||
BUTTONS_STATES = ["accelCruise", "decelCruise", "cancel", "resumeCruise"]
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarController(CarControllerBase):
|
||||
@@ -104,7 +106,7 @@ class CarController(CarControllerBase):
|
||||
self.last_button_frame = CS.button_counter
|
||||
|
||||
if ram_cars:
|
||||
if CS.buttonStates["cancel"]:
|
||||
if any(b.type == ButtonType.cancel for b in CS.out.buttonEvents):
|
||||
can_sends.append(chryslercan.create_cruise_buttons(self.packer, CS.button_counter, das_bus, self.CP, cancel=True))
|
||||
else:
|
||||
can_sends.append(chryslercan.create_cruise_buttons(self.packer, CS.button_counter, das_bus, self.CP,
|
||||
@@ -189,8 +191,10 @@ class CarController(CarControllerBase):
|
||||
|
||||
# multikyd methods, sunnyhaibin logic
|
||||
def get_cruise_buttons_status(self, CS):
|
||||
if not CS.out.cruiseState.enabled or any(CS.buttonStates[button_state] for button_state in BUTTONS_STATES):
|
||||
self.timer = 40
|
||||
if not CS.out.cruiseState.enabled:
|
||||
for be in CS.out.buttonEvents:
|
||||
if be.type in (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.resumeCruise) and be.pressed:
|
||||
self.timer = 40
|
||||
elif self.timer:
|
||||
self.timer -= 1
|
||||
else:
|
||||
|
||||
@@ -3,7 +3,7 @@ from openpilot.common.conversions import Conversions as CV
|
||||
from opendbc.can.parser import CANParser
|
||||
from opendbc.can.can_define import CANDefine
|
||||
from openpilot.selfdrive.car.interfaces import CarStateBase
|
||||
from openpilot.selfdrive.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS, BUTTON_STATES
|
||||
from openpilot.selfdrive.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS, BUTTONS
|
||||
|
||||
|
||||
class CarState(CarStateBase):
|
||||
@@ -29,8 +29,7 @@ class CarState(CarStateBase):
|
||||
self.lkas_heartbit = None
|
||||
self.lkas_disabled = False
|
||||
|
||||
self.buttonStates = BUTTON_STATES.copy()
|
||||
self.buttonStatesPrev = BUTTON_STATES.copy()
|
||||
self.button_states = {button.event_type: False for button in BUTTONS}
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
|
||||
@@ -41,7 +40,6 @@ class CarState(CarStateBase):
|
||||
|
||||
self.prev_mads_enabled = self.mads_enabled
|
||||
self.prev_lkas_enabled = self.lkas_enabled
|
||||
self.buttonStatesPrev = self.buttonStates.copy()
|
||||
|
||||
# lock info
|
||||
ret.doorOpen = any([cp.vl["BCM_1"]["DOOR_OPEN_FL"],
|
||||
@@ -76,6 +74,16 @@ class CarState(CarStateBase):
|
||||
unit=1,
|
||||
)
|
||||
|
||||
# Buttons
|
||||
for button in BUTTONS:
|
||||
state = (cp.vl[button.can_addr][button.can_msg] in button.values)
|
||||
if self.button_states[button.event_type] != state:
|
||||
event = car.CarState.ButtonEvent.new_message()
|
||||
event.type = button.event_type
|
||||
event.pressed = state
|
||||
self.button_events.append(event)
|
||||
self.button_states[button.event_type] = state
|
||||
|
||||
# button presses
|
||||
ret.leftBlinker, ret.rightBlinker = ret.leftBlinkerOn, ret.rightBlinkerOn = self.update_blinker_from_stalk(200, cp.vl["STEERING_LEVERS"]["TURN_SIGNALS"] == 1,
|
||||
cp.vl["STEERING_LEVERS"]["TURN_SIGNALS"] == 2)
|
||||
@@ -116,11 +124,6 @@ class CarState(CarStateBase):
|
||||
ret.leftBlindspot = cp.vl["BSM_1"]["LEFT_STATUS"] == 1
|
||||
ret.rightBlindspot = cp.vl["BSM_1"]["RIGHT_STATUS"] == 1
|
||||
|
||||
self.buttonStates["accelCruise"] = bool(cp.vl["CRUISE_BUTTONS"]["ACC_Accel"])
|
||||
self.buttonStates["decelCruise"] = bool(cp.vl["CRUISE_BUTTONS"]["ACC_Decel"])
|
||||
self.buttonStates["cancel"] = bool(cp.vl["CRUISE_BUTTONS"]["ACC_Cancel"])
|
||||
self.buttonStates["resumeCruise"] = bool(cp.vl["CRUISE_BUTTONS"]["ACC_Resume"])
|
||||
|
||||
self.lkas_car_model = cp_cam.vl["DAS_6"]["CAR_MODEL"]
|
||||
self.button_counter = cp.vl["CRUISE_BUTTONS"]["COUNTER"]
|
||||
self.cruise_buttons = cp.vl["CRUISE_BUTTONS"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from panda import Panda
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event
|
||||
from openpilot.selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerFlagsSP, BUTTON_STATES
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerFlagsSP
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
@@ -13,7 +13,6 @@ GearShifter = car.CarState.GearShifter
|
||||
class CarInterface(CarInterfaceBase):
|
||||
def __init__(self, CP, CarController, CarState):
|
||||
super().__init__(CP, CarController, CarState)
|
||||
self.buttonStatesPrev = BUTTON_STATES.copy()
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
@@ -94,19 +93,12 @@ class CarInterface(CarInterfaceBase):
|
||||
ret = self.CS.update(self.cp, self.cp_cam)
|
||||
self.sp_update_params()
|
||||
|
||||
buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
|
||||
for button in self.CS.buttonStates:
|
||||
if self.CS.buttonStates[button] != self.buttonStatesPrev[button]:
|
||||
be = car.CarState.ButtonEvent.new_message()
|
||||
be.type = button
|
||||
be.pressed = self.CS.buttonStates[button]
|
||||
buttonEvents.append(be)
|
||||
self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}))
|
||||
|
||||
self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS)
|
||||
|
||||
self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled,
|
||||
buttonEvents, c.vCruise,
|
||||
self.CS.button_events, c.vCruise,
|
||||
enable_buttons=(ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.resumeCruise) if not self.CP.pcmCruiseSpeed else
|
||||
(ButtonType.accelCruise, ButtonType.decelCruise),
|
||||
resume_button=(ButtonType.resumeCruise,) if not self.CP.pcmCruiseSpeed else
|
||||
@@ -125,7 +117,7 @@ class CarInterface(CarInterfaceBase):
|
||||
self.CS.madsEnabled = self.get_sp_started_mads(ret, self.CS)
|
||||
|
||||
if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed:
|
||||
if any(b.type == ButtonType.cancel for b in buttonEvents):
|
||||
if any(b.type == ButtonType.cancel for b in self.CS.button_events):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
if self.get_sp_pedal_disengage(ret):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
@@ -143,17 +135,10 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button))
|
||||
|
||||
# MADS BUTTON
|
||||
if self.CS.out.madsEnabled != self.CS.madsEnabled:
|
||||
if self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = False
|
||||
else:
|
||||
if not self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = True
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
ret.buttonEvents = [
|
||||
*self.CS.button_events,
|
||||
*self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON
|
||||
]
|
||||
|
||||
# events
|
||||
events = self.create_common_events(ret, c, extra_gears=[car.CarState.GearShifter.low], pcm_enable=False)
|
||||
@@ -180,6 +165,4 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret.events = events.to_msg()
|
||||
|
||||
self.buttonStatesPrev = self.CS.buttonStates.copy()
|
||||
|
||||
return ret
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from collections import namedtuple
|
||||
from enum import IntFlag
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
@@ -8,6 +9,7 @@ from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarPar
|
||||
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16
|
||||
|
||||
Ecu = car.CarParams.Ecu
|
||||
Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values'])
|
||||
|
||||
|
||||
class ChryslerFlags(IntFlag):
|
||||
@@ -113,12 +115,12 @@ class CarControllerParams:
|
||||
self.STEER_MAX = 261 # higher than this faults the EPS
|
||||
|
||||
|
||||
BUTTON_STATES = {
|
||||
"accelCruise": False,
|
||||
"decelCruise": False,
|
||||
"cancel": False,
|
||||
"resumeCruise": False,
|
||||
}
|
||||
BUTTONS = [
|
||||
Button(car.CarState.ButtonEvent.Type.accelCruise, "CRUISE_BUTTONS", "ACC_Accel", [1]),
|
||||
Button(car.CarState.ButtonEvent.Type.decelCruise, "CRUISE_BUTTONS", "ACC_Decel", [1]),
|
||||
Button(car.CarState.ButtonEvent.Type.cancel, "CRUISE_BUTTONS", "ACC_Cancel", [1]),
|
||||
Button(car.CarState.ButtonEvent.Type.resumeCruise, "CRUISE_BUTTONS", "ACC_Resume", [1]),
|
||||
]
|
||||
|
||||
|
||||
STEER_THRESHOLD = 120
|
||||
|
||||
@@ -3,7 +3,7 @@ from opendbc.can.can_define import CANDefine
|
||||
from opendbc.can.parser import CANParser
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.car.ford.fordcan import CanBus
|
||||
from openpilot.selfdrive.car.ford.values import DBC, CarControllerParams, FordFlags, BUTTON_STATES
|
||||
from openpilot.selfdrive.car.ford.values import DBC, CarControllerParams, FordFlags, BUTTONS
|
||||
from openpilot.selfdrive.car.interfaces import CarStateBase
|
||||
|
||||
GearShifter = car.CarState.GearShifter
|
||||
@@ -24,15 +24,14 @@ class CarState(CarStateBase):
|
||||
|
||||
self.lkas_enabled = None
|
||||
self.prev_lkas_enabled = None
|
||||
self.buttonStates = BUTTON_STATES.copy()
|
||||
self.buttonStatesPrev = BUTTON_STATES.copy()
|
||||
|
||||
self.button_states = {button.event_type: False for button in BUTTONS}
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
self.prev_mads_enabled = self.mads_enabled
|
||||
self.prev_lkas_enabled = self.lkas_enabled
|
||||
self.buttonStatesPrev = self.buttonStates.copy()
|
||||
|
||||
# Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement
|
||||
# The vehicle usually recovers out of this state within a minute of normal driving
|
||||
@@ -87,6 +86,16 @@ class CarState(CarStateBase):
|
||||
else:
|
||||
ret.gearShifter = GearShifter.drive
|
||||
|
||||
# Buttons
|
||||
for button in BUTTONS:
|
||||
state = (cp.vl[button.can_addr][button.can_msg] in button.values)
|
||||
if self.button_states[button.event_type] != state:
|
||||
event = car.CarState.ButtonEvent.new_message()
|
||||
event.type = button.event_type
|
||||
event.pressed = state
|
||||
self.button_events.append(event)
|
||||
self.button_states[button.event_type] = state
|
||||
|
||||
# safety
|
||||
ret.stockFcw = bool(cp_cam.vl["ACCDATA_3"]["FcwVisblWarn_B_Rq"])
|
||||
ret.stockAeb = bool(cp_cam.vl["ACCDATA_2"]["CmbbBrkDecel_B_Rq"])
|
||||
@@ -112,13 +121,6 @@ class CarState(CarStateBase):
|
||||
|
||||
self.lkas_enabled = bool(cp.vl["Steering_Data_FD1"]["TjaButtnOnOffPress"])
|
||||
|
||||
self.buttonStates["accelCruise"] = bool(cp.vl["Steering_Data_FD1"]["CcAslButtnSetIncPress"])
|
||||
self.buttonStates["decelCruise"] = bool(cp.vl["Steering_Data_FD1"]["CcAslButtnSetDecPress"])
|
||||
self.buttonStates["cancel"] = bool(cp.vl["Steering_Data_FD1"]["CcAslButtnCnclPress"])
|
||||
self.buttonStates["setCruise"] = bool(cp.vl["Steering_Data_FD1"]["CcAslButtnSetPress"])
|
||||
self.buttonStates["resumeCruise"] = bool(cp.vl["Steering_Data_FD1"]["CcAsllButtnResPress"])
|
||||
self.buttonStates["gapAdjustCruise"] = bool(cp.vl["Steering_Data_FD1"]["AccButtnGapTogglePress"])
|
||||
|
||||
# Stock steering buttons so that we can passthru blinkers etc.
|
||||
self.buttons_stock_values = cp.vl["Steering_Data_FD1"]
|
||||
# Stock values from IPMA so that we can retain some stock functionality
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from cereal import car
|
||||
from panda import Panda
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.ford.fordcan import CanBus
|
||||
from openpilot.selfdrive.car.ford.values import Ecu, FordFlags, BUTTON_STATES
|
||||
from openpilot.selfdrive.car.ford.values import Ecu, FordFlags
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
@@ -15,8 +15,6 @@ class CarInterface(CarInterfaceBase):
|
||||
def __init__(self, CP, CarController, CarState):
|
||||
super().__init__(CP, CarController, CarState)
|
||||
|
||||
self.buttonStatesPrev = BUTTON_STATES.copy()
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "ford"
|
||||
@@ -76,19 +74,12 @@ class CarInterface(CarInterfaceBase):
|
||||
ret = self.CS.update(self.cp, self.cp_cam)
|
||||
self.sp_update_params()
|
||||
|
||||
buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
|
||||
for button in self.CS.buttonStates:
|
||||
if self.CS.buttonStates[button] != self.buttonStatesPrev[button]:
|
||||
be = car.CarState.ButtonEvent.new_message()
|
||||
be.type = button
|
||||
be.pressed = self.CS.buttonStates[button]
|
||||
buttonEvents.append(be)
|
||||
self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}))
|
||||
|
||||
self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS)
|
||||
|
||||
self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled,
|
||||
buttonEvents, c.vCruise)
|
||||
self.CS.button_events, c.vCruise)
|
||||
|
||||
if ret.cruiseState.available:
|
||||
if self.enable_mads:
|
||||
@@ -101,7 +92,7 @@ class CarInterface(CarInterfaceBase):
|
||||
self.CS.madsEnabled = False
|
||||
|
||||
if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0):
|
||||
if any(b.type == ButtonType.cancel for b in buttonEvents):
|
||||
if any(b.type == ButtonType.cancel for b in self.CS.button_events):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
if self.get_sp_pedal_disengage(ret):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
@@ -114,16 +105,10 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button))
|
||||
|
||||
if self.CS.out.madsEnabled != self.CS.madsEnabled:
|
||||
if self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = False
|
||||
else:
|
||||
if not self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = True
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
ret.buttonEvents = [
|
||||
*self.CS.button_events,
|
||||
*self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON
|
||||
]
|
||||
|
||||
events = self.create_common_events(ret, c, extra_gears=[GearShifter.manumatic], pcm_enable=False)
|
||||
|
||||
@@ -134,7 +119,4 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret.events = events.to_msg()
|
||||
|
||||
# update previous car states
|
||||
self.buttonStatesPrev = self.CS.buttonStates.copy()
|
||||
|
||||
return ret
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import copy
|
||||
import re
|
||||
from collections import namedtuple
|
||||
from dataclasses import dataclass, field, replace
|
||||
from enum import Enum, IntFlag
|
||||
|
||||
@@ -11,6 +12,7 @@ from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, Ca
|
||||
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, LiveFwVersions, OfflineFwVersions, Request, StdQueries, p16
|
||||
|
||||
Ecu = car.CarParams.Ecu
|
||||
Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values'])
|
||||
|
||||
|
||||
class CarControllerParams:
|
||||
@@ -46,16 +48,6 @@ class FordFlags(IntFlag):
|
||||
CANFD = 1
|
||||
|
||||
|
||||
BUTTON_STATES = {
|
||||
"accelCruise": False,
|
||||
"decelCruise": False,
|
||||
"cancel": False,
|
||||
"setCruise": False,
|
||||
"resumeCruise": False,
|
||||
"gapAdjustCruise": False
|
||||
}
|
||||
|
||||
|
||||
class RADAR:
|
||||
DELPHI_ESR = 'ford_fusion_2018_adas'
|
||||
DELPHI_MRR = 'FORD_CADS'
|
||||
@@ -154,6 +146,15 @@ class CAR(Platforms):
|
||||
)
|
||||
|
||||
|
||||
BUTTONS = [
|
||||
Button(car.CarState.ButtonEvent.Type.accelCruise, "Steering_Data_FD1", "CcAslButtnSetIncPress", [1]),
|
||||
Button(car.CarState.ButtonEvent.Type.decelCruise, "Steering_Data_FD1", "CcAslButtnSetDecPress", [1]),
|
||||
Button(car.CarState.ButtonEvent.Type.cancel, "Steering_Data_FD1", "CcAslButtnCnclPress", [1]),
|
||||
Button(car.CarState.ButtonEvent.Type.setCruise, "Steering_Data_FD1", "CcAslButtnSetPress", [1]),
|
||||
Button(car.CarState.ButtonEvent.Type.resumeCruise, "Steering_Data_FD1", "CcAsllButtnResPress", [1]),
|
||||
]
|
||||
|
||||
|
||||
# FW response contains a combined software and part number
|
||||
# A-Z except no I, O or W
|
||||
# e.g. NZ6A-14C204-AAA
|
||||
|
||||
@@ -6,7 +6,7 @@ from panda import Panda
|
||||
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG
|
||||
from openpilot.selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LatControlInputs, NanoFFModel
|
||||
@@ -206,12 +206,11 @@ class CarInterface(CarInterfaceBase):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_loopback)
|
||||
self.sp_update_params()
|
||||
|
||||
buttonEvents = []
|
||||
distance_button = 0
|
||||
|
||||
# Don't add event if transitioning from INIT, unless it's to an actual button
|
||||
if self.CS.cruise_buttons != CruiseButtons.UNPRESS or self.CS.prev_cruise_buttons != CruiseButtons.INIT:
|
||||
buttonEvents = [
|
||||
self.CS.button_events = [
|
||||
*create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT,
|
||||
unpressed_btn=CruiseButtons.UNPRESS),
|
||||
*create_button_events(self.CS.distance_button, self.CS.prev_distance_button,
|
||||
@@ -222,11 +221,11 @@ class CarInterface(CarInterfaceBase):
|
||||
self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS)
|
||||
|
||||
if not self.CP.pcmCruise:
|
||||
if any(b.type == ButtonType.accelCruise and b.pressed for b in buttonEvents):
|
||||
if any(b.type == ButtonType.accelCruise and b.pressed for b in self.CS.button_events):
|
||||
self.CS.accEnabled = True
|
||||
|
||||
self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled,
|
||||
buttonEvents, c.vCruise)
|
||||
self.CS.button_events, c.vCruise)
|
||||
|
||||
if ret.cruiseState.available:
|
||||
if self.enable_mads:
|
||||
@@ -239,7 +238,7 @@ class CarInterface(CarInterfaceBase):
|
||||
self.CS.madsEnabled = False
|
||||
|
||||
if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0):
|
||||
if any(b.type == ButtonType.cancel for b in buttonEvents):
|
||||
if any(b.type == ButtonType.cancel for b in self.CS.button_events):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
if self.get_sp_pedal_disengage(ret):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
@@ -252,17 +251,10 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(distance_button))
|
||||
|
||||
# MADS BUTTON
|
||||
if self.CS.out.madsEnabled != self.CS.madsEnabled:
|
||||
if self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = False
|
||||
else:
|
||||
if not self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = True
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
ret.buttonEvents = [
|
||||
*self.CS.button_events,
|
||||
*self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON
|
||||
]
|
||||
|
||||
# The ECM allows enabling on falling edge of set, but only rising edge of resume
|
||||
events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low,
|
||||
|
||||
@@ -268,7 +268,7 @@ class CarInterface(CarInterfaceBase):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_body)
|
||||
self.sp_update_params()
|
||||
|
||||
buttonEvents = [
|
||||
self.CS.button_events = [
|
||||
*create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT),
|
||||
*create_button_events(self.CS.cruise_setting, self.CS.prev_cruise_setting, SETTINGS_BUTTONS_DICT),
|
||||
]
|
||||
@@ -276,7 +276,7 @@ class CarInterface(CarInterfaceBase):
|
||||
self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS)
|
||||
|
||||
self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled,
|
||||
buttonEvents, c.vCruise)
|
||||
self.CS.button_events, c.vCruise)
|
||||
|
||||
if ret.cruiseState.available:
|
||||
if self.enable_mads:
|
||||
@@ -289,7 +289,7 @@ class CarInterface(CarInterfaceBase):
|
||||
self.CS.madsEnabled = False
|
||||
|
||||
if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed:
|
||||
if any(b.type == ButtonType.cancel for b in buttonEvents):
|
||||
if any(b.type == ButtonType.cancel for b in self.CS.button_events):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
if self.get_sp_pedal_disengage(ret):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
@@ -304,7 +304,10 @@ class CarInterface(CarInterfaceBase):
|
||||
min_enable_speed_pcm=(self.CP.pcmCruise and self.CP.minEnableSpeed > 0 and self.CP.pcmCruiseSpeed),
|
||||
gap_button=(self.CS.cruise_setting == 3))
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
ret.buttonEvents = [
|
||||
*self.CS.button_events,
|
||||
*self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON
|
||||
]
|
||||
|
||||
# events
|
||||
events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low], pcm_enable=False)
|
||||
|
||||
@@ -7,7 +7,7 @@ from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, HyundaiFlagsSP,
|
||||
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, NON_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, \
|
||||
UNSUPPORTED_LONGITUDINAL_CAR, Buttons
|
||||
from openpilot.selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
from openpilot.selfdrive.car.disable_ecu import disable_ecu
|
||||
|
||||
@@ -205,12 +205,12 @@ class CarInterface(CarInterfaceBase):
|
||||
ret = self.CS.update(self.cp, self.cp_cam)
|
||||
self.sp_update_params()
|
||||
|
||||
buttonEvents = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)
|
||||
self.CS.button_events = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)
|
||||
|
||||
self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS)
|
||||
|
||||
self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled,
|
||||
buttonEvents, c.vCruise)
|
||||
self.CS.button_events, c.vCruise)
|
||||
|
||||
if ret.cruiseState.available:
|
||||
if not self.CP.pcmCruiseSpeed:
|
||||
@@ -233,7 +233,7 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
if not self.CP.pcmCruise or not self.CP.pcmCruiseSpeed:
|
||||
if not self.CP.pcmCruise:
|
||||
if any(b.type == ButtonType.cancel for b in buttonEvents):
|
||||
if any(b.type == ButtonType.cancel for b in self.CS.button_events):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
if not self.CP.pcmCruiseSpeed:
|
||||
if not ret.cruiseState.enabled:
|
||||
@@ -244,17 +244,10 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=(self.CS.cruise_buttons[-1] == 3))
|
||||
|
||||
# MADS BUTTON
|
||||
if self.CS.out.madsEnabled != self.CS.madsEnabled:
|
||||
if self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = False
|
||||
else:
|
||||
if not self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = True
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
ret.buttonEvents = [
|
||||
*self.CS.button_events,
|
||||
*self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON
|
||||
]
|
||||
|
||||
# On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
|
||||
# To avoid re-engaging when openpilot cancels, check user engagement intention via buttons
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import capnp
|
||||
import json
|
||||
import os
|
||||
import numpy as np
|
||||
@@ -17,7 +18,7 @@ from openpilot.common.simple_kalman import KF1D, get_kalman_gain
|
||||
from openpilot.common.numpy_fast import clip
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
from openpilot.selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG
|
||||
from openpilot.selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG, ButtonEvents
|
||||
from openpilot.selfdrive.car.values import PLATFORMS
|
||||
from openpilot.selfdrive.controls.lib.desire_helper import get_min_lateral_speed
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, V_CRUISE_UNSET, get_friction
|
||||
@@ -253,6 +254,7 @@ class CarInterfaceBase(ABC):
|
||||
self.last_mads_init = 0.
|
||||
self.madsEnabledInit = False
|
||||
self.madsEnabledInitPrev = False
|
||||
self.button_events = ButtonEvents()
|
||||
|
||||
self.lat_torque_nn_model = None
|
||||
eps_firmware = str(next((fw.fwVersion for fw in CP.carFw if fw.ecu == "eps"), ""))
|
||||
@@ -425,6 +427,8 @@ class CarInterfaceBase(ABC):
|
||||
if cp is not None:
|
||||
cp.update_strings(can_strings)
|
||||
|
||||
self.CS.button_events = []
|
||||
|
||||
# get CarState
|
||||
ret = self._update(c)
|
||||
|
||||
@@ -780,6 +784,8 @@ class CarStateBase(ABC):
|
||||
self.prev_mads_enabled = False
|
||||
self.control_initialized = False
|
||||
|
||||
self.button_events: list[capnp.lib.capnp._DynamicStructBuilder] = []
|
||||
|
||||
Q = [[0.0, 0.0], [0.0, 100.0]]
|
||||
R = 0.3
|
||||
A = [[1.0, DT_CTRL], [0.0, 1.0]]
|
||||
|
||||
@@ -11,8 +11,7 @@ from openpilot.selfdrive.car.mazda.values import CarControllerParams, Buttons
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import MAZDA_V_CRUISE_MIN
|
||||
|
||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||
|
||||
BUTTONS_STATES = ["accelCruise", "decelCruise", "cancel", "resumeCruise"]
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarController(CarControllerBase):
|
||||
@@ -141,8 +140,10 @@ class CarController(CarControllerBase):
|
||||
# multikyd methods, sunnyhaibin logic
|
||||
def get_cruise_buttons_status(self, CS):
|
||||
if not CS.out.cruiseState.enabled:
|
||||
if any(CS.buttonStates[button_state] for button_state in BUTTONS_STATES):
|
||||
self.timer = 40
|
||||
for be in CS.out.buttonEvents:
|
||||
if be.type in (ButtonType.accelCruise, ButtonType.resumeCruise,
|
||||
ButtonType.decelCruise, ButtonType.setCruise) and be.pressed:
|
||||
self.timer = 40
|
||||
elif self.timer:
|
||||
self.timer -= 1
|
||||
else:
|
||||
|
||||
@@ -3,7 +3,7 @@ from openpilot.common.conversions import Conversions as CV
|
||||
from opendbc.can.can_define import CANDefine
|
||||
from opendbc.can.parser import CANParser
|
||||
from openpilot.selfdrive.car.interfaces import CarStateBase
|
||||
from openpilot.selfdrive.car.mazda.values import DBC, LKAS_LIMITS, MazdaFlags, BUTTON_STATES
|
||||
from openpilot.selfdrive.car.mazda.values import DBC, LKAS_LIMITS, MazdaFlags, BUTTONS
|
||||
|
||||
class CarState(CarStateBase):
|
||||
def __init__(self, CP):
|
||||
@@ -24,8 +24,7 @@ class CarState(CarStateBase):
|
||||
self.lkas_enabled = False
|
||||
self.prev_lkas_enabled = False
|
||||
|
||||
self.buttonStates = BUTTON_STATES.copy()
|
||||
self.buttonStatesPrev = BUTTON_STATES.copy()
|
||||
self.button_states = {button.event_type: False for button in BUTTONS}
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
|
||||
@@ -36,7 +35,6 @@ class CarState(CarStateBase):
|
||||
|
||||
self.prev_mads_enabled = self.mads_enabled
|
||||
self.prev_lkas_enabled = self.lkas_enabled
|
||||
self.buttonStatesPrev = self.buttonStates.copy()
|
||||
|
||||
ret.wheelSpeeds = self.get_wheel_speeds(
|
||||
cp.vl["WHEEL_SPEEDS"]["FL"],
|
||||
@@ -56,6 +54,16 @@ class CarState(CarStateBase):
|
||||
can_gear = int(cp.vl["GEAR"]["GEAR"])
|
||||
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None))
|
||||
|
||||
# Buttons
|
||||
for button in BUTTONS:
|
||||
state = (cp.vl[button.can_addr][button.can_msg] in button.values)
|
||||
if self.button_states[button.event_type] != state:
|
||||
event = car.CarState.ButtonEvent.new_message()
|
||||
event.type = button.event_type
|
||||
event.pressed = state
|
||||
self.button_events.append(event)
|
||||
self.button_states[button.event_type] = state
|
||||
|
||||
ret.genericToggle = bool(cp.vl["BLINK_INFO"]["HIGH_BEAMS"])
|
||||
ret.leftBlindspot = cp.vl["BSM"]["LEFT_BS_STATUS"] != 0
|
||||
ret.rightBlindspot = cp.vl["BSM"]["RIGHT_BS_STATUS"] != 0
|
||||
@@ -114,11 +122,6 @@ class CarState(CarStateBase):
|
||||
|
||||
self.acc_active_last = ret.cruiseState.enabled
|
||||
|
||||
self.buttonStates["accelCruise"] = bool(cp.vl["CRZ_BTNS"]["SET_P"])
|
||||
self.buttonStates["decelCruise"] = bool(cp.vl["CRZ_BTNS"]["SET_M"])
|
||||
self.buttonStates["cancel"] = bool(cp.vl["CRZ_BTNS"]["CAN_OFF"])
|
||||
self.buttonStates["resumeCruise"] = bool(cp.vl["CRZ_BTNS"]["RES"])
|
||||
|
||||
self.crz_btns_counter = cp.vl["CRZ_BTNS"]["CTR"]
|
||||
|
||||
# camera signals
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.car.mazda.values import CAR, LKAS_LIMITS, BUTTON_STATES
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event
|
||||
from openpilot.selfdrive.car.mazda.values import CAR, LKAS_LIMITS
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
@@ -12,7 +12,6 @@ GearShifter = car.CarState.GearShifter
|
||||
class CarInterface(CarInterfaceBase):
|
||||
def __init__(self, CP, CarController, CarState):
|
||||
super().__init__(CP, CarController, CarState)
|
||||
self.buttonStatesPrev = BUTTON_STATES.copy()
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
@@ -41,19 +40,15 @@ class CarInterface(CarInterfaceBase):
|
||||
self.sp_update_params()
|
||||
|
||||
# TODO: add button types for inc and dec
|
||||
buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
|
||||
for button in self.CS.buttonStates:
|
||||
if self.CS.buttonStates[button] != self.buttonStatesPrev[button]:
|
||||
be = car.CarState.ButtonEvent.new_message()
|
||||
be.type = button
|
||||
be.pressed = self.CS.buttonStates[button]
|
||||
buttonEvents.append(be)
|
||||
self.CS.button_events = [
|
||||
*self.CS.button_events,
|
||||
*create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
]
|
||||
|
||||
self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS)
|
||||
|
||||
self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled,
|
||||
buttonEvents, c.vCruise)
|
||||
self.CS.button_events, c.vCruise)
|
||||
|
||||
if ret.cruiseState.available:
|
||||
if self.enable_mads:
|
||||
@@ -66,7 +61,7 @@ class CarInterface(CarInterfaceBase):
|
||||
self.CS.madsEnabled = False
|
||||
|
||||
if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed:
|
||||
if any(b.type == ButtonType.cancel for b in buttonEvents):
|
||||
if any(b.type == ButtonType.cancel for b in self.CS.button_events):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
if self.get_sp_pedal_disengage(ret):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
@@ -79,17 +74,10 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button))
|
||||
|
||||
# MADS BUTTON
|
||||
if self.CS.out.madsEnabled != self.CS.madsEnabled:
|
||||
if self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = False
|
||||
else:
|
||||
if not self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = True
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
ret.buttonEvents = [
|
||||
*self.CS.button_events,
|
||||
*self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON
|
||||
]
|
||||
|
||||
# events
|
||||
events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low, GearShifter.brake],
|
||||
@@ -108,6 +96,4 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret.events = events.to_msg()
|
||||
|
||||
self.buttonStatesPrev = self.CS.buttonStates.copy()
|
||||
|
||||
return ret
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from collections import namedtuple
|
||||
from dataclasses import dataclass, field
|
||||
from enum import IntFlag
|
||||
|
||||
@@ -8,6 +9,7 @@ from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarPar
|
||||
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
|
||||
|
||||
Ecu = car.CarParams.Ecu
|
||||
Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values'])
|
||||
|
||||
|
||||
# Steer torque limits
|
||||
@@ -26,14 +28,6 @@ class CarControllerParams:
|
||||
pass
|
||||
|
||||
|
||||
BUTTON_STATES = {
|
||||
"accelCruise": False,
|
||||
"decelCruise": False,
|
||||
"cancel": False,
|
||||
"resumeCruise": False,
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class MazdaCarDocs(CarDocs):
|
||||
package: str = "All"
|
||||
@@ -98,6 +92,14 @@ class Buttons:
|
||||
CANCEL = 4
|
||||
|
||||
|
||||
BUTTONS = [
|
||||
Button(car.CarState.ButtonEvent.Type.accelCruise, "CRZ_BTNS", "SET_P", [1]),
|
||||
Button(car.CarState.ButtonEvent.Type.decelCruise, "CRZ_BTNS", "SET_M", [1]),
|
||||
Button(car.CarState.ButtonEvent.Type.cancel, "CRZ_BTNS", "CAN_OFF", [1]),
|
||||
Button(car.CarState.ButtonEvent.Type.resumeCruise, "CRZ_BTNS", "RES", [1]),
|
||||
]
|
||||
|
||||
|
||||
FW_QUERY_CONFIG = FwQueryConfig(
|
||||
requests=[
|
||||
# TODO: check data to ensure ABS does not skip ISO-TP frames on bus 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from cereal import car
|
||||
from panda import Panda
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
from openpilot.selfdrive.car.nissan.values import CAR
|
||||
|
||||
@@ -34,7 +34,7 @@ class CarInterface(CarInterfaceBase):
|
||||
ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam)
|
||||
self.sp_update_params()
|
||||
|
||||
buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
self.CS.button_events = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
|
||||
self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS)
|
||||
|
||||
@@ -53,24 +53,11 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button))
|
||||
|
||||
# CANCEL
|
||||
if self.CS.out.cruiseState.enabled and not ret.cruiseState.enabled:
|
||||
be = car.CarState.ButtonEvent.new_message()
|
||||
be.pressed = True
|
||||
be.type = ButtonType.cancel
|
||||
buttonEvents.append(be)
|
||||
|
||||
# MADS BUTTON
|
||||
if self.CS.out.madsEnabled != self.CS.madsEnabled:
|
||||
if self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = False
|
||||
else:
|
||||
if not self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = True
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
ret.buttonEvents = [
|
||||
*self.CS.button_events,
|
||||
*self.button_events.create_cancel_event(ret.cruiseState.enabled, self.CS.out.cruiseState.enabled),
|
||||
*self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON
|
||||
]
|
||||
|
||||
events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low, GearShifter.brake],
|
||||
pcm_enable=False)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from cereal import car
|
||||
from panda import Panda
|
||||
from openpilot.selfdrive.car import get_safety_config, create_mads_event
|
||||
from openpilot.selfdrive.car import get_safety_config
|
||||
from openpilot.selfdrive.car.disable_ecu import disable_ecu
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
from openpilot.selfdrive.car.subaru.values import CAR, GLOBAL_ES_ADDR, SubaruFlags, SubaruFlagsSP
|
||||
@@ -118,8 +118,6 @@ class CarInterface(CarInterfaceBase):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_body)
|
||||
self.sp_update_params()
|
||||
|
||||
buttonEvents = []
|
||||
|
||||
self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS)
|
||||
|
||||
if ret.cruiseState.available:
|
||||
@@ -145,24 +143,11 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret, self.CS = self.get_sp_common_state(ret, self.CS)
|
||||
|
||||
# CANCEL
|
||||
if self.CS.out.cruiseState.enabled and not ret.cruiseState.enabled:
|
||||
be = car.CarState.ButtonEvent.new_message()
|
||||
be.pressed = True
|
||||
be.type = ButtonType.cancel
|
||||
buttonEvents.append(be)
|
||||
|
||||
# MADS BUTTON
|
||||
if self.CS.out.madsEnabled != self.CS.madsEnabled:
|
||||
if self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = False
|
||||
else:
|
||||
if not self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = True
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
ret.buttonEvents = [
|
||||
*self.CS.button_events,
|
||||
*self.button_events.create_cancel_event(ret.cruiseState.enabled, self.CS.out.cruiseState.enabled),
|
||||
*self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON
|
||||
]
|
||||
|
||||
events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low], pcm_enable=False)
|
||||
|
||||
|
||||
@@ -61,12 +61,6 @@ class CarController(CarControllerBase):
|
||||
self.right_blindspot_debug_enabled = False
|
||||
self.last_blindspot_frame = 0
|
||||
|
||||
if CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD:
|
||||
self.brake_hold_active: bool = False
|
||||
self._brake_hold_counter: int = 0
|
||||
self._brake_hold_reset: bool = False
|
||||
self._prev_brake_pressed: bool = False
|
||||
|
||||
self._auto_lock_by_speed = self.param_s.get_bool("ToyotaAutoLockBySpeed")
|
||||
self._auto_unlock_by_shifter = self.param_s.get_bool("ToyotaAutoUnlockByShifter")
|
||||
self._auto_lock_speed = 10 * (CV.KPH_TO_MS if self._is_metric else CV.MPH_TO_MS)
|
||||
@@ -187,9 +181,6 @@ class CarController(CarControllerBase):
|
||||
|
||||
self.last_standstill = CS.out.standstill
|
||||
|
||||
if self.CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD:
|
||||
can_sends.extend(self.create_auto_brake_hold_messages(CS))
|
||||
|
||||
# handle UI messages
|
||||
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
|
||||
steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw)
|
||||
@@ -308,25 +299,3 @@ class CarController(CarControllerBase):
|
||||
# print("bsm poll right")
|
||||
|
||||
return can_sends
|
||||
|
||||
# auto brake hold (https://github.com/AlexandreSato/)
|
||||
def create_auto_brake_hold_messages(self, CS: car.CarState, brake_hold_allowed_timer: int = 100):
|
||||
can_sends = []
|
||||
disallowed_gears = [GearShifter.park, GearShifter.reverse]
|
||||
brake_hold_allowed = CS.out.standstill and CS.out.cruiseState.available and not CS.out.gasPressed and \
|
||||
not CS.out.cruiseState.enabled and (CS.out.gearShifter not in disallowed_gears)
|
||||
|
||||
if brake_hold_allowed:
|
||||
self._brake_hold_counter += 1
|
||||
self.brake_hold_active = self._brake_hold_counter > brake_hold_allowed_timer and not self._brake_hold_reset
|
||||
self._brake_hold_reset = not self._prev_brake_pressed and CS.out.brakePressed and not self._brake_hold_reset
|
||||
else:
|
||||
self._brake_hold_counter = 0
|
||||
self.brake_hold_active = False
|
||||
self._brake_hold_reset = False
|
||||
self._prev_brake_pressed = CS.out.brakePressed
|
||||
|
||||
if self.frame % 2 == 0:
|
||||
can_sends.append(toyotacan.create_brake_hold_command(self.packer, self.frame, CS.pre_collision_2, self.brake_hold_active))
|
||||
|
||||
return can_sends
|
||||
|
||||
@@ -79,9 +79,6 @@ class CarState(CarStateBase):
|
||||
self._right_blindspot_d2 = 0
|
||||
self._right_blindspot_counter = 0
|
||||
|
||||
if CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD:
|
||||
self.pre_collision_2 = {}
|
||||
|
||||
self.frame = 0
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
@@ -263,9 +260,6 @@ class CarState(CarStateBase):
|
||||
if self.CP.spFlags & ToyotaFlagsSP.SP_ENHANCED_BSM and self.frame > 199:
|
||||
ret.leftBlindspot, ret.rightBlindspot = self.sp_get_enhanced_bsm(cp)
|
||||
|
||||
if self.CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD:
|
||||
self.pre_collision_2 = copy.copy(cp_cam.vl["PRE_COLLISION_2"])
|
||||
|
||||
self._update_traffic_signals(cp_cam)
|
||||
ret.cruiseState.speedLimit = self._calculate_speed_limit()
|
||||
self.frame += 1
|
||||
@@ -469,7 +463,4 @@ class CarState(CarStateBase):
|
||||
("PCS_HUD", 1),
|
||||
]
|
||||
|
||||
if CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD:
|
||||
messages.append(("PRE_COLLISION_2", 33))
|
||||
|
||||
return CANParser(DBC[CP.carFingerprint]["pt"], messages, 2)
|
||||
|
||||
@@ -5,7 +5,7 @@ from panda import Panda
|
||||
from panda.python import uds
|
||||
from openpilot.selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, ToyotaFlagsSP, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \
|
||||
MIN_ACC_SPEED, EPS_SCALE, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.disable_ecu import disable_ecu
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
|
||||
@@ -195,9 +195,6 @@ class CarInterface(CarInterfaceBase):
|
||||
if candidate == CAR.TOYOTA_PRIUS_TSS2:
|
||||
ret.spFlags |= ToyotaFlagsSP.SP_NEED_DEBUG_BSM.value
|
||||
|
||||
if Params().get_bool("ToyotaAutoHold") and candidate in (TSS2_CAR - RADAR_ACC_CAR):
|
||||
ret.spFlags |= ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD.value
|
||||
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
@@ -212,11 +209,10 @@ class CarInterface(CarInterfaceBase):
|
||||
ret = self.CS.update(self.cp, self.cp_cam)
|
||||
self.sp_update_params()
|
||||
|
||||
buttonEvents = []
|
||||
distance_button = 0
|
||||
|
||||
if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR) or (self.CP.flags & ToyotaFlags.SMART_DSU and not self.CP.flags & ToyotaFlags.RADAR_CAN_FILTER):
|
||||
buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
self.CS.button_events = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
distance_button = self.CS.distance_button
|
||||
|
||||
self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS)
|
||||
@@ -245,24 +241,11 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(distance_button))
|
||||
|
||||
# CANCEL
|
||||
if self.CS.out.cruiseState.enabled and not ret.cruiseState.enabled:
|
||||
be = car.CarState.ButtonEvent.new_message()
|
||||
be.pressed = True
|
||||
be.type = ButtonType.cancel
|
||||
buttonEvents.append(be)
|
||||
|
||||
# MADS BUTTON
|
||||
if self.CS.out.madsEnabled != self.CS.madsEnabled:
|
||||
if self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = False
|
||||
else:
|
||||
if not self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = True
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
ret.buttonEvents = [
|
||||
*self.CS.button_events,
|
||||
*self.button_events.create_cancel_event(ret.cruiseState.enabled, self.CS.out.cruiseState.enabled),
|
||||
*self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON
|
||||
]
|
||||
|
||||
# events
|
||||
events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low, GearShifter.brake],
|
||||
@@ -289,11 +272,6 @@ class CarInterface(CarInterfaceBase):
|
||||
# while in standstill, send a user alert
|
||||
events.add(EventName.manualRestart)
|
||||
|
||||
# auto brake hold
|
||||
if self.CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD:
|
||||
if self.CC.brake_hold_active and not ret.brakeHoldActive:
|
||||
events.add(EventName.spAutoBrakeHold)
|
||||
|
||||
ret.events = events.to_msg()
|
||||
|
||||
return ret
|
||||
|
||||
@@ -130,37 +130,3 @@ def create_set_bsm_debug_mode(lr_blindspot, enabled):
|
||||
|
||||
def create_bsm_polling_status(lr_blindspot):
|
||||
return make_can_msg(0x750, lr_blindspot + b"\x02\x21\x69\x00\x00\x00\x00", 0)
|
||||
|
||||
|
||||
# auto brake hold
|
||||
def create_brake_hold_command(packer, frame, pre_collision_2, brake_hold_active):
|
||||
# forward PRE_COLLISION_2 when auto brake hold is not active
|
||||
values = {s: pre_collision_2[s] for s in [
|
||||
"DSS1GDRV",
|
||||
"DS1STAT2",
|
||||
"DS1STBK2",
|
||||
"PCSWAR",
|
||||
"PCSALM",
|
||||
"PCSOPR",
|
||||
"PCSABK",
|
||||
"PBATRGR",
|
||||
"PPTRGR",
|
||||
"IBTRGR",
|
||||
"CLEXTRGR",
|
||||
"IRLT_REQ",
|
||||
"BRKHLD",
|
||||
"AVSTRGR",
|
||||
"VGRSTRGR",
|
||||
"PREFILL",
|
||||
"PBRTRGR",
|
||||
"PCSDIS",
|
||||
"PBPREPMP",
|
||||
]}
|
||||
|
||||
if brake_hold_active:
|
||||
values = {
|
||||
"DSS1GDRV": 0x3FF,
|
||||
"PBRTRGR": frame % 730 < 727, # cut actuation for 3 frames
|
||||
}
|
||||
|
||||
return packer.make_can_msg("PRE_COLLISION_2", 0, values)
|
||||
|
||||
@@ -64,7 +64,6 @@ class ToyotaFlagsSP(IntFlag):
|
||||
SP_ZSS = 1
|
||||
SP_ENHANCED_BSM = 2
|
||||
SP_NEED_DEBUG_BSM = 4
|
||||
SP_AUTO_BRAKE_HOLD = 8
|
||||
|
||||
|
||||
class Footnote(Enum):
|
||||
|
||||
@@ -4,7 +4,7 @@ from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.car.interfaces import CarStateBase
|
||||
from opendbc.can.parser import CANParser
|
||||
from openpilot.selfdrive.car.volkswagen.values import DBC, CANBUS, NetworkLocation, TransmissionType, GearShifter, \
|
||||
CarControllerParams, VolkswagenFlags, BUTTON_STATES, VolkswagenFlagsSP
|
||||
CarControllerParams, VolkswagenFlags, VolkswagenFlagsSP
|
||||
|
||||
|
||||
class CarState(CarStateBase):
|
||||
@@ -17,8 +17,6 @@ class CarState(CarStateBase):
|
||||
self.esp_hold_confirmation = False
|
||||
self.upscale_lead_car_signal = False
|
||||
self.eps_stock_values = False
|
||||
self.buttonStates = BUTTON_STATES.copy()
|
||||
self.buttonStatesPrev = BUTTON_STATES.copy()
|
||||
|
||||
def create_button_events(self, pt_cp, buttons):
|
||||
button_events = []
|
||||
@@ -41,7 +39,6 @@ class CarState(CarStateBase):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
self.prev_mads_enabled = self.mads_enabled
|
||||
self.buttonStatesPrev = self.buttonStates.copy()
|
||||
|
||||
# Update vehicle speed and acceleration from ABS wheel speeds.
|
||||
ret.wheelSpeeds = self.get_wheel_speeds(
|
||||
@@ -150,18 +147,10 @@ class CarState(CarStateBase):
|
||||
if ret.cruiseState.speed > 90:
|
||||
ret.cruiseState.speed = 0
|
||||
|
||||
# Update control button states for turn signals and ACC controls.
|
||||
self.buttonStates["accelCruise"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Tip_Hoch"])
|
||||
self.buttonStates["decelCruise"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Tip_Runter"])
|
||||
self.buttonStates["cancel"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Abbrechen"])
|
||||
self.buttonStates["setCruise"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Tip_Setzen"])
|
||||
self.buttonStates["resumeCruise"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Tip_Wiederaufnahme"])
|
||||
self.buttonStates["gapAdjustCruise"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Verstellung_Zeitluecke"])
|
||||
|
||||
# Update button states for turn signals and ACC controls, capture all ACC button state/config for passthrough
|
||||
ret.leftBlinker = ret.leftBlinkerOn = bool(pt_cp.vl["Blinkmodi_02"]["Comfort_Signal_Left"])
|
||||
ret.rightBlinker = ret.rightBlinkerOn = bool(pt_cp.vl["Blinkmodi_02"]["Comfort_Signal_Right"])
|
||||
ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS)
|
||||
self.button_events = self.create_button_events(pt_cp, self.CCP.BUTTONS)
|
||||
self.gra_stock_values = pt_cp.vl["GRA_ACC_01"]
|
||||
|
||||
# Additional safety checks performed in CarInterface.
|
||||
@@ -177,7 +166,6 @@ class CarState(CarStateBase):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
self.prev_mads_enabled = self.mads_enabled
|
||||
self.buttonStatesPrev = self.buttonStates.copy()
|
||||
|
||||
# Update vehicle speed and acceleration from ABS wheel speeds.
|
||||
ret.wheelSpeeds = self.get_wheel_speeds(
|
||||
@@ -265,18 +253,10 @@ class CarState(CarStateBase):
|
||||
if ret.cruiseState.speed > 70: # 255 kph in m/s == no current setpoint
|
||||
ret.cruiseState.speed = 0
|
||||
|
||||
# Update control button states for turn signals and ACC controls.
|
||||
self.buttonStates["accelCruise"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Up_kurz"])
|
||||
self.buttonStates["decelCruise"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Down_kurz"])
|
||||
self.buttonStates["cancel"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Abbrechen"])
|
||||
self.buttonStates["setCruise"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Neu_Setzen"])
|
||||
self.buttonStates["resumeCruise"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Recall"])
|
||||
self.buttonStates["gapAdjustCruise"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Zeitluecke"])
|
||||
|
||||
# Update button states for turn signals and ACC controls, capture all ACC button state/config for passthrough
|
||||
ret.leftBlinker, ret.rightBlinker = ret.leftBlinkerOn, ret.rightBlinkerOn = self.update_blinker_from_stalk(300, pt_cp.vl["Gate_Komf_1"]["GK1_Blinker_li"],
|
||||
pt_cp.vl["Gate_Komf_1"]["GK1_Blinker_re"])
|
||||
ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS)
|
||||
self.button_events = self.create_button_events(pt_cp, self.CCP.BUTTONS)
|
||||
self.gra_stock_values = pt_cp.vl["GRA_Neu"]
|
||||
|
||||
# Additional safety checks performed in CarInterface.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from cereal import car
|
||||
from panda import Panda
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.car import get_safety_config, create_mads_event
|
||||
from openpilot.selfdrive.car import get_safety_config
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
from openpilot.selfdrive.car.volkswagen.values import CAR, CANBUS, CarControllerParams, NetworkLocation, TransmissionType, GearShifter, VolkswagenFlags, \
|
||||
BUTTON_STATES, VolkswagenFlagsSP
|
||||
VolkswagenFlagsSP
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
EventName = car.CarEvent.EventName
|
||||
@@ -21,8 +21,6 @@ class CarInterface(CarInterfaceBase):
|
||||
self.ext_bus = CANBUS.cam
|
||||
self.cp_ext = self.cp_cam
|
||||
|
||||
self.buttonStatesPrev = BUTTON_STATES.copy()
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "volkswagen"
|
||||
@@ -117,21 +115,10 @@ class CarInterface(CarInterfaceBase):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_ext, self.CP.transmissionType)
|
||||
self.sp_update_params()
|
||||
|
||||
buttonEvents = []
|
||||
|
||||
# Check for and process state-change events (button press or release) from
|
||||
# the turn stalk switch or ACC steering wheel/control stalk buttons.
|
||||
for button in self.CS.buttonStates:
|
||||
if self.CS.buttonStates[button] != self.buttonStatesPrev[button]:
|
||||
be = car.CarState.ButtonEvent.new_message()
|
||||
be.type = button
|
||||
be.pressed = self.CS.buttonStates[button]
|
||||
buttonEvents.append(be)
|
||||
|
||||
self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS)
|
||||
|
||||
self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled,
|
||||
buttonEvents, c.vCruise,
|
||||
self.CS.button_events, c.vCruise,
|
||||
enable_buttons=(ButtonType.setCruise, ButtonType.resumeCruise))
|
||||
|
||||
if ret.cruiseState.available:
|
||||
@@ -144,7 +131,7 @@ class CarInterface(CarInterfaceBase):
|
||||
self.CS.madsEnabled = self.get_sp_started_mads(ret, self.CS)
|
||||
|
||||
if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed:
|
||||
if any(b.type == ButtonType.cancel for b in buttonEvents):
|
||||
if any(b.type == ButtonType.cancel for b in self.CS.button_events):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
if self.get_sp_pedal_disengage(ret):
|
||||
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
|
||||
@@ -155,19 +142,13 @@ class CarInterface(CarInterfaceBase):
|
||||
self.CS.accEnabled = False
|
||||
self.CS.accEnabled = ret.cruiseState.enabled or self.CS.accEnabled
|
||||
|
||||
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.buttonStates["gapAdjustCruise"]))
|
||||
ret, self.CS = self.get_sp_common_state(ret, self.CS,
|
||||
gap_button=any(b.type == ButtonType.gapAdjustCruise and b.pressed for b in self.CS.button_events))
|
||||
|
||||
# MADS BUTTON
|
||||
if self.CS.out.madsEnabled != self.CS.madsEnabled:
|
||||
if self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = False
|
||||
else:
|
||||
if not self.mads_event_lock:
|
||||
buttonEvents.append(create_mads_event(self.mads_event_lock))
|
||||
self.mads_event_lock = True
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
ret.buttonEvents = [
|
||||
*self.CS.button_events,
|
||||
*self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON
|
||||
]
|
||||
|
||||
events = self.create_common_events(ret, c, extra_gears=[GearShifter.eco, GearShifter.sport, GearShifter.manumatic],
|
||||
pcm_enable=False,
|
||||
@@ -199,8 +180,4 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret.events = events.to_msg()
|
||||
|
||||
# update previous car states
|
||||
self.buttonStatesPrev = self.CS.buttonStates.copy()
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@@ -147,16 +147,6 @@ class VolkswagenFlagsSP(IntFlag):
|
||||
SP_CC_ONLY_NO_RADAR = 2
|
||||
|
||||
|
||||
BUTTON_STATES = {
|
||||
"accelCruise": False,
|
||||
"decelCruise": False,
|
||||
"cancel": False,
|
||||
"setCruise": False,
|
||||
"resumeCruise": False,
|
||||
"gapAdjustCruise": False
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class VolkswagenMQBPlatformConfig(PlatformConfig):
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: dbc_dict('vw_mqb_2010', None))
|
||||
|
||||
@@ -744,14 +744,6 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"),
|
||||
},
|
||||
|
||||
EventName.spAutoBrakeHold: {
|
||||
ET.PERMANENT: Alert(
|
||||
"sunnypilot Brake Hold Active",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.small,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.prompt, 0.),
|
||||
},
|
||||
|
||||
EventName.parkBrake: {
|
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
|
||||
ET.NO_ENTRY: NoEntryAlert("Parking Brake Engaged"),
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
|
||||
#include "common/util.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h"
|
||||
#else
|
||||
#include "selfdrive/ui/qt/maps/map_helpers.h"
|
||||
#endif
|
||||
#include "selfdrive/navd/map_renderer.h"
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
#include "common/util.h"
|
||||
#include "common/timing.h"
|
||||
#include "common/swaglog.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h"
|
||||
#else
|
||||
#include "selfdrive/ui/qt/maps/map_helpers.h"
|
||||
#endif
|
||||
|
||||
const float DEFAULT_ZOOM = 13.5; // Don't go below 13 or features will start to disappear
|
||||
const int HEIGHT = 256, WIDTH = 256;
|
||||
|
||||
+11
-8
@@ -18,30 +18,32 @@ if arch == "Darwin":
|
||||
qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"]
|
||||
|
||||
sp_widgets_src = []
|
||||
sp_maps_widgets_src = []
|
||||
sp_qt_src = []
|
||||
if GetOption('sunnypilot'):
|
||||
sp_qt_util = []
|
||||
if not GetOption('stock_ui'):
|
||||
SConscript(['sunnypilot/SConscript'])
|
||||
Import('sp_widgets_src', 'sp_qt_src')
|
||||
Import('sp_widgets_src', 'sp_maps_widgets_src', 'sp_qt_src', "sp_qt_util")
|
||||
|
||||
qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"], LIBS=base_libs)
|
||||
qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"] + sp_qt_util, LIBS=base_libs)
|
||||
widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/wifi.cc",
|
||||
"qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc",
|
||||
"qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc",
|
||||
"qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc",
|
||||
"qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc"] + sp_widgets_src
|
||||
|
||||
qt_env['CPPDEFINES'] = ["SUNNYPILOT"] if GetOption('sunnypilot') else []
|
||||
qt_env['CPPDEFINES'] = []
|
||||
if maps:
|
||||
base_libs += ['QMapLibre']
|
||||
widgets_src += ["qt/maps/map_helpers.cc", "qt/maps/map_settings.cc", "qt/maps/map.cc", "qt/maps/map_panel.cc",
|
||||
"qt/maps/map_eta.cc", "qt/maps/map_instructions.cc"]
|
||||
"qt/maps/map_eta.cc", "qt/maps/map_instructions.cc"] + sp_maps_widgets_src
|
||||
qt_env['CPPDEFINES'] += ["ENABLE_MAPS"]
|
||||
|
||||
widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=base_libs)
|
||||
Export('widgets')
|
||||
qt_libs = [widgets, qt_util] + base_libs
|
||||
|
||||
qt_src = ["main.cc", "qt/sidebar.cc", "qt/body.cc",
|
||||
qt_src = ["main.cc", "qt/sidebar.cc", "qt/body.cc", "qt/offroad_home.cc",
|
||||
"qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc",
|
||||
"qt/offroad/software_settings.cc", "qt/offroad/onboarding.cc",
|
||||
"qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc",
|
||||
@@ -79,14 +81,15 @@ asset_obj = qt_env.Object("assets", assets)
|
||||
qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs)
|
||||
|
||||
# spinner and text window
|
||||
qt_env.Program("_text", ["qt/text.cc"], LIBS=qt_libs)
|
||||
text_cc_path = "qt/text.cc" if GetOption('stock_ui') else "sunnypilot/qt/text.cc"
|
||||
qt_env.Program("_text", [text_cc_path], LIBS=qt_libs)
|
||||
qt_env.Program("_spinner", ["qt/spinner.cc"], LIBS=qt_libs)
|
||||
|
||||
# build main UI
|
||||
qt_env.Program("ui", qt_src + [asset_obj], LIBS=qt_libs)
|
||||
if GetOption('extras'):
|
||||
qt_src.remove("main.cc") # replaced by test_runner
|
||||
#qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs)
|
||||
qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs)
|
||||
qt_env.Program('tests/ui_snapshot', [asset_obj, "tests/ui_snapshot.cc"] + qt_src, LIBS=qt_libs)
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
#include "system/hardware/hw.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/window.h"
|
||||
#define MainWindow MainWindowSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/window.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
setpriority(PRIO_PROCESS, 0, -20);
|
||||
@@ -22,7 +28,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
QApplication a(argc, argv);
|
||||
a.installTranslator(&translator);
|
||||
|
||||
MainWindow w;
|
||||
setMainWindow(&w);
|
||||
a.installEventFilter(&w);
|
||||
|
||||
+19
-143
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/aes.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCryptographicHash>
|
||||
@@ -10,12 +9,10 @@
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkRequest>
|
||||
#include <QSsl>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "common/util.h"
|
||||
#include "system/hardware/hw.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
@@ -48,130 +45,11 @@ QByteArray rsa_sign(const QByteArray &data) {
|
||||
return sig;
|
||||
}
|
||||
|
||||
void derive_aes_key_iv_from_rsa(EVP_PKEY *rsa_key, unsigned char *aes_key, unsigned char *aes_iv) {
|
||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||
size_t pub_len;
|
||||
unsigned char *pub_key;
|
||||
|
||||
// Convert RSA key to public key in DER format for simplicity
|
||||
pub_len = i2d_PublicKey(rsa_key, NULL);
|
||||
pub_key = (unsigned char *)malloc(pub_len);
|
||||
unsigned char *tmp = pub_key;
|
||||
i2d_PublicKey(rsa_key, &tmp);
|
||||
|
||||
// Hash the public key to derive bytes for AES key and IV
|
||||
SHA256(pub_key, pub_len, hash);
|
||||
|
||||
// Assuming AES-256-CBC, we need 32 bytes for the key and 16 for the IV
|
||||
memcpy(aes_key, hash, 32); // First 32 bytes for AES key
|
||||
memcpy(aes_iv, hash + 32 - 16, 16); // Last 16 bytes for AES IV
|
||||
|
||||
free(pub_key);
|
||||
}
|
||||
|
||||
EVP_PKEY *load_public_key(const char *file) {
|
||||
EVP_PKEY *key = NULL;
|
||||
FILE *fp = fopen(file, "r");
|
||||
if (fp) {
|
||||
key = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
|
||||
fclose(fp);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
EVP_PKEY *load_private_key(const char *file) {
|
||||
EVP_PKEY *key = NULL;
|
||||
FILE *fp = fopen(file, "r");
|
||||
if (fp) {
|
||||
key = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
|
||||
fclose(fp);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
QByteArray rsa_encrypt(const QByteArray &data) {
|
||||
EVP_PKEY *rsa_key = load_public_key(Path::rsa_pub_file().c_str()); // Load your RSA key
|
||||
unsigned char aes_key[32], aes_iv[16];
|
||||
derive_aes_key_iv_from_rsa(rsa_key, aes_key, aes_iv);
|
||||
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
if (!(ctx = EVP_CIPHER_CTX_new())) {
|
||||
// Handle error: Allocate memory failed
|
||||
return {};
|
||||
}
|
||||
|
||||
if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, aes_key, aes_iv) != 1) {
|
||||
qDebug() << "Failed to initialize encryption";
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return {};
|
||||
}
|
||||
|
||||
int ciphertext_len;
|
||||
int len = data.size();
|
||||
unsigned char out[len + AES_BLOCK_SIZE];
|
||||
auto *in = (unsigned char*) data.constData();
|
||||
if (EVP_EncryptUpdate(ctx, out, &ciphertext_len, in, len) != 1) {
|
||||
qDebug() << "Failed to update encryption";
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (EVP_EncryptFinal_ex(ctx, out + ciphertext_len, &len) != 1) {
|
||||
// Handle error: Encryption finalize failed
|
||||
qDebug() << "Failed to finalize encryption";
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return {};
|
||||
}
|
||||
|
||||
//qDebug() << "Encrypted data length: %d", ciphertext_len + len; // Print the length of encrypted data
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return {reinterpret_cast<char*>(out), ciphertext_len + len};
|
||||
}
|
||||
|
||||
QByteArray rsa_decrypt(const QByteArray &data) {
|
||||
EVP_PKEY *rsa_key = load_public_key(Path::rsa_pub_file().c_str()); // Load your RSA key
|
||||
unsigned char aes_key[32], aes_iv[16];
|
||||
derive_aes_key_iv_from_rsa(rsa_key, aes_key, aes_iv);
|
||||
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
if (!(ctx = EVP_CIPHER_CTX_new())) {
|
||||
qDebug() << "Failed to allocate memory for EVP_CIPHER_CTX";
|
||||
return {};
|
||||
}
|
||||
|
||||
if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, aes_key, aes_iv) != 1) {
|
||||
qDebug() << "Failed to initialize EVP";
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return {};
|
||||
}
|
||||
|
||||
int len = data.size();
|
||||
unsigned char out[len + AES_BLOCK_SIZE];
|
||||
auto *in = (unsigned char*) data.constData();
|
||||
if (EVP_DecryptUpdate(ctx, out, &len, in, len) != 1) {
|
||||
qDebug() << "Failed to update decryption";
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return {};
|
||||
}
|
||||
|
||||
int final_len;
|
||||
if (EVP_DecryptFinal_ex(ctx, out + len, &final_len) != 1) {
|
||||
qDebug() << "Failed to finalize decryption";
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return {};
|
||||
}
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
//qDebug() << "Decrypted data length: %d", len + final_len; // Print the length of decrypted data
|
||||
return {reinterpret_cast<char*>(out), len + final_len};
|
||||
}
|
||||
|
||||
QString create_jwt(const QJsonObject &payloads, int expiry, bool sunnylink) {
|
||||
QString create_jwt(const QJsonObject &payloads, int expiry) {
|
||||
QJsonObject header = {{"alg", "RS256"}};
|
||||
|
||||
auto t = QDateTime::currentSecsSinceEpoch();
|
||||
auto dongle_id = sunnylink ? getSunnylinkDongleId() : getDongleId();
|
||||
QJsonObject payload = {{"identity", dongle_id.value_or("")}, {"nbf", t}, {"iat", t}, {"exp", t + expiry}};
|
||||
QJsonObject payload = {{"identity", getDongleId().value_or("")}, {"nbf", t}, {"iat", t}, {"exp", t + expiry}};
|
||||
for (auto it = payloads.begin(); it != payloads.end(); ++it) {
|
||||
payload.insert(it.key(), it.value());
|
||||
}
|
||||
@@ -186,7 +64,7 @@ QString create_jwt(const QJsonObject &payloads, int expiry, bool sunnylink) {
|
||||
|
||||
} // namespace CommaApi
|
||||
|
||||
HttpRequest::HttpRequest(QObject *parent, bool create_jwt, int timeout, const bool sunnylink) : create_jwt(create_jwt), sunnylink(sunnylink), QObject(parent) {
|
||||
HttpRequest::HttpRequest(QObject *parent, bool create_jwt, int timeout) : create_jwt(create_jwt), QObject(parent) {
|
||||
networkTimer = new QTimer(this);
|
||||
networkTimer->setSingleShot(true);
|
||||
networkTimer->setInterval(timeout);
|
||||
@@ -201,40 +79,38 @@ bool HttpRequest::timeout() const {
|
||||
return reply && reply->error() == QNetworkReply::OperationCanceledError;
|
||||
}
|
||||
|
||||
void HttpRequest::sendRequest(const QString &requestURL, const HttpRequest::Method method, const QByteArray &payload) {
|
||||
LOGD("Requesting %s", qPrintable(requestURL));
|
||||
if (active()) {
|
||||
qDebug() << "HttpRequest is active";
|
||||
return;
|
||||
}
|
||||
QNetworkRequest HttpRequest::prepareRequest(const QString &requestURL)
|
||||
{
|
||||
QNetworkRequest request;
|
||||
QString token;
|
||||
if (create_jwt) {
|
||||
token = CommaApi::create_jwt({}, 3600, sunnylink);
|
||||
token = GetJwtToken();
|
||||
} else {
|
||||
QString token_json = QString::fromStdString(util::read_file(util::getenv("HOME") + "/.comma/auth.json"));
|
||||
QJsonDocument json_d = QJsonDocument::fromJson(token_json.toUtf8());
|
||||
token = json_d["access_token"].toString();
|
||||
}
|
||||
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl(requestURL));
|
||||
request.setRawHeader("User-Agent", getUserAgent(sunnylink).toUtf8());
|
||||
if (!payload.isEmpty()) {
|
||||
request.setRawHeader("Content-Type", "application/json");
|
||||
}
|
||||
request.setRawHeader("User-Agent", GetUserAgent().toUtf8());
|
||||
|
||||
if (!token.isEmpty()) {
|
||||
request.setRawHeader(QByteArray("Authorization"), ("JWT " + token).toUtf8());
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
if (method == HttpRequest::Method::GET) {
|
||||
void HttpRequest::sendRequest(const QString &requestURL, const Method method) {
|
||||
if (active()) {
|
||||
qDebug() << "HttpRequest is active";
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest request = prepareRequest(requestURL);
|
||||
if (method == Method::GET) {
|
||||
reply = nam()->get(request);
|
||||
} else if (method == HttpRequest::Method::DELETE) {
|
||||
} else if (method == Method::DELETE) {
|
||||
reply = nam()->deleteResource(request);
|
||||
} else if (method == HttpRequest::Method::POST) {
|
||||
reply = nam()->post(request, payload);
|
||||
} else if (method == HttpRequest::Method::PUT) {
|
||||
reply = nam()->put(request, payload);
|
||||
}
|
||||
|
||||
networkTimer->start();
|
||||
|
||||
@@ -6,14 +6,13 @@
|
||||
#include <QTimer>
|
||||
|
||||
#include "common/util.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
namespace CommaApi {
|
||||
|
||||
const QString BASE_URL = util::getenv("API_HOST", "https://api.commadotai.com").c_str();
|
||||
QByteArray rsa_sign(const QByteArray &data);
|
||||
QByteArray rsa_encrypt(const QByteArray &data);
|
||||
QByteArray rsa_decrypt(const QByteArray &data);
|
||||
QString create_jwt(const QJsonObject &payloads = {}, int expiry = 3600, bool sunnylink = false);
|
||||
QString create_jwt(const QJsonObject &payloads = {}, int expiry = 3600);
|
||||
|
||||
} // namespace CommaApi
|
||||
|
||||
@@ -27,8 +26,9 @@ class HttpRequest : public QObject {
|
||||
public:
|
||||
enum class Method {GET, DELETE, POST, PUT};
|
||||
|
||||
explicit HttpRequest(QObject* parent, bool create_jwt = true, int timeout = 20000, const bool sunnylink = false);
|
||||
void sendRequest(const QString &requestURL, const Method method = Method::GET, const QByteArray &payload = {});
|
||||
explicit HttpRequest(QObject* parent, bool create_jwt = true, int timeout = 20000);
|
||||
virtual void sendRequest(const QString &requestURL, Method method);
|
||||
void sendRequest(const QString &requestURL) { sendRequest(requestURL, Method::GET);}
|
||||
bool active() const;
|
||||
bool timeout() const;
|
||||
|
||||
@@ -37,14 +37,14 @@ signals:
|
||||
|
||||
protected:
|
||||
QNetworkReply *reply = nullptr;
|
||||
|
||||
private:
|
||||
static QNetworkAccessManager *nam();
|
||||
QTimer *networkTimer = nullptr;
|
||||
bool create_jwt;
|
||||
bool sunnylink;
|
||||
virtual QNetworkRequest prepareRequest(const QString& requestURL);
|
||||
virtual QString GetJwtToken() const { return CommaApi::create_jwt(); }
|
||||
virtual QString GetUserAgent() const { return getUserAgent(); }
|
||||
|
||||
private slots:
|
||||
protected slots:
|
||||
void requestTimeout();
|
||||
void requestFinished();
|
||||
};
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
#include <QPushButton>
|
||||
|
||||
#include "common/util.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
class RecordButton : public QPushButton {
|
||||
Q_OBJECT
|
||||
|
||||
+1
-171
@@ -9,10 +9,6 @@
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/widgets/prime.h"
|
||||
|
||||
#ifdef ENABLE_MAPS
|
||||
#include "selfdrive/ui/qt/maps/map_settings.h"
|
||||
#endif
|
||||
|
||||
// HomeWindow: the container for the offroad and onroad UIs
|
||||
|
||||
HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) {
|
||||
@@ -32,8 +28,6 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) {
|
||||
slayout->addWidget(home);
|
||||
|
||||
onroad = new OnroadWindow(this);
|
||||
QObject::connect(onroad, &OnroadWindow::mapPanelRequested, this, [=] { sidebar->hide(); });
|
||||
QObject::connect(onroad, &OnroadWindow::onroadSettingsPanelRequested, this, [=] { sidebar->hide(); });
|
||||
slayout->addWidget(onroad);
|
||||
|
||||
body = new BodyWindow(this);
|
||||
@@ -54,10 +48,6 @@ void HomeWindow::showSidebar(bool show) {
|
||||
sidebar->setVisible(show);
|
||||
}
|
||||
|
||||
void HomeWindow::showMapPanel(bool show) {
|
||||
onroad->showMapPanel(show);
|
||||
}
|
||||
|
||||
void HomeWindow::updateState(const UIState &s) {
|
||||
const SubMaster &sm = *(s.sm);
|
||||
|
||||
@@ -66,9 +56,6 @@ void HomeWindow::updateState(const UIState &s) {
|
||||
body->setEnabled(true);
|
||||
slayout->setCurrentWidget(body);
|
||||
}
|
||||
|
||||
uiState()->scene.map_visible = onroad->isMapVisible();
|
||||
uiState()->scene.onroad_settings_visible = onroad->isOnroadSettingsVisible();
|
||||
}
|
||||
|
||||
void HomeWindow::offroadTransition(bool offroad) {
|
||||
@@ -92,23 +79,9 @@ void HomeWindow::showDriverView(bool show) {
|
||||
}
|
||||
|
||||
void HomeWindow::mousePressEvent(QMouseEvent* e) {
|
||||
if (uiState()->scene.started) {
|
||||
if (uiState()->scene.onroadScreenOff != -2) {
|
||||
uiState()->scene.touched2 = true;
|
||||
QTimer::singleShot(500, []() { uiState()->scene.touched2 = false; });
|
||||
}
|
||||
if (uiState()->scene.button_auto_hide) {
|
||||
uiState()->scene.touch_to_wake = true;
|
||||
uiState()->scene.sleep_btn_fading_in = true;
|
||||
QTimer::singleShot(500, []() { uiState()->scene.touch_to_wake = false; });
|
||||
}
|
||||
}
|
||||
|
||||
// Handle sidebar collapsing
|
||||
if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) {
|
||||
if (onroad->wakeScreenTimeout()) {
|
||||
sidebar->setVisible(!sidebar->isVisible() && !onroad->isMapVisible());
|
||||
}
|
||||
sidebar->setVisible(!sidebar->isVisible());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,146 +97,3 @@ void HomeWindow::mouseDoubleClickEvent(QMouseEvent* e) {
|
||||
showSidebar(false);
|
||||
}
|
||||
}
|
||||
|
||||
// OffroadHome: the offroad home page
|
||||
|
||||
OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
|
||||
QVBoxLayout* main_layout = new QVBoxLayout(this);
|
||||
main_layout->setContentsMargins(40, 40, 40, 40);
|
||||
|
||||
// top header
|
||||
QHBoxLayout* header_layout = new QHBoxLayout();
|
||||
header_layout->setContentsMargins(0, 0, 0, 0);
|
||||
header_layout->setSpacing(16);
|
||||
|
||||
update_notif = new QPushButton(tr("UPDATE"));
|
||||
update_notif->setVisible(false);
|
||||
update_notif->setStyleSheet("background-color: #364DEF;");
|
||||
QObject::connect(update_notif, &QPushButton::clicked, [=]() { center_layout->setCurrentIndex(1); });
|
||||
header_layout->addWidget(update_notif, 0, Qt::AlignHCenter | Qt::AlignLeft);
|
||||
|
||||
alert_notif = new QPushButton();
|
||||
alert_notif->setVisible(false);
|
||||
alert_notif->setStyleSheet("background-color: #E22C2C;");
|
||||
QObject::connect(alert_notif, &QPushButton::clicked, [=] { center_layout->setCurrentIndex(2); });
|
||||
header_layout->addWidget(alert_notif, 0, Qt::AlignHCenter | Qt::AlignLeft);
|
||||
|
||||
version = new ElidedLabel();
|
||||
header_layout->addWidget(version, 0, Qt::AlignHCenter | Qt::AlignRight);
|
||||
|
||||
main_layout->addLayout(header_layout);
|
||||
|
||||
// main content
|
||||
main_layout->addSpacing(25);
|
||||
center_layout = new QStackedLayout();
|
||||
|
||||
QWidget *home_widget = new QWidget(this);
|
||||
{
|
||||
QHBoxLayout *home_layout = new QHBoxLayout(home_widget);
|
||||
home_layout->setContentsMargins(0, 0, 0, 0);
|
||||
home_layout->setSpacing(30);
|
||||
|
||||
// left: MapSettings/PrimeAdWidget
|
||||
QStackedWidget *left_widget = new QStackedWidget(this);
|
||||
#ifdef ENABLE_MAPS
|
||||
left_widget->addWidget(new MapSettings);
|
||||
#else
|
||||
left_widget->addWidget(new QWidget);
|
||||
#endif
|
||||
custom_mapbox = QString::fromStdString(params.get("CustomMapboxTokenSk")) != "";
|
||||
if (!custom_mapbox) {
|
||||
left_widget->addWidget(new PrimeAdWidget);
|
||||
}
|
||||
left_widget->setStyleSheet("border-radius: 10px;");
|
||||
|
||||
left_widget->setCurrentIndex((uiState()->hasPrime() || custom_mapbox) ? 0 : 1);
|
||||
connect(uiState(), &UIState::primeChanged, [=](bool prime) {
|
||||
left_widget->setCurrentIndex((prime || custom_mapbox) ? 0 : 1);
|
||||
});
|
||||
|
||||
home_layout->addWidget(left_widget, 1);
|
||||
|
||||
// right: ExperimentalModeButton, SetupWidget
|
||||
QWidget* right_widget = new QWidget(this);
|
||||
QVBoxLayout* right_column = new QVBoxLayout(right_widget);
|
||||
right_column->setContentsMargins(0, 0, 0, 0);
|
||||
right_widget->setFixedWidth(750);
|
||||
right_column->setSpacing(30);
|
||||
|
||||
ExperimentalModeButton *experimental_mode = new ExperimentalModeButton(this);
|
||||
QObject::connect(experimental_mode, &ExperimentalModeButton::openSettings, this, &OffroadHome::openSettings);
|
||||
right_column->addWidget(experimental_mode, 1);
|
||||
|
||||
SetupWidget *setup_widget = new SetupWidget;
|
||||
QObject::connect(setup_widget, &SetupWidget::openSettings, this, &OffroadHome::openSettings);
|
||||
right_column->addWidget(setup_widget, 1);
|
||||
|
||||
home_layout->addWidget(right_widget, 1);
|
||||
}
|
||||
center_layout->addWidget(home_widget);
|
||||
|
||||
// add update & alerts widgets
|
||||
update_widget = new UpdateAlert();
|
||||
QObject::connect(update_widget, &UpdateAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); });
|
||||
center_layout->addWidget(update_widget);
|
||||
alerts_widget = new OffroadAlert();
|
||||
QObject::connect(alerts_widget, &OffroadAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); });
|
||||
center_layout->addWidget(alerts_widget);
|
||||
|
||||
main_layout->addLayout(center_layout, 1);
|
||||
|
||||
// set up refresh timer
|
||||
timer = new QTimer(this);
|
||||
timer->callOnTimeout(this, &OffroadHome::refresh);
|
||||
|
||||
setStyleSheet(R"(
|
||||
* {
|
||||
color: white;
|
||||
}
|
||||
OffroadHome {
|
||||
background-color: black;
|
||||
}
|
||||
OffroadHome > QPushButton {
|
||||
padding: 15px 30px;
|
||||
border-radius: 5px;
|
||||
font-size: 40px;
|
||||
font-weight: 500;
|
||||
}
|
||||
OffroadHome > QLabel {
|
||||
font-size: 55px;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
void OffroadHome::showEvent(QShowEvent *event) {
|
||||
refresh();
|
||||
timer->start(10 * 1000);
|
||||
}
|
||||
|
||||
void OffroadHome::hideEvent(QHideEvent *event) {
|
||||
timer->stop();
|
||||
}
|
||||
|
||||
void OffroadHome::refresh() {
|
||||
version->setText(getBrand() + " " + QString::fromStdString(params.get("UpdaterCurrentDescription")));
|
||||
|
||||
bool updateAvailable = update_widget->refresh();
|
||||
int alerts = alerts_widget->refresh();
|
||||
|
||||
// pop-up new notification
|
||||
int idx = center_layout->currentIndex();
|
||||
if (!updateAvailable && !alerts) {
|
||||
idx = 0;
|
||||
} else if (updateAvailable && (!update_notif->isVisible() || (!alerts && idx == 2))) {
|
||||
idx = 1;
|
||||
} else if (alerts && (!alert_notif->isVisible() || (!updateAvailable && idx == 1))) {
|
||||
idx = 2;
|
||||
}
|
||||
center_layout->setCurrentIndex(idx);
|
||||
|
||||
update_notif->setVisible(updateAvailable);
|
||||
alert_notif->setVisible(alerts);
|
||||
if (alerts) {
|
||||
alert_notif->setText(QString::number(alerts) + (alerts > 1 ? tr(" ALERTS") : tr(" ALERT")));
|
||||
}
|
||||
}
|
||||
|
||||
+13
-30
@@ -12,35 +12,20 @@
|
||||
#include "selfdrive/ui/qt/body.h"
|
||||
#include "selfdrive/ui/qt/onroad/onroad_home.h"
|
||||
#include "selfdrive/ui/qt/sidebar.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/offroad_alerts.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
class OffroadHome : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OffroadHome(QWidget* parent = 0);
|
||||
|
||||
signals:
|
||||
void openSettings(int index = 0, const QString ¶m = "");
|
||||
|
||||
private:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void refresh();
|
||||
|
||||
Params params;
|
||||
|
||||
QTimer* timer;
|
||||
ElidedLabel* version;
|
||||
QStackedLayout* center_layout;
|
||||
UpdateAlert *update_widget;
|
||||
OffroadAlert* alerts_widget;
|
||||
QPushButton* alert_notif;
|
||||
QPushButton* update_notif;
|
||||
bool custom_mapbox;
|
||||
};
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad_home.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h"
|
||||
#define OnroadWindow OnroadWindowSP
|
||||
#define OffroadHome OffroadHomeSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/onroad/onroad_home.h"
|
||||
#include "selfdrive/ui/qt/offroad_home.h"
|
||||
#endif
|
||||
|
||||
class HomeWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
@@ -56,13 +41,11 @@ public slots:
|
||||
void offroadTransition(bool offroad);
|
||||
void showDriverView(bool show);
|
||||
void showSidebar(bool show);
|
||||
void showMapPanel(bool show);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent* e) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent* e) override;
|
||||
|
||||
private:
|
||||
Sidebar *sidebar;
|
||||
OffroadHome *home;
|
||||
OnroadWindow *onroad;
|
||||
@@ -70,6 +53,6 @@ private:
|
||||
DriverViewWindow *driver_view;
|
||||
QStackedLayout *slayout;
|
||||
|
||||
private slots:
|
||||
void updateState(const UIState &s);
|
||||
protected slots:
|
||||
virtual void updateState(const UIState &s);
|
||||
};
|
||||
|
||||
@@ -6,9 +6,14 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "selfdrive/ui/qt/maps/map_helpers.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h"
|
||||
#else
|
||||
#include "selfdrive/ui/qt/maps/map_helpers.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
|
||||
const int INTERACTION_TIMEOUT = 100;
|
||||
@@ -54,6 +59,7 @@ MapWindow::~MapWindow() {
|
||||
}
|
||||
|
||||
void MapWindow::initLayers() {
|
||||
RETURN_IF_SUNNYPILOT
|
||||
// This doesn't work from initializeGL
|
||||
if (!m_map->layerExists("modelPathLayer")) {
|
||||
qDebug() << "Initializing modelPathLayer";
|
||||
@@ -75,7 +81,7 @@ void MapWindow::initLayers() {
|
||||
|
||||
QVariantMap transition;
|
||||
transition["duration"] = 400; // ms
|
||||
m_map->setPaintProperty("navLayer", "line-color", getNavPathColor(uiState()->scene.navigate_on_openpilot_deprecated));
|
||||
m_map->setPaintProperty("navLayer", "line-color", QColor("#31a1ee"));
|
||||
m_map->setPaintProperty("navLayer", "line-color-transition", transition);
|
||||
m_map->setPaintProperty("navLayer", "line-width", 7.5);
|
||||
m_map->setLayoutProperty("navLayer", "line-cap", "round");
|
||||
@@ -110,52 +116,10 @@ void MapWindow::initLayers() {
|
||||
// TODO: remove, symbol-sort-key does not seem to matter outside of each layer
|
||||
m_map->setLayoutProperty("carPosLayer", "symbol-sort-key", 0);
|
||||
}
|
||||
if ((!m_map->layerExists("buildingsLayer")) && uiState()->scene.map_3d_buildings) { // Could put this behind the cellular metered toggle in case it increases data usage
|
||||
qDebug() << "Initializing buildingsLayer";
|
||||
QVariantMap buildings;
|
||||
buildings["id"] = "buildingsLayer";
|
||||
buildings["source"] = "composite";
|
||||
buildings["source-layer"] = "building";
|
||||
buildings["type"] = "fill-extrusion";
|
||||
buildings["minzoom"] = 15;
|
||||
m_map->addLayer("buildingsLayer", buildings);
|
||||
m_map->setFilter("buildingsLayer", QVariantList({"==", "extrude", "true"}));
|
||||
|
||||
QVariantList fillExtrusionHeight = { // scale buildings as you zoom in
|
||||
"interpolate",
|
||||
QVariantList{"linear"},
|
||||
QVariantList{"zoom"},
|
||||
15, 0,
|
||||
15.05, QVariantList{"get", "height"}
|
||||
};
|
||||
|
||||
QVariantList fillExtrusionBase = {
|
||||
"interpolate",
|
||||
QVariantList{"linear"},
|
||||
QVariantList{"zoom"},
|
||||
15, 0,
|
||||
15.05, QVariantList{"get", "min_height"}
|
||||
};
|
||||
|
||||
QVariantList fillExtrusionOpacity = {
|
||||
"interpolate",
|
||||
QVariantList{"linear"},
|
||||
QVariantList{"zoom"},
|
||||
15, 0, // transparent at zoom level 15
|
||||
15.5, .6, // fade in
|
||||
17, .6, // begin fading out
|
||||
20, 0 // fade out when zoomed in
|
||||
};
|
||||
|
||||
m_map->setPaintProperty("buildingsLayer", "fill-extrusion-color", QColor("grey"));
|
||||
m_map->setPaintProperty("buildingsLayer", "fill-extrusion-opacity", fillExtrusionOpacity);
|
||||
m_map->setPaintProperty("buildingsLayer", "fill-extrusion-height", fillExtrusionHeight);
|
||||
m_map->setPaintProperty("buildingsLayer", "fill-extrusion-base", fillExtrusionBase);
|
||||
m_map->setLayoutProperty("buildingsLayer", "visibility", "visible");
|
||||
}
|
||||
}
|
||||
|
||||
void MapWindow::updateState(const UIState &s) {
|
||||
RETURN_IF_SUNNYPILOT
|
||||
if (!uiState()->scene.started) {
|
||||
return;
|
||||
}
|
||||
@@ -170,22 +134,6 @@ void MapWindow::updateState(const UIState &s) {
|
||||
}
|
||||
prev_time_valid = sm.valid("clocks");
|
||||
|
||||
if (sm.updated("modelV2")) {
|
||||
// set path color on change, and show map on rising edge of navigate on openpilot
|
||||
auto car_control = sm["carControl"].getCarControl();
|
||||
bool nav_enabled = sm["modelV2"].getModelV2().getNavEnabledDEPRECATED() &&
|
||||
(sm["controlsState"].getControlsState().getEnabled() || car_control.getLatActive() || car_control.getLongActive());
|
||||
if (nav_enabled != uiState()->scene.navigate_on_openpilot_deprecated) {
|
||||
if (loaded_once) {
|
||||
m_map->setPaintProperty("navLayer", "line-color", getNavPathColor(nav_enabled));
|
||||
}
|
||||
if (nav_enabled) {
|
||||
emit requestVisible(true);
|
||||
}
|
||||
}
|
||||
uiState()->scene.navigate_on_openpilot_deprecated = nav_enabled;
|
||||
}
|
||||
|
||||
if (sm.updated("liveLocationKalman")) {
|
||||
auto locationd_location = sm["liveLocationKalman"].getLiveLocationKalman();
|
||||
auto locationd_pos = locationd_location.getPositionGeodetic();
|
||||
@@ -425,7 +373,6 @@ void MapWindow::pinchTriggered(QPinchGesture *gesture) {
|
||||
void MapWindow::offroadTransition(bool offroad) {
|
||||
if (offroad) {
|
||||
clearRoute();
|
||||
uiState()->scene.navigate_on_openpilot_deprecated = false;
|
||||
routing_problem = false;
|
||||
} else {
|
||||
auto dest = coordinate_from_param("NavDestination");
|
||||
|
||||
@@ -20,7 +20,11 @@
|
||||
#include "cereal/messaging/messaging.h"
|
||||
#include "common/params.h"
|
||||
#include "common/util.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
#include "selfdrive/ui/qt/maps/map_eta.h"
|
||||
#include "selfdrive/ui/qt/maps/map_instructions.h"
|
||||
|
||||
@@ -32,15 +36,17 @@ public:
|
||||
~MapWindow();
|
||||
|
||||
private:
|
||||
void initializeGL() final;
|
||||
void paintGL() final;
|
||||
void resizeGL(int w, int h) override;
|
||||
|
||||
protected:
|
||||
void initializeGL() final;
|
||||
QMapLibre::Settings m_settings;
|
||||
QScopedPointer<QMapLibre::Map> m_map;
|
||||
|
||||
void initLayers();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *ev) final;
|
||||
void mouseDoubleClickEvent(QMouseEvent *ev) final;
|
||||
void mouseMoveEvent(QMouseEvent *ev) final;
|
||||
@@ -50,9 +56,11 @@ private:
|
||||
void pinchTriggered(QPinchGesture *gesture);
|
||||
void setError(const QString &err_str);
|
||||
|
||||
protected:
|
||||
bool loaded_once = false;
|
||||
bool prev_time_valid = true;
|
||||
|
||||
protected:
|
||||
// Panning
|
||||
QPointF m_lastPos;
|
||||
int interaction_counter = 0;
|
||||
@@ -70,16 +78,11 @@ private:
|
||||
MapInstructions* map_instructions;
|
||||
MapETA* map_eta;
|
||||
|
||||
// Blue with normal nav, green when nav is input into the model
|
||||
QColor getNavPathColor(bool nav_enabled) {
|
||||
return nav_enabled ? QColor("#31ee73") : QColor("#31a1ee");
|
||||
}
|
||||
|
||||
void clearRoute();
|
||||
void updateDestinationMarker();
|
||||
uint64_t route_rcv_frame = 0;
|
||||
|
||||
private slots:
|
||||
public slots:
|
||||
void updateState(const UIState &s);
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -3,8 +3,13 @@
|
||||
#include <QDateTime>
|
||||
#include <QPainter>
|
||||
|
||||
#include "selfdrive/ui/qt/maps/map_helpers.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/maps/map_helpers.h"
|
||||
#endif
|
||||
|
||||
const float MANEUVER_TRANSITION_THRESHOLD = 10;
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h"
|
||||
#else
|
||||
#include "selfdrive/ui/qt/maps/map_helpers.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
@@ -12,9 +12,8 @@
|
||||
#include "common/transformations/coordinates.hpp"
|
||||
#include "common/transformations/orientation.hpp"
|
||||
#include "cereal/messaging/messaging.h"
|
||||
#include "common/params.h"
|
||||
|
||||
const QString MAPBOX_TOKEN = QString::fromStdString(Params().get("CustomMapboxTokenSk")) != "" ? QString::fromStdString(Params().get("CustomMapboxTokenSk")) : util::getenv("MAPBOX_TOKEN").c_str();
|
||||
const QString MAPBOX_TOKEN = util::getenv("MAPBOX_TOKEN").c_str();
|
||||
const QString MAPS_HOST = util::getenv("MAPS_HOST", MAPBOX_TOKEN.isEmpty() ? "https://maps.comma.ai" : "https://api.mapbox.com").c_str();
|
||||
const QString MAPS_CACHE_PATH = "/data/mbgl-cache-navd.db";
|
||||
|
||||
|
||||
@@ -3,8 +3,13 @@
|
||||
#include <QDir>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "selfdrive/ui/qt/maps/map_helpers.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/maps/map_helpers.h"
|
||||
#endif
|
||||
|
||||
const QString ICON_SUFFIX = ".png";
|
||||
|
||||
|
||||
@@ -3,10 +3,16 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include "selfdrive/ui/qt/maps/map.h"
|
||||
#include "selfdrive/ui/qt/maps/map_settings.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/maps/map.h"
|
||||
#define MapWindow MapWindowSP
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/maps/map.h"
|
||||
#endif
|
||||
|
||||
MapPanel::MapPanel(const QMapLibre::Settings &mapboxSettings, QWidget *parent) : QFrame(parent) {
|
||||
content_stack = new QStackedLayout(this);
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
|
||||
#include "common/params.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#else
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#endif
|
||||
|
||||
const QString NAV_TYPE_FAVORITE = "favorite";
|
||||
const QString NAV_TYPE_RECENT = "recent";
|
||||
|
||||
@@ -6,11 +6,16 @@
|
||||
#include <QScrollBar>
|
||||
#include <QStyle>
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
#include "selfdrive/ui/qt/home.h"
|
||||
|
||||
static const int ICON_WIDTH = 49;
|
||||
|
||||
@@ -26,29 +31,17 @@ Networking::Networking(QWidget* parent, bool show_advanced) : QFrame(parent) {
|
||||
wifiScreen = new QWidget(this);
|
||||
QVBoxLayout* vlayout = new QVBoxLayout(wifiScreen);
|
||||
vlayout->setContentsMargins(20, 20, 20, 20);
|
||||
QHBoxLayout* hlayout = new QHBoxLayout();
|
||||
QPushButton* scanButton = new QPushButton(tr("Scan"));
|
||||
scanButton->setObjectName("scan_btn");
|
||||
scanButton->setFixedSize(400, 100);
|
||||
connect(wifi, &WifiManager::refreshSignal, this, [=]() { scanButton->setText(tr("Scan")); scanButton->setEnabled(true); });
|
||||
connect(scanButton, &QPushButton::clicked, [=]() { scanButton->setText(tr("Scanning...")); scanButton->setEnabled(false); wifi->requestScan(); });
|
||||
|
||||
hlayout->addWidget(scanButton);
|
||||
hlayout->addStretch(1); // Pushes the button all the way to the left
|
||||
|
||||
if (show_advanced) {
|
||||
hlayout->setSpacing(10);
|
||||
|
||||
QPushButton* advancedSettings = new QPushButton(tr("Advanced"));
|
||||
advancedSettings->setObjectName("advanced_btn");
|
||||
advancedSettings->setStyleSheet("margin-right: 30px;");
|
||||
advancedSettings->setFixedSize(400, 100);
|
||||
connect(advancedSettings, &QPushButton::clicked, [=]() { main_layout->setCurrentWidget(an); });
|
||||
hlayout->addWidget(advancedSettings);
|
||||
vlayout->addSpacing(10);
|
||||
vlayout->addWidget(advancedSettings, 0, Qt::AlignRight);
|
||||
vlayout->addSpacing(10);
|
||||
}
|
||||
|
||||
vlayout->addLayout(hlayout);
|
||||
vlayout->addSpacing(10);
|
||||
|
||||
wifiWidget = new WifiUI(this, wifi);
|
||||
wifiWidget->setObjectName("wifiWidget");
|
||||
connect(wifiWidget, &WifiUI::connectToNetwork, this, &Networking::connectToNetwork);
|
||||
@@ -69,7 +62,7 @@ Networking::Networking(QWidget* parent, bool show_advanced) : QFrame(parent) {
|
||||
setPalette(pal);
|
||||
|
||||
setStyleSheet(R"(
|
||||
#wifiWidget > QPushButton, #back_btn, #advanced_btn, #scan_btn{
|
||||
#wifiWidget > QPushButton, #back_btn, #advanced_btn {
|
||||
font-size: 50px;
|
||||
margin: 0px;
|
||||
padding: 15px;
|
||||
@@ -78,7 +71,7 @@ Networking::Networking(QWidget* parent, bool show_advanced) : QFrame(parent) {
|
||||
color: #dddddd;
|
||||
background-color: #393939;
|
||||
}
|
||||
#back_btn:pressed, #advanced_btn:pressed, #scan_btn:pressed {
|
||||
#back_btn:pressed, #advanced_btn:pressed {
|
||||
background-color: #4a4a4a;
|
||||
}
|
||||
)");
|
||||
@@ -139,23 +132,10 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid
|
||||
|
||||
ListWidget *list = new ListWidget(this);
|
||||
// Enable tethering layout
|
||||
const bool set_hotspot_on_boot = params.getBool("HotspotOnBoot") && params.getBool("HotspotOnBootConfirmed");
|
||||
tetheringToggle = new ToggleControl(tr("Enable Tethering"), "", "", wifi->isTetheringEnabled() || set_hotspot_on_boot);
|
||||
tetheringToggle = new ToggleControl(tr("Enable Tethering"), "", "", wifi->isTetheringEnabled());
|
||||
list->addItem(tetheringToggle);
|
||||
QObject::connect(tetheringToggle, &ToggleControl::toggleFlipped, this, &AdvancedNetworking::toggleTethering);
|
||||
|
||||
hotspotOnBootToggle = new ToggleControl(
|
||||
tr("Retain hotspot/tethering state"),
|
||||
tr("Enabling this toggle will retain the hotspot/tethering toggle state across reboots."),
|
||||
"",
|
||||
params.getBool("HotspotOnBoot")
|
||||
);
|
||||
hotspotOnBootToggle->setEnabled(wifi->isTetheringEnabled() || set_hotspot_on_boot);
|
||||
QObject::connect(hotspotOnBootToggle, &ToggleControl::toggleFlipped, [=](bool state) {
|
||||
params.putBool("HotspotOnBoot", state);
|
||||
});
|
||||
list->addItem(hotspotOnBootToggle);
|
||||
|
||||
// Change tethering password
|
||||
ButtonControl *editPasswordButton = new ButtonControl(tr("Tethering Password"), tr("EDIT"));
|
||||
connect(editPasswordButton, &ButtonControl::clicked, [=]() {
|
||||
@@ -226,19 +206,6 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid
|
||||
});
|
||||
list->addItem(hiddenNetworkButton);
|
||||
|
||||
// Ngrok
|
||||
QProcess process;
|
||||
process.start("sudo service ngrok status | grep running");
|
||||
process.waitForFinished();
|
||||
QString output = QString(process.readAllStandardOutput());
|
||||
bool ngrokRunning = !output.isEmpty();
|
||||
ToggleControl *ngrokToggle = new ToggleControl(tr("Ngrok Service"), "", "", ngrokRunning);
|
||||
connect(ngrokToggle, &ToggleControl::toggleFlipped, [=](bool state) {
|
||||
if (state) std::system("sudo ngrok service start");
|
||||
else std::system("sudo ngrok service stop");
|
||||
});
|
||||
list->addItem(ngrokToggle);
|
||||
|
||||
// Set initial config
|
||||
wifi->updateGsmSettings(roamingEnabled, QString::fromStdString(params.get("GsmApn")), metered);
|
||||
|
||||
@@ -260,14 +227,8 @@ void AdvancedNetworking::refresh() {
|
||||
}
|
||||
|
||||
void AdvancedNetworking::toggleTethering(bool enabled) {
|
||||
params.putBool("HotspotOnBootConfirmed", enabled);
|
||||
wifi->setTetheringEnabled(enabled);
|
||||
tetheringToggle->setEnabled(false);
|
||||
|
||||
hotspotOnBootToggle->setEnabled(enabled);
|
||||
if (!enabled) {
|
||||
params.remove("HotspotOnBoot");
|
||||
}
|
||||
}
|
||||
|
||||
// WifiUI functions
|
||||
@@ -419,4 +380,4 @@ void WifiItem::setItem(const Network &n, const QPixmap &status_icon, bool show_f
|
||||
|
||||
iconLabel->setPixmap(status_icon);
|
||||
strengthLabel->setPixmap(strength_icon);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,13 @@
|
||||
#include "selfdrive/ui/qt/widgets/input.h"
|
||||
#include "selfdrive/ui/qt/widgets/ssh_keys.h"
|
||||
#include "selfdrive/ui/qt/widgets/toggle.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#define LabelControl LabelControlSP
|
||||
#define ElidedLabel ElidedLabelSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#endif
|
||||
|
||||
class WifiItem : public QWidget {
|
||||
Q_OBJECT
|
||||
@@ -67,8 +74,6 @@ private:
|
||||
WifiManager* wifi = nullptr;
|
||||
Params params;
|
||||
|
||||
ToggleControl* hotspotOnBootToggle;
|
||||
|
||||
signals:
|
||||
void backPress();
|
||||
void requestWifiScreen();
|
||||
@@ -100,4 +105,4 @@ public slots:
|
||||
private slots:
|
||||
void connectToNetwork(const Network n);
|
||||
void wrongPassword(const QString &ssid);
|
||||
};
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef USER_MODEL_H
|
||||
#define USER_MODEL_H
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
class UserModel {
|
||||
public:
|
||||
QString device_id;
|
||||
QString user_id;
|
||||
qint64 created_at;
|
||||
qint64 updated_at;
|
||||
QString token_hash;
|
||||
|
||||
explicit UserModel(const QJsonObject &json) {
|
||||
device_id = json["device_id"].toString();
|
||||
user_id = json["user_id"].toString();
|
||||
created_at = json["created_at"].toInt();
|
||||
updated_at = json["updated_at"].toInt();
|
||||
token_hash = json["token_hash"].toString();
|
||||
}
|
||||
|
||||
[[nodiscard]] QJsonObject toJson() const {
|
||||
QJsonObject json;
|
||||
json["device_id"] = device_id;
|
||||
json["user_id"] = user_id;
|
||||
json["created_at"] = created_at;
|
||||
json["updated_at"] = updated_at;
|
||||
json["token_hash"] = token_hash;
|
||||
return json;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "base_device_service.h"
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.h"
|
||||
|
||||
BaseDeviceService::BaseDeviceService(QObject* parent) : QObject(parent), initial_request(nullptr), repeater(nullptr) {
|
||||
param_watcher = new ParamWatcher(this);
|
||||
connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) {
|
||||
paramsRefresh();
|
||||
});
|
||||
param_watcher->addParam("SunnylinkEnabled");
|
||||
}
|
||||
|
||||
void BaseDeviceService::paramsRefresh() {
|
||||
}
|
||||
|
||||
void BaseDeviceService::loadDeviceData(const QString &url, bool poll) {
|
||||
if (!is_sunnylink_enabled()) {
|
||||
LOGW("Sunnylink is not enabled, refusing to load data.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto sl_dongle_id = getSunnylinkDongleId();
|
||||
if (!sl_dongle_id.has_value())
|
||||
return;
|
||||
|
||||
QString fullUrl = SUNNYLINK_BASE_URL + "/device/" + *sl_dongle_id + url;
|
||||
if (poll && !isCurrentyPolling()) {
|
||||
LOGD("Polling %s", qPrintable(fullUrl));
|
||||
LOGD("Cache key: SunnylinkCache_%s", qPrintable(QString(getCacheKey())));
|
||||
repeater = new RequestRepeater(this, fullUrl, "SunnylinkCache_" + getCacheKey(), 60, false, true);
|
||||
connect(repeater, &RequestRepeater::requestDone, this, &BaseDeviceService::handleResponse);
|
||||
} else if(isCurrentyPolling()){
|
||||
repeater->ForceUpdate();
|
||||
} else {
|
||||
LOGD("Sending one-time %s", qPrintable(fullUrl));
|
||||
initial_request = new HttpRequest(this, true, 10000, true);
|
||||
connect(initial_request, &HttpRequest::requestDone, this, &BaseDeviceService::handleResponse);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseDeviceService::stopPolling() {
|
||||
if (repeater != nullptr) {
|
||||
repeater->deleteLater();
|
||||
repeater = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef BASESERVICE_H
|
||||
#define BASESERVICE_H
|
||||
|
||||
|
||||
#include "selfdrive/ui/qt/api.h"
|
||||
#include "selfdrive/ui/qt/request_repeater.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
class BaseDeviceService : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
void paramsRefresh();
|
||||
void loadDeviceData(const QString &url, bool poll = false);
|
||||
virtual void handleResponse(const QString &response, bool success) = 0;
|
||||
|
||||
static bool is_sunnylink_enabled() { return Params().getBool("SunnylinkEnabled");};
|
||||
ParamWatcher* param_watcher;
|
||||
HttpRequest* initial_request = nullptr;
|
||||
RequestRepeater* repeater = nullptr;
|
||||
|
||||
public:
|
||||
explicit BaseDeviceService(QObject* parent = nullptr);
|
||||
virtual QString getCacheKey() const = 0;
|
||||
bool isCurrentyPolling() {return repeater != nullptr;}
|
||||
void stopPolling();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "selfdrive/ui/qt/network/sunnylink/services/role_service.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
RoleService::RoleService(QObject* parent) : BaseDeviceService(parent) {}
|
||||
|
||||
void RoleService::load() {
|
||||
loadDeviceData(url);
|
||||
}
|
||||
|
||||
void RoleService::startPolling() {
|
||||
loadDeviceData(url, true);
|
||||
}
|
||||
|
||||
void RoleService::handleResponse(const QString &response, bool success) {
|
||||
if (!success) return;
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8());
|
||||
QJsonArray jsonArray = doc.array();
|
||||
|
||||
std::vector<RoleModel> roles;
|
||||
for (const auto &value : jsonArray) {
|
||||
roles.emplace_back(value.toObject());
|
||||
}
|
||||
|
||||
emit rolesReady(roles);
|
||||
uiState()->setSunnylinkRoles(roles);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef ROLESERVICE_H
|
||||
#define ROLESERVICE_H
|
||||
|
||||
#include "selfdrive/ui/qt/network/sunnylink/services/base_device_service.h"
|
||||
#include "selfdrive/ui/qt/network/sunnylink/models/role_model.h"
|
||||
|
||||
class RoleService : public BaseDeviceService {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RoleService(QObject* parent = nullptr);
|
||||
void load();
|
||||
void startPolling();
|
||||
[[nodiscard]] QString getCacheKey() const final { return "Roles"; };
|
||||
|
||||
signals:
|
||||
void rolesReady(const std::vector<RoleModel> &roles);
|
||||
|
||||
protected:
|
||||
void handleResponse(const QString&response, bool success) override;
|
||||
|
||||
private:
|
||||
QString url = "/roles";
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,31 +0,0 @@
|
||||
#include "selfdrive/ui/qt/network/sunnylink/services/user_service.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
UserService::UserService(QObject* parent) : BaseDeviceService(parent) {
|
||||
url = "/users";
|
||||
}
|
||||
|
||||
void UserService::load() {
|
||||
loadDeviceData(url);
|
||||
}
|
||||
|
||||
void UserService::startPolling() {
|
||||
loadDeviceData(url, true);
|
||||
}
|
||||
|
||||
void UserService::handleResponse(const QString &response, bool success) {
|
||||
if (!success) return;
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8());
|
||||
QJsonArray jsonArray = doc.array();
|
||||
|
||||
std::vector<UserModel> users;
|
||||
for (const auto &value : jsonArray) {
|
||||
users.emplace_back(value.toObject());
|
||||
}
|
||||
|
||||
emit usersReady(users);
|
||||
uiState()->setSunnylinkDeviceUsers(users);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef USERSERVICE_H
|
||||
#define USERSERVICE_H
|
||||
|
||||
#include "selfdrive/ui/qt/network/sunnylink/services/base_device_service.h"
|
||||
#include "selfdrive/ui/qt/network/sunnylink/models/user_model.h"
|
||||
|
||||
class UserService : public BaseDeviceService {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UserService(QObject* parent = nullptr);
|
||||
void load();
|
||||
void startPolling();
|
||||
[[nodiscard]] QString getCacheKey() const final { return "Users"; };
|
||||
|
||||
signals:
|
||||
void usersReady(const std::vector<UserModel>&users);
|
||||
|
||||
protected:
|
||||
void handleResponse(const QString&response, bool success) override;
|
||||
|
||||
private:
|
||||
QString url = "/users";
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +0,0 @@
|
||||
#include "selfdrive/ui/qt/network/sunnylink/sunnylink_client.h"
|
||||
#include "selfdrive/ui/qt/network/sunnylink/services/user_service.h"
|
||||
|
||||
SunnylinkClient::SunnylinkClient(QObject* parent) : QObject(parent) {
|
||||
role_service = new RoleService(parent);
|
||||
user_service = new UserService(parent);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#ifndef SUNNYLINK_CLIENT_H
|
||||
#define SUNNYLINK_CLIENT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "selfdrive/ui/qt/network/sunnylink/services/role_service.h"
|
||||
#include "selfdrive/ui/qt/network/sunnylink/services/user_service.h"
|
||||
|
||||
class SunnylinkClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SunnylinkClient(QObject* parent);
|
||||
RoleService* role_service;
|
||||
UserService* user_service;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
#include "selfdrive/ui/qt/widgets/prime.h"
|
||||
|
||||
#include "common/params.h"
|
||||
|
||||
@@ -7,13 +7,18 @@
|
||||
#include <QStyle>
|
||||
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#define TOGGLES_PANEL_INDEX 3
|
||||
#else
|
||||
#define TOGGLES_PANEL_INDEX 2
|
||||
#endif
|
||||
|
||||
ExperimentalModeButton::ExperimentalModeButton(QWidget *parent) : QPushButton(parent) {
|
||||
chill_pixmap = QPixmap("../assets/img_couch.svg").scaledToWidth(img_width, Qt::SmoothTransformation);
|
||||
experimental_pixmap = QPixmap("../assets/img_experimental_grey.svg").scaledToWidth(img_width, Qt::SmoothTransformation);
|
||||
|
||||
// go to toggles and expand experimental mode description
|
||||
connect(this, &QPushButton::clicked, [=]() { emit openSettings(3, "ExperimentalMode"); });
|
||||
connect(this, &QPushButton::clicked, [=]() { emit openSettings(TOGGLES_PANEL_INDEX, "ExperimentalMode"); });
|
||||
|
||||
setFixedHeight(125);
|
||||
QHBoxLayout *main_layout = new QHBoxLayout;
|
||||
|
||||
@@ -106,8 +106,7 @@ void TermsPage::showEvent(QShowEvent *event) {
|
||||
text->setAttribute(Qt::WA_AlwaysStackOnTop);
|
||||
text->setClearColor(QColor("#1B1B1B"));
|
||||
|
||||
std::string tc_text = sunnypilot_tc ? "../assets/offroad/sp_tc.html" : "../assets/offroad/tc.html";
|
||||
QString text_view = util::read_file(tc_text).c_str();
|
||||
QString text_view = util::read_file("../assets/offroad/tc.html").c_str();
|
||||
text->rootContext()->setContextProperty("text_view", text_view);
|
||||
|
||||
text->setSource(QUrl::fromLocalFile("qt/offroad/text_view.qml"));
|
||||
@@ -186,8 +185,6 @@ void OnboardingWindow::updateActiveScreen() {
|
||||
setCurrentIndex(0);
|
||||
} else if (!training_done) {
|
||||
setCurrentIndex(1);
|
||||
} else if (!accepted_terms_sp) {
|
||||
setCurrentIndex(3);
|
||||
} else {
|
||||
emit onboardingDone();
|
||||
}
|
||||
@@ -195,13 +192,11 @@ void OnboardingWindow::updateActiveScreen() {
|
||||
|
||||
OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) {
|
||||
std::string current_terms_version = params.get("TermsVersion");
|
||||
std::string current_terms_version_sp = params.get("TermsVersionSunnypilot");
|
||||
std::string current_training_version = params.get("TrainingVersion");
|
||||
accepted_terms = params.get("HasAcceptedTerms") == current_terms_version;
|
||||
accepted_terms_sp = params.get("HasAcceptedTermsSP") == current_terms_version_sp;
|
||||
training_done = params.get("CompletedTrainingVersion") == current_training_version;
|
||||
|
||||
TermsPage* terms = new TermsPage(false, this);
|
||||
TermsPage* terms = new TermsPage(this);
|
||||
addWidget(terms);
|
||||
connect(terms, &TermsPage::acceptedTerms, [=]() {
|
||||
params.put("HasAcceptedTerms", current_terms_version);
|
||||
@@ -222,15 +217,6 @@ OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) {
|
||||
addWidget(declinePage);
|
||||
connect(declinePage, &DeclinePage::getBack, [=]() { updateActiveScreen(); });
|
||||
|
||||
TermsPage* terms_sp = new TermsPage(true, this);
|
||||
addWidget(terms_sp); // index = 3
|
||||
connect(terms_sp, &TermsPage::acceptedTerms, [=]() {
|
||||
params.put("HasAcceptedTermsSP", current_terms_version_sp);
|
||||
accepted_terms_sp = true;
|
||||
updateActiveScreen();
|
||||
});
|
||||
connect(terms_sp, &TermsPage::declinedTerms, [=]() { setCurrentIndex(2); });
|
||||
|
||||
setStyleSheet(R"(
|
||||
* {
|
||||
color: white;
|
||||
@@ -245,4 +231,4 @@ OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) {
|
||||
}
|
||||
)");
|
||||
updateActiveScreen();
|
||||
}
|
||||
}
|
||||
@@ -63,16 +63,17 @@ class TermsPage : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TermsPage(bool sunnypilot = false, QWidget *parent = 0) : QFrame(parent), sunnypilot_tc(sunnypilot) {}
|
||||
explicit TermsPage(QWidget *parent = 0) : QFrame(parent) {}
|
||||
|
||||
public slots:
|
||||
void enableAccept();
|
||||
|
||||
protected:
|
||||
QPushButton *accept_btn;
|
||||
|
||||
private:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
QPushButton *accept_btn;
|
||||
bool sunnypilot_tc = false;
|
||||
|
||||
signals:
|
||||
void acceptedTerms();
|
||||
@@ -98,14 +99,14 @@ class OnboardingWindow : public QStackedWidget {
|
||||
public:
|
||||
explicit OnboardingWindow(QWidget *parent = 0);
|
||||
inline void showTrainingGuide() { setCurrentIndex(1); }
|
||||
inline bool completed() const { return accepted_terms && accepted_terms_sp && training_done; }
|
||||
virtual inline bool completed() const { return accepted_terms && training_done; }
|
||||
|
||||
private:
|
||||
void updateActiveScreen();
|
||||
protected:
|
||||
virtual void updateActiveScreen();
|
||||
|
||||
Params params;
|
||||
bool accepted_terms = false, accepted_terms_sp = false, training_done = false;
|
||||
bool accepted_terms = false, training_done = false;
|
||||
|
||||
signals:
|
||||
void onboardingDone();
|
||||
};
|
||||
};
|
||||
@@ -5,28 +5,29 @@
|
||||
#include <vector>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "common/watchdog.h"
|
||||
#include "common/util.h"
|
||||
#include "selfdrive/ui/qt/network/networking.h"
|
||||
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot_main.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
#include "selfdrive/ui/qt/widgets/prime.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
#include "selfdrive/ui/qt/widgets/ssh_keys.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/sunnypilot_main.h"
|
||||
#endif
|
||||
|
||||
TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
RETURN_IF_SUNNYPILOT
|
||||
|
||||
// param, title, desc, icon
|
||||
std::vector<std::tuple<QString, QString, QString, QString>> toggle_defs{
|
||||
{
|
||||
"OpenpilotEnabledToggle",
|
||||
tr("Enable sunnypilot"),
|
||||
tr("Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
"../assets/offroad/icon_openpilot.png",
|
||||
},
|
||||
{
|
||||
"ExperimentalLongitudinalEnabled",
|
||||
@@ -35,105 +36,54 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
.arg(tr("WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB)."))
|
||||
.arg(tr("On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. "
|
||||
"Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.")),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"CustomStockLong",
|
||||
tr("Custom Stock Longitudinal Control"),
|
||||
tr("When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses.\nThis feature must be used along with SLC, and/or V-TSC, and/or M-TSC."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
"../assets/offroad/icon_speed_limit.png",
|
||||
},
|
||||
{
|
||||
"ExperimentalMode",
|
||||
tr("Experimental Mode"),
|
||||
"",
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"DynamicExperimentalControl",
|
||||
tr("Enable Dynamic Experimental Control"),
|
||||
tr("Enable toggle to allow the model to determine when to use openpilot ACC or openpilot End to End Longitudinal."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"DynamicPersonality",
|
||||
tr("Enable Dynamic Personality"),
|
||||
tr("Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your \"Driving Personality\" setting. "
|
||||
"Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
"../assets/img_experimental_white.svg",
|
||||
},
|
||||
{
|
||||
"DisengageOnAccelerator",
|
||||
tr("Disengage on Accelerator Pedal"),
|
||||
tr("When enabled, pressing the accelerator pedal will disengage openpilot."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
"../assets/offroad/icon_disengage_on_accelerator.svg",
|
||||
},
|
||||
{
|
||||
"IsLdwEnabled",
|
||||
tr("Enable Lane Departure Warnings"),
|
||||
tr("Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h)."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
"../assets/offroad/icon_warning.png",
|
||||
},
|
||||
{
|
||||
"AlwaysOnDM",
|
||||
tr("Always-On Driver Monitoring"),
|
||||
tr("Enable driver monitoring even when openpilot is not engaged."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
"../assets/offroad/icon_monitoring.png",
|
||||
},
|
||||
{
|
||||
"RecordFront",
|
||||
tr("Record and Upload Driver Camera"),
|
||||
tr("Upload data from the driver facing camera and help improve the driver monitoring algorithm."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"DisableOnroadUploads",
|
||||
tr("Disable Onroad Uploads"),
|
||||
tr("Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC)."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
"../assets/offroad/icon_monitoring.png",
|
||||
},
|
||||
{
|
||||
"IsMetric",
|
||||
tr("Use Metric System"),
|
||||
tr("Display speed in km/h instead of mph."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
"../assets/offroad/icon_metric.png",
|
||||
},
|
||||
#ifdef ENABLE_MAPS
|
||||
{
|
||||
"NavSettingTime24h",
|
||||
tr("Show ETA in 24h Format"),
|
||||
tr("Use 24h format instead of am/pm"),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"NavSettingLeftSide",
|
||||
tr("Show Map on Left Side of UI"),
|
||||
tr("Show map on left side when in split screen view."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
std::vector<QString> longi_button_texts{tr("Aggressive"), tr("Moderate"), tr("Standard"), tr("Relaxed")};
|
||||
std::vector<QString> longi_button_texts{tr("Aggressive"), tr("Standard"), tr("Relaxed")};
|
||||
long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"),
|
||||
tr("Standard is recommended. In moderate/aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. "
|
||||
tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. "
|
||||
"In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with "
|
||||
"your steering wheel distance button."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
longi_button_texts,
|
||||
380);
|
||||
long_personality_setting->showDescription();
|
||||
|
||||
// accel controller
|
||||
std::vector<QString> accel_personality_texts{tr("Sport"), tr("Normal"), tr("Eco"), tr("Stock")};
|
||||
accel_personality_setting = new ButtonParamControl("AccelPersonality", tr("Acceleration Personality"),
|
||||
tr("Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. "
|
||||
"In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these "
|
||||
"acceleration personality within Onroad Settings on the driving screen."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
accel_personality_texts);
|
||||
accel_personality_setting->showDescription();
|
||||
"../assets/offroad/icon_speed_limit.png",
|
||||
longi_button_texts);
|
||||
|
||||
// set up uiState update for personality setting
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &TogglesPanel::updateState);
|
||||
@@ -150,28 +100,17 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
// insert longitudinal personality after NDOG toggle
|
||||
if (param == "DisengageOnAccelerator") {
|
||||
addItem(long_personality_setting);
|
||||
addItem(accel_personality_setting);
|
||||
}
|
||||
}
|
||||
|
||||
// Toggles with confirmation dialogs
|
||||
//toggles["ExperimentalMode"]->setActiveIcon("../assets/img_experimental.svg");
|
||||
toggles["ExperimentalMode"]->setActiveIcon("../assets/img_experimental.svg");
|
||||
toggles["ExperimentalMode"]->setConfirmation(true, true);
|
||||
toggles["ExperimentalLongitudinalEnabled"]->setConfirmation(true, false);
|
||||
toggles["CustomStockLong"]->setConfirmation(true, false);
|
||||
|
||||
connect(toggles["ExperimentalLongitudinalEnabled"], &ToggleControl::toggleFlipped, [=]() {
|
||||
updateToggles();
|
||||
});
|
||||
connect(toggles["CustomStockLong"], &ToggleControl::toggleFlipped, [=]() {
|
||||
updateToggles();
|
||||
});
|
||||
|
||||
param_watcher = new ParamWatcher(this);
|
||||
|
||||
QObject::connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) {
|
||||
updateToggles();
|
||||
});
|
||||
}
|
||||
|
||||
void TogglesPanel::updateState(const UIState &s) {
|
||||
@@ -184,14 +123,6 @@ void TogglesPanel::updateState(const UIState &s) {
|
||||
}
|
||||
uiState()->scene.personality = personality;
|
||||
}
|
||||
|
||||
if (sm.updated("controlsStateSP")) {
|
||||
auto accel_personality = sm["controlsStateSP"].getControlsStateSP().getAccelPersonality();
|
||||
if (accel_personality != s.scene.accel_personality && s.scene.started && isVisible()) {
|
||||
accel_personality_setting->setCheckedButton(static_cast<int>(accel_personality));
|
||||
}
|
||||
uiState()->scene.accel_personality = accel_personality;
|
||||
}
|
||||
}
|
||||
|
||||
void TogglesPanel::expandToggleDescription(const QString ¶m) {
|
||||
@@ -203,15 +134,8 @@ void TogglesPanel::showEvent(QShowEvent *event) {
|
||||
}
|
||||
|
||||
void TogglesPanel::updateToggles() {
|
||||
param_watcher->addParam("LongitudinalPersonality");
|
||||
|
||||
if (!isVisible()) return;
|
||||
|
||||
auto experimental_mode_toggle = toggles["ExperimentalMode"];
|
||||
auto op_long_toggle = toggles["ExperimentalLongitudinalEnabled"];
|
||||
auto custom_stock_long_toggle = toggles["CustomStockLong"];
|
||||
auto dec_toggle = toggles["DynamicExperimentalControl"];
|
||||
auto dynamic_personality_toggle = toggles["DynamicPersonality"];
|
||||
const QString e2e_description = QString("%1<br>"
|
||||
"<h4>%2</h4><br>"
|
||||
"%3<br>"
|
||||
@@ -236,35 +160,15 @@ void TogglesPanel::updateToggles() {
|
||||
params.remove("ExperimentalLongitudinalEnabled");
|
||||
}
|
||||
op_long_toggle->setVisible(CP.getExperimentalLongitudinalAvailable() && !is_release);
|
||||
|
||||
if (!CP.getCustomStockLongAvailable()) {
|
||||
params.remove("CustomStockLong");
|
||||
}
|
||||
custom_stock_long_toggle->setVisible(CP.getCustomStockLongAvailable());
|
||||
|
||||
if (hasLongitudinalControl(CP)) {
|
||||
// normal description and toggle
|
||||
experimental_mode_toggle->setEnabled(true);
|
||||
experimental_mode_toggle->setDescription(e2e_description);
|
||||
long_personality_setting->setEnabled(true);
|
||||
accel_personality_setting->setEnabled(true);
|
||||
op_long_toggle->setEnabled(true);
|
||||
custom_stock_long_toggle->setEnabled(false);
|
||||
params.remove("CustomStockLong");
|
||||
dec_toggle->setEnabled(true);
|
||||
dynamic_personality_toggle->setEnabled(true);
|
||||
} else if (custom_stock_long_toggle->isToggled()) {
|
||||
op_long_toggle->setEnabled(false);
|
||||
experimental_mode_toggle->setEnabled(false);
|
||||
long_personality_setting->setEnabled(false);
|
||||
accel_personality_setting->setEnabled(false);
|
||||
params.remove("ExperimentalLongitudinalEnabled");
|
||||
params.remove("ExperimentalMode");
|
||||
} else {
|
||||
// no long for now
|
||||
experimental_mode_toggle->setEnabled(false);
|
||||
long_personality_setting->setEnabled(false);
|
||||
accel_personality_setting->setEnabled(false);
|
||||
params.remove("ExperimentalMode");
|
||||
|
||||
const QString unavailable = tr("Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control.");
|
||||
@@ -279,26 +183,12 @@ void TogglesPanel::updateToggles() {
|
||||
}
|
||||
}
|
||||
experimental_mode_toggle->setDescription("<b>" + long_desc + "</b><br><br>" + e2e_description);
|
||||
|
||||
op_long_toggle->setEnabled(CP.getExperimentalLongitudinalAvailable() && !is_release);
|
||||
custom_stock_long_toggle->setEnabled(CP.getCustomStockLongAvailable());
|
||||
dec_toggle->setEnabled(false);
|
||||
dynamic_personality_toggle->setEnabled(false);
|
||||
params.remove("DynamicExperimentalControl");
|
||||
params.remove("DynamicPersonality");
|
||||
}
|
||||
|
||||
experimental_mode_toggle->refresh();
|
||||
op_long_toggle->refresh();
|
||||
custom_stock_long_toggle->refresh();
|
||||
dec_toggle->refresh();
|
||||
dynamic_personality_toggle->refresh();
|
||||
} else {
|
||||
experimental_mode_toggle->setDescription(e2e_description);
|
||||
op_long_toggle->setVisible(false);
|
||||
custom_stock_long_toggle->setVisible(false);
|
||||
dec_toggle->setVisible(false);
|
||||
dynamic_personality_toggle->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,44 +197,6 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
addItem(new LabelControl(tr("Dongle ID"), getDongleId().value_or(tr("N/A"))));
|
||||
addItem(new LabelControl(tr("Serial"), params.get("HardwareSerial").c_str()));
|
||||
|
||||
fleetManagerPin = new ButtonControl(
|
||||
pin_title + pin, tr("TOGGLE"),
|
||||
tr("Enable or disable PIN requirement for Fleet Manager access."));
|
||||
connect(fleetManagerPin, &ButtonControl::clicked, [=]() {
|
||||
if (params.getBool("FleetManagerPin")) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to turn off PIN requirement?"), tr("Turn Off"), this)) {
|
||||
params.remove("FleetManagerPin");
|
||||
refreshPin();
|
||||
}
|
||||
} else {
|
||||
params.putBool("FleetManagerPin", true);
|
||||
refreshPin();
|
||||
}
|
||||
});
|
||||
addItem(fleetManagerPin);
|
||||
|
||||
fs_watch = new QFileSystemWatcher(this);
|
||||
connect(fs_watch, &QFileSystemWatcher::fileChanged, this, &DevicePanel::onPinFileChanged);
|
||||
|
||||
QString pin_path = "/data/otp/otp.conf";
|
||||
QString pin_require = "/data/params/d/FleetManagerPin";
|
||||
fs_watch->addPath(pin_path);
|
||||
fs_watch->addPath(pin_require);
|
||||
refreshPin();
|
||||
|
||||
// Error Troubleshoot
|
||||
auto errorBtn = new ButtonControl(
|
||||
tr("Error Troubleshoot"), tr("VIEW"),
|
||||
tr("Display error from the tmux session when an error has occurred from a system process."));
|
||||
QFileInfo file("/data/community/crashes/error.txt");
|
||||
QDateTime modifiedTime = file.lastModified();
|
||||
QString modified_time = modifiedTime.toString("yyyy-MM-dd hh:mm:ss ");
|
||||
connect(errorBtn, &ButtonControl::clicked, [=]() {
|
||||
const std::string txt = util::read_file("/data/community/crashes/error.txt");
|
||||
ConfirmationDialog::rich(modified_time + QString::fromStdString(txt), this);
|
||||
});
|
||||
addItem(errorBtn);
|
||||
|
||||
pair_device = new ButtonControl(tr("Pair Device"), tr("PAIR"),
|
||||
tr("Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer."));
|
||||
connect(pair_device, &ButtonControl::clicked, [=]() {
|
||||
@@ -370,33 +222,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
});
|
||||
addItem(resetCalibBtn);
|
||||
|
||||
auto resetMapboxTokenBtn = new ButtonControl(tr("Reset Access Tokens for Map Services"), tr("RESET"), tr("Reset self-service access tokens for Mapbox, Amap, and Google Maps."));
|
||||
connect(resetMapboxTokenBtn, &ButtonControl::clicked, [=]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to reset access tokens for all map services?"), tr("Reset"), this)) {
|
||||
std::vector<std::string> tokens = {
|
||||
"CustomMapboxTokenPk",
|
||||
"CustomMapboxTokenSk",
|
||||
"AmapKey1",
|
||||
"AmapKey2",
|
||||
"GmapKey"
|
||||
};
|
||||
for (const auto& token : tokens) {
|
||||
params.remove(token);
|
||||
}
|
||||
}
|
||||
});
|
||||
addItem(resetMapboxTokenBtn);
|
||||
|
||||
auto resetParamsBtn = new ButtonControl(tr("Reset sunnypilot Settings"), tr("RESET"), "");
|
||||
connect(resetParamsBtn, &ButtonControl::clicked, [=]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all sunnypilot settings?"), tr("Reset"), this)) {
|
||||
std::system("sudo rm -rf /data/params/d/*");
|
||||
Hardware::reboot();
|
||||
}
|
||||
});
|
||||
addItem(resetParamsBtn);
|
||||
|
||||
auto retrainingBtn = new ButtonControl(tr("Review Training Guide"), tr("REVIEW"), tr("Review the rules, features, and limitations of sunnypilot"));
|
||||
auto retrainingBtn = new ButtonControl(tr("Review Training Guide"), tr("REVIEW"), tr("Review the rules, features, and limitations of openpilot"));
|
||||
connect(retrainingBtn, &ButtonControl::clicked, [=]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to review the training guide?"), tr("Review"), this)) {
|
||||
emit reviewTrainingGuide();
|
||||
@@ -429,16 +255,19 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
QObject::connect(uiState(), &UIState::primeTypeChanged, [this] (PrimeType type) {
|
||||
pair_device->setVisible(type == PrimeType::UNPAIRED);
|
||||
});
|
||||
|
||||
#ifndef SUNNYPILOT
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) {
|
||||
for (auto btn : findChildren<ButtonControl *>()) {
|
||||
if ((btn != pair_device) && (btn != errorBtn)) {
|
||||
if (btn != pair_device) {
|
||||
btn->setEnabled(offroad);
|
||||
}
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
// power buttons
|
||||
QHBoxLayout *power_layout = new QHBoxLayout();
|
||||
power_layout = new QHBoxLayout();
|
||||
power_layout->setSpacing(30);
|
||||
|
||||
QPushButton *reboot_btn = new QPushButton(tr("Reboot"));
|
||||
@@ -455,46 +284,14 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
connect(uiState(), &UIState::offroadTransition, poweroff_btn, &QPushButton::setVisible);
|
||||
}
|
||||
|
||||
offroad_btn = new QPushButton(tr("Toggle Onroad/Offroad"));
|
||||
offroad_btn->setObjectName("offroad_btn");
|
||||
QObject::connect(offroad_btn, &QPushButton::clicked, this, &DevicePanel::forceoffroad);
|
||||
|
||||
QVBoxLayout *buttons_layout = new QVBoxLayout();
|
||||
buttons_layout->setSpacing(24);
|
||||
buttons_layout->addLayout(power_layout);
|
||||
buttons_layout->addWidget(offroad_btn);
|
||||
|
||||
setStyleSheet(R"(
|
||||
#reboot_btn { height: 120px; border-radius: 15px; background-color: #393939; }
|
||||
#reboot_btn:pressed { background-color: #4a4a4a; }
|
||||
#poweroff_btn { height: 120px; border-radius: 15px; background-color: #E22C2C; }
|
||||
#poweroff_btn:pressed { background-color: #FF2424; }
|
||||
)");
|
||||
addItem(buttons_layout);
|
||||
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
void DevicePanel::onPinFileChanged(const QString &file_path) {
|
||||
if (file_path == "/data/params/d/FleetManagerPin") {
|
||||
refreshPin();
|
||||
} else if (file_path == "/data/otp/otp.conf") {
|
||||
refreshPin();
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePanel::refreshPin() {
|
||||
QFile f("/data/otp/otp.conf");
|
||||
QFile require("/data/params/d/FleetManagerPin");
|
||||
if (!require.exists()) {
|
||||
setSpacing(50);
|
||||
fleetManagerPin->setTitle(pin_title + tr("OFF"));
|
||||
} else if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
pin = f.readAll();
|
||||
f.close();
|
||||
setSpacing(50);
|
||||
fleetManagerPin->setTitle(pin_title + pin);
|
||||
}
|
||||
RETURN_IF_SUNNYPILOT
|
||||
addItem(power_layout);
|
||||
}
|
||||
|
||||
void DevicePanel::updateCalibDescription() {
|
||||
@@ -547,51 +344,9 @@ void DevicePanel::poweroff() {
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePanel::forceoffroad() {
|
||||
if (!uiState()->engaged()) {
|
||||
if (params.getBool("ForceOffroad")) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to unforce offroad?"), tr("Unforce"), this)) {
|
||||
// Check engaged again in case it changed while the dialog was open
|
||||
if (!uiState()->engaged()) {
|
||||
params.remove("ForceOffroad");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to force offroad?"), tr("Force"), this)) {
|
||||
// Check engaged again in case it changed while the dialog was open
|
||||
if (!uiState()->engaged()) {
|
||||
params.putBool("ForceOffroad", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ConfirmationDialog::alert(tr("Disengage to Force Offroad"), this);
|
||||
}
|
||||
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
void DevicePanel::showEvent(QShowEvent *event) {
|
||||
pair_device->setVisible(uiState()->primeType() == PrimeType::UNPAIRED);
|
||||
ListWidget::showEvent(event);
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
void DevicePanel::updateLabels() {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool force_offroad_param = params.getBool("ForceOffroad");
|
||||
QString offroad_btn_style = force_offroad_param ? "#393939" : "#E22C2C";
|
||||
QString offroad_btn_pressed_style = force_offroad_param ? "#4a4a4a" : "#FF2424";
|
||||
QString btn_common_style = QString("QPushButton { height: 120px; border-radius: 15px; background-color: %1; }"
|
||||
"QPushButton:pressed { background-color: %2; }")
|
||||
.arg(offroad_btn_style,
|
||||
offroad_btn_pressed_style);
|
||||
|
||||
offroad_btn->setText(force_offroad_param ? tr("Unforce Offroad") : tr("Force Offroad"));
|
||||
offroad_btn->setStyleSheet(btn_common_style + offroad_btn_style + offroad_btn_pressed_style);
|
||||
}
|
||||
|
||||
void SettingsWindow::showEvent(QShowEvent *event) {
|
||||
@@ -607,23 +362,20 @@ void SettingsWindow::setCurrentPanel(int index, const QString ¶m) {
|
||||
}
|
||||
|
||||
SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
RETURN_IF_SUNNYPILOT
|
||||
|
||||
// setup two main layouts
|
||||
sidebar_widget = new QWidget;
|
||||
QVBoxLayout *sidebar_layout = new QVBoxLayout(sidebar_widget);
|
||||
panel_widget = new QStackedWidget();
|
||||
|
||||
// setup layout for close button
|
||||
QVBoxLayout *close_btn_layout = new QVBoxLayout;
|
||||
close_btn_layout->setContentsMargins(0, 0, 0, 20);
|
||||
|
||||
// close button
|
||||
QPushButton *close_btn = new QPushButton(tr("×"));
|
||||
close_btn->setStyleSheet(R"(
|
||||
QPushButton {
|
||||
font-size: 140px;
|
||||
padding-bottom: 20px;
|
||||
border-radius: 76px;
|
||||
border-radius: 100px;
|
||||
background-color: #292929;
|
||||
font-weight: 400;
|
||||
}
|
||||
@@ -631,16 +383,11 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
background-color: #3B3B3B;
|
||||
}
|
||||
)");
|
||||
close_btn->setFixedSize(152, 152);
|
||||
close_btn_layout->addWidget(close_btn, 0, Qt::AlignLeft);
|
||||
close_btn->setFixedSize(200, 200);
|
||||
sidebar_layout->addSpacing(45);
|
||||
sidebar_layout->addWidget(close_btn, 0, Qt::AlignCenter);
|
||||
QObject::connect(close_btn, &QPushButton::clicked, this, &SettingsWindow::closeSettings);
|
||||
|
||||
// setup buttons widget
|
||||
QWidget *buttons_widget = new QWidget;
|
||||
QVBoxLayout *buttons_layout = new QVBoxLayout(buttons_widget);
|
||||
buttons_layout->setMargin(0);
|
||||
buttons_layout->addSpacing(10);
|
||||
|
||||
// setup panels
|
||||
DevicePanel *device = new DevicePanel(this);
|
||||
QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide);
|
||||
@@ -649,43 +396,27 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
TogglesPanel *toggles = new TogglesPanel(this);
|
||||
QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription);
|
||||
|
||||
QList<PanelInfo> panels = {
|
||||
PanelInfo(" " + tr("Device"), device, "../assets/navigation/icon_home.svg"),
|
||||
PanelInfo(" " + tr("Network"), new Networking(this), "../assets/offroad/icon_network.png"),
|
||||
PanelInfo(" " + tr("sunnylink"), new SunnylinkPanel(this), "../assets/offroad/icon_wifi_strength_full.svg"),
|
||||
PanelInfo(" " + tr("Toggles"), toggles, "../assets/offroad/icon_toggle.png"),
|
||||
PanelInfo(" " + tr("Software"), new SoftwarePanelSP(this), "../assets/offroad/icon_software.png"),
|
||||
PanelInfo(" " + tr("sunnypilot"), new SunnypilotPanel(this), "../assets/offroad/icon_openpilot.png"),
|
||||
PanelInfo(" " + tr("OSM"), new OsmPanel(this), "../assets/offroad/icon_map.png"),
|
||||
PanelInfo(" " + tr("Monitoring"), new MonitoringPanel(this), "../assets/offroad/icon_monitoring.png"),
|
||||
PanelInfo(" " + tr("Visuals"), new VisualsPanel(this), "../assets/offroad/icon_visuals.png"),
|
||||
PanelInfo(" " + tr("Display"), new DisplayPanel(this), "../assets/offroad/icon_display.png"),
|
||||
PanelInfo(" " + tr("Trips"), new TripsPanel(this), "../assets/offroad/icon_trips.png"),
|
||||
PanelInfo(" " + tr("Vehicle"), new VehiclePanel(this), "../assets/offroad/icon_vehicle.png"),
|
||||
QList<QPair<QString, QWidget *>> panels = {
|
||||
{tr("Device"), device},
|
||||
{tr("Network"), new Networking(this)},
|
||||
{tr("Toggles"), toggles},
|
||||
{tr("Software"), new SoftwarePanel(this)},
|
||||
};
|
||||
|
||||
nav_btns = new QButtonGroup(this);
|
||||
for (auto &[name, panel, icon] : panels) {
|
||||
for (auto &[name, panel] : panels) {
|
||||
QPushButton *btn = new QPushButton(name);
|
||||
btn->setCheckable(true);
|
||||
btn->setChecked(nav_btns->buttons().size() == 0);
|
||||
btn->setIcon(QIcon(QPixmap(icon)));
|
||||
btn->setIconSize(QSize(70, 70));
|
||||
btn->setStyleSheet(R"(
|
||||
QPushButton {
|
||||
border-radius: 20px;
|
||||
width: 400px;
|
||||
height: 98px;
|
||||
color: #bdbdbd;
|
||||
color: grey;
|
||||
border: none;
|
||||
background: none;
|
||||
font-size: 50px;
|
||||
font-size: 65px;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
padding-left: 22px;
|
||||
}
|
||||
QPushButton:checked {
|
||||
background-color: #696868;
|
||||
color: white;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
@@ -694,9 +425,9 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
)");
|
||||
btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
nav_btns->addButton(btn);
|
||||
buttons_layout->addWidget(btn, 0, Qt::AlignLeft | Qt::AlignBottom);
|
||||
sidebar_layout->addWidget(btn, 0, Qt::AlignRight);
|
||||
|
||||
const int lr_margin = (name != (" " + tr("Network")) || (name != (" " + tr("sunnypilot")))) ? 50 : 0; // Network and sunnypilot panel handles its own margins
|
||||
const int lr_margin = name != tr("Network") ? 50 : 0; // Network panel handles its own margins
|
||||
panel->setContentsMargins(lr_margin, 25, lr_margin, 25);
|
||||
|
||||
ScrollView *panel_frame = new ScrollView(panel, this);
|
||||
@@ -707,18 +438,11 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
panel_widget->setCurrentWidget(w);
|
||||
});
|
||||
}
|
||||
sidebar_layout->setContentsMargins(50, 50, 25, 50);
|
||||
sidebar_layout->setContentsMargins(50, 50, 100, 50);
|
||||
|
||||
// main settings layout, sidebar + main panel
|
||||
QHBoxLayout *main_layout = new QHBoxLayout(this);
|
||||
|
||||
// add layout for close button
|
||||
sidebar_layout->addLayout(close_btn_layout);
|
||||
|
||||
// add layout for buttons scrolling
|
||||
ScrollView *buttons_scrollview = new ScrollView(buttons_widget, this);
|
||||
sidebar_layout->addWidget(buttons_scrollview);
|
||||
|
||||
sidebar_widget->setFixedWidth(500);
|
||||
main_layout->addWidget(sidebar_widget);
|
||||
main_layout->addWidget(panel_widget);
|
||||
@@ -732,7 +456,7 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
background-color: black;
|
||||
}
|
||||
QStackedWidget, ScrollView {
|
||||
background-color: black;
|
||||
background-color: #292929;
|
||||
border-radius: 30px;
|
||||
}
|
||||
)");
|
||||
|
||||
@@ -8,12 +8,23 @@
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QStackedWidget>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#define ListWidget ListWidgetSP
|
||||
#define ParamControl ParamControlSP
|
||||
#define ButtonControl ButtonControlSP
|
||||
#define ButtonParamControl ButtonParamControlSP
|
||||
#define ToggleControl ToggleControlSP
|
||||
#define LabelControl LabelControlSP
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#endif
|
||||
|
||||
// ********** settings window + top-level panels **********
|
||||
class SettingsWindow : public QFrame {
|
||||
@@ -32,19 +43,11 @@ signals:
|
||||
void showDriverView();
|
||||
void expandToggleDescription(const QString ¶m);
|
||||
|
||||
private:
|
||||
protected:
|
||||
QPushButton *sidebar_alert_widget;
|
||||
QWidget *sidebar_widget;
|
||||
QButtonGroup *nav_btns;
|
||||
QStackedWidget *panel_widget;
|
||||
|
||||
struct PanelInfo {
|
||||
QString name;
|
||||
QWidget *widget;
|
||||
QString icon;
|
||||
|
||||
PanelInfo(const QString &name, QWidget *widget, const QString &icon) : name(name), widget(widget), icon(icon) {}
|
||||
};
|
||||
};
|
||||
|
||||
class DevicePanel : public ListWidget {
|
||||
@@ -57,26 +60,15 @@ signals:
|
||||
void reviewTrainingGuide();
|
||||
void showDriverView();
|
||||
|
||||
private slots:
|
||||
protected slots:
|
||||
void poweroff();
|
||||
void reboot();
|
||||
void updateCalibDescription();
|
||||
void onPinFileChanged(const QString &file_path);
|
||||
void refreshPin();
|
||||
void forceoffroad();
|
||||
|
||||
void updateLabels();
|
||||
|
||||
private:
|
||||
protected:
|
||||
Params params;
|
||||
ButtonControl *pair_device;
|
||||
|
||||
ButtonControl *fleetManagerPin;
|
||||
QString pin_title = tr("Fleet Manager PIN:") + " ";
|
||||
QString pin = "OFF";
|
||||
QFileSystemWatcher *fs_watch;
|
||||
|
||||
QPushButton *offroad_btn;
|
||||
QHBoxLayout *power_layout;
|
||||
};
|
||||
|
||||
class TogglesPanel : public ListWidget {
|
||||
@@ -87,18 +79,16 @@ public:
|
||||
|
||||
public slots:
|
||||
void expandToggleDescription(const QString ¶m);
|
||||
void updateToggles();
|
||||
|
||||
private slots:
|
||||
void updateState(const UIState &s);
|
||||
protected slots:
|
||||
virtual void updateState(const UIState &s);
|
||||
|
||||
private:
|
||||
protected:
|
||||
Params params;
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
ButtonParamControl *long_personality_setting;
|
||||
ButtonParamControl *accel_personality_setting;
|
||||
|
||||
ParamWatcher *param_watcher;
|
||||
virtual void updateToggles();
|
||||
};
|
||||
|
||||
class SoftwarePanel : public ListWidget {
|
||||
@@ -114,7 +104,6 @@ protected:
|
||||
bool is_onroad = false;
|
||||
|
||||
QLabel *onroadLbl;
|
||||
LabelControl *currentModelLbl;
|
||||
LabelControl *versionLbl;
|
||||
ButtonControl *installBtn;
|
||||
ButtonControl *downloadBtn;
|
||||
|
||||
@@ -9,22 +9,27 @@
|
||||
|
||||
#include "common/params.h"
|
||||
#include "common/util.h"
|
||||
#include "common/model.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#else
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#endif
|
||||
#include "selfdrive/ui/qt/widgets/input.h"
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#define ListWidget ListWidgetSP
|
||||
#define ButtonControl ButtonControlSP
|
||||
#endif
|
||||
|
||||
|
||||
void SoftwarePanel::checkForUpdates() {
|
||||
std::system("pkill -SIGUSR1 -f system.updated.updated");
|
||||
}
|
||||
|
||||
SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
|
||||
currentModelLbl = new LabelControl(tr("Driving Model"), CURRENT_MODEL);
|
||||
addItem(currentModelLbl);
|
||||
|
||||
onroadLbl = new QLabel(tr("Updates are only downloaded while the car is off."));
|
||||
onroadLbl->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left; padding-top: 30px; padding-bottom: 30px;");
|
||||
addItem(onroadLbl);
|
||||
@@ -74,7 +79,9 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
|
||||
checkForUpdates();
|
||||
}
|
||||
});
|
||||
addItem(targetBranchBtn);
|
||||
if (!params.getBool("IsTestedBranch")) {
|
||||
addItem(targetBranchBtn);
|
||||
}
|
||||
|
||||
// uninstall button
|
||||
auto uninstallBtn = new ButtonControl(tr("Uninstall %1").arg(getBrand()), tr("UNINSTALL"));
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
class CameraOffset : public SPOptionControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CameraOffset();
|
||||
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
};
|
||||
|
||||
class PathOffset : public SPOptionControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PathOffset();
|
||||
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
};
|
||||
|
||||
class CustomOffsetsSettings : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CustomOffsetsSettings(QWidget* parent = nullptr);
|
||||
|
||||
signals:
|
||||
void backPress();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
|
||||
CameraOffset *camera_offset;
|
||||
PathOffset *path_offset;
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
|
||||
class OnroadScreenOff : public SPOptionControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OnroadScreenOff();
|
||||
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
};
|
||||
|
||||
class OnroadScreenOffBrightness : public SPOptionControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OnroadScreenOffBrightness();
|
||||
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
};
|
||||
|
||||
class MaxTimeOffroad : public SPOptionControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MaxTimeOffroad();
|
||||
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
};
|
||||
|
||||
class BrightnessControl : public SPOptionControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BrightnessControl();
|
||||
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
};
|
||||
|
||||
class DisplayPanel : public ListWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DisplayPanel(QWidget *parent = nullptr);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
public slots:
|
||||
void updateToggles();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
|
||||
OnroadScreenOff *onroad_screen_off;
|
||||
OnroadScreenOffBrightness *onroad_screen_off_brightness;
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QEventLoop>
|
||||
|
||||
class JsonFetcher
|
||||
{
|
||||
public:
|
||||
static QJsonObject getJsonFromURL(const QString &url)
|
||||
{
|
||||
const auto qurl = QUrl(url);
|
||||
QNetworkAccessManager manager;
|
||||
const QNetworkRequest request(qurl);
|
||||
QNetworkReply *reply = manager.get(request);
|
||||
QEventLoop loop;
|
||||
|
||||
// Send GET request
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qWarning() << "Failed to fetch data from URL: " << reply->errorString();
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
const QByteArray responseData = reply->readAll();
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(responseData);
|
||||
QJsonObject json = doc.object();
|
||||
|
||||
reply->deleteLater();
|
||||
return json;
|
||||
}
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
class AutoLaneChangeTimer : public SPOptionControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AutoLaneChangeTimer();
|
||||
|
||||
void refresh();
|
||||
|
||||
signals:
|
||||
void toggleUpdated();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
};
|
||||
|
||||
class PauseLateralSpeed : public SPOptionControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PauseLateralSpeed();
|
||||
|
||||
void refresh();
|
||||
|
||||
signals:
|
||||
void ToggleUpdated();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
};
|
||||
|
||||
|
||||
class LaneChangeSettings : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LaneChangeSettings(QWidget* parent = nullptr);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
signals:
|
||||
void backPress();
|
||||
|
||||
public slots:
|
||||
void updateToggles();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
|
||||
AutoLaneChangeTimer *auto_lane_change_timer;
|
||||
PauseLateralSpeed *pause_lateral_speed;
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
class MadsSettings : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MadsSettings(QWidget* parent = nullptr);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
signals:
|
||||
void backPress();
|
||||
|
||||
public slots:
|
||||
void updateToggles();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
|
||||
ButtonParamControl *dlob_settings;
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.h"
|
||||
|
||||
MonitoringPanel::MonitoringPanel(QWidget *parent) : QFrame(parent) {
|
||||
main_layout = new QStackedLayout(this);
|
||||
|
||||
ListWidget *list = new ListWidget(this, false);
|
||||
// param, title, desc, icon
|
||||
std::vector<std::tuple<QString, QString, QString, QString>> toggle_defs{
|
||||
{
|
||||
"HandsOnWheelMonitoring",
|
||||
tr("Enable Hands on Wheel Monitoring"),
|
||||
tr("Monitor and alert when driver is not keeping the hands on the steering wheel."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
}
|
||||
};
|
||||
|
||||
for (auto &[param, title, desc, icon] : toggle_defs) {
|
||||
auto toggle = new ParamControl(param, title, desc, icon, this);
|
||||
|
||||
list->addItem(toggle);
|
||||
toggles[param.toStdString()] = toggle;
|
||||
}
|
||||
|
||||
monitoringScreen = new QWidget(this);
|
||||
QVBoxLayout* vlayout = new QVBoxLayout(monitoringScreen);
|
||||
vlayout->setContentsMargins(50, 20, 50, 20);
|
||||
|
||||
vlayout->addWidget(new ScrollView(list, this), 1);
|
||||
main_layout->addWidget(monitoringScreen);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
class MonitoringPanel : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MonitoringPanel(QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
QStackedLayout* main_layout = nullptr;
|
||||
QWidget* monitoringScreen = nullptr;
|
||||
Params params;
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.h"
|
||||
|
||||
SpeedLimitPolicySettings::SpeedLimitPolicySettings(QWidget* parent) : QWidget(parent) {
|
||||
QVBoxLayout* main_layout = new QVBoxLayout(this);
|
||||
main_layout->setContentsMargins(50, 20, 50, 20);
|
||||
main_layout->setSpacing(20);
|
||||
|
||||
// Back button
|
||||
PanelBackButton* back = new PanelBackButton();
|
||||
connect(back, &QPushButton::clicked, [=]() { emit backPress(); });
|
||||
main_layout->addWidget(back, 0, Qt::AlignLeft);
|
||||
|
||||
ListWidget *list = new ListWidget(this, false);
|
||||
|
||||
speed_limit_policy = new ButtonParamControl(
|
||||
"SpeedLimitControlPolicy",
|
||||
tr("Speed Limit Source Policy"),
|
||||
"",
|
||||
"../assets/offroad/icon_blank.png",
|
||||
speed_limit_policy_texts,
|
||||
250
|
||||
);
|
||||
speed_limit_policy->showDescription();
|
||||
connect(speed_limit_policy, &ButtonParamControl::buttonToggled, this, &SpeedLimitPolicySettings::updateToggles);
|
||||
list->addItem(speed_limit_policy);
|
||||
|
||||
param_watcher = new ParamWatcher(this);
|
||||
|
||||
QObject::connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) {
|
||||
updateToggles();
|
||||
});
|
||||
|
||||
main_layout->addWidget(new ScrollView(list, this));
|
||||
}
|
||||
|
||||
void SpeedLimitPolicySettings::showEvent(QShowEvent *event) {
|
||||
updateToggles();
|
||||
}
|
||||
|
||||
void SpeedLimitPolicySettings::updateToggles() {
|
||||
param_watcher->addParam("SpeedLimitControlPolicy");
|
||||
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: SP: use upstream's setCheckedButton
|
||||
speed_limit_policy->setButton("SpeedLimitControlPolicy");
|
||||
|
||||
speed_limit_policy->setDescription(speedLimitPolicyDescriptionBuilder("SpeedLimitControlPolicy", speed_limit_policy_descriptions));
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/model.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/custom_offsets_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/lane_change_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/mads_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_control_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_warning_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
class TorqueFriction : public SPOptionControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TorqueFriction();
|
||||
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
};
|
||||
|
||||
class TorqueMaxLatAccel : public SPOptionControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TorqueMaxLatAccel();
|
||||
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
};
|
||||
|
||||
class SunnypilotPanel : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SunnypilotPanel(QWidget *parent = nullptr);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent* event) override;
|
||||
|
||||
public slots:
|
||||
void updateToggles();
|
||||
|
||||
private:
|
||||
QStackedLayout* main_layout = nullptr;
|
||||
QWidget* sunnypilotScreen = nullptr;
|
||||
MadsSettings* mads_settings = nullptr;
|
||||
SubPanelButton *slcSettings = nullptr;
|
||||
SlcSettings* slc_settings = nullptr;
|
||||
SubPanelButton *slwSettings = nullptr;
|
||||
SpeedLimitWarningSettings* slw_settings = nullptr;
|
||||
SubPanelButton *slpSettings = nullptr;
|
||||
SpeedLimitPolicySettings* slp_settings = nullptr;
|
||||
LaneChangeSettings* lane_change_settings = nullptr;
|
||||
CustomOffsetsSettings* custom_offsets_settings = nullptr;
|
||||
Params params;
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
ParamWatcher *param_watcher;
|
||||
|
||||
TorqueFriction *friction;
|
||||
TorqueMaxLatAccel *lat_accel_factor;
|
||||
ButtonParamControl *dlp_settings;
|
||||
|
||||
ScrollView *scrollView = nullptr;
|
||||
|
||||
const QString nnff_description = QString("%1<br><br>"
|
||||
"%2")
|
||||
.arg(tr("Formerly known as <b>\"NNFF\"</b>, this replaces the lateral <b>\"torque\"</b> controller with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy."))
|
||||
.arg(tr("Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: ") + "<font color='white'><b>#tuning-nnlc</b></font>");
|
||||
|
||||
QString nnffDescriptionBuilder(const QString &custom_description) {
|
||||
QString description = "<b>" + custom_description + "</b><br><br>" + nnff_description;
|
||||
return description;
|
||||
}
|
||||
|
||||
const QString custom_offsets_description = QString(tr("Add custom offsets to Camera and Path in sunnypilot."));
|
||||
const QString dlp_description = QString(tr("Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions."));
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/trips_settings.h"
|
||||
|
||||
TripsPanel::TripsPanel(QWidget* parent) : QFrame(parent) {
|
||||
QVBoxLayout* main_layout = new QVBoxLayout(this);
|
||||
main_layout->setMargin(0);
|
||||
|
||||
// main content
|
||||
main_layout->addSpacing(25);
|
||||
center_layout = new QStackedLayout();
|
||||
|
||||
driveStatsWidget = new DriveStats;
|
||||
driveStatsWidget->setStyleSheet(R"(
|
||||
QLabel[type="title"] { font-size: 51px; font-weight: 500; }
|
||||
QLabel[type="number"] { font-size: 78px; font-weight: 500; }
|
||||
QLabel[type="unit"] { font-size: 51px; font-weight: 300; color: #A0A0A0; }
|
||||
)");
|
||||
center_layout->addWidget(driveStatsWidget);
|
||||
|
||||
main_layout->addLayout(center_layout, 1);
|
||||
|
||||
setStyleSheet(R"(
|
||||
* {
|
||||
color: white;
|
||||
}
|
||||
TripsPanel > QLabel {
|
||||
font-size: 55px;
|
||||
}
|
||||
)");
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/sunnypilot/drive_stats.h"
|
||||
|
||||
class TripsPanel : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TripsPanel(QWidget* parent = 0);
|
||||
|
||||
private:
|
||||
Params params;
|
||||
|
||||
QStackedLayout* center_layout;
|
||||
DriveStats *driveStatsWidget;
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "common/watchdog.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
class VehiclePanel : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VehiclePanel(QWidget *parent = nullptr);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
public slots:
|
||||
void updateToggles();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
|
||||
QStackedLayout* main_layout = nullptr;
|
||||
QWidget* home = nullptr;
|
||||
|
||||
QPushButton* setCarBtn;
|
||||
QString set;
|
||||
|
||||
QWidget* home_widget;
|
||||
QString prompt_select = tr("Select your car");
|
||||
};
|
||||
|
||||
class SPVehiclesTogglesPanel : public ListWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SPVehiclesTogglesPanel(VehiclePanel *parent);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
public slots:
|
||||
void updateToggles();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
bool is_onroad = false;
|
||||
|
||||
ParamControl *stockLongToyota;
|
||||
ParamControl *toyotaEnhancedBsm;
|
||||
|
||||
const QString toyotaEnhancedBsmDescription = QString("%1<br><br>"
|
||||
"%2")
|
||||
.arg(tr("sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects."))
|
||||
.arg(tr("Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2."));
|
||||
|
||||
QString toyotaEnhancedBsmDesciptionBuilder(const QString &custom_description) {
|
||||
QString description = "<b>" + custom_description + "</b><br><br>" + toyotaEnhancedBsmDescription;
|
||||
return description;
|
||||
}
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
|
||||
class VisualsPanel : public ListWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VisualsPanel(QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
Params params;
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
|
||||
ButtonParamControl *dev_ui_settings;
|
||||
ButtonParamControl *chevron_info_settings;
|
||||
ButtonParamControl *sidebar_temp_setting;
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/display_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/trips_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/osm_settings.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/software_settings_sp.h"
|
||||
#include "selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.h"
|
||||
@@ -0,0 +1,152 @@
|
||||
#include "selfdrive/ui/qt/offroad_home.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "selfdrive/ui/qt/offroad/experimental_mode.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/widgets/prime.h"
|
||||
|
||||
// OffroadHome: the offroad home page
|
||||
|
||||
OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
|
||||
QVBoxLayout* main_layout = new QVBoxLayout(this);
|
||||
main_layout->setContentsMargins(40, 40, 40, 40);
|
||||
|
||||
// top header
|
||||
QHBoxLayout* header_layout = new QHBoxLayout();
|
||||
header_layout->setContentsMargins(0, 0, 0, 0);
|
||||
header_layout->setSpacing(16);
|
||||
|
||||
update_notif = new QPushButton(tr("UPDATE"));
|
||||
update_notif->setVisible(false);
|
||||
update_notif->setStyleSheet("background-color: #364DEF;");
|
||||
QObject::connect(update_notif, &QPushButton::clicked, [=]() { center_layout->setCurrentIndex(1); });
|
||||
header_layout->addWidget(update_notif, 0, Qt::AlignHCenter | Qt::AlignLeft);
|
||||
|
||||
alert_notif = new QPushButton();
|
||||
alert_notif->setVisible(false);
|
||||
alert_notif->setStyleSheet("background-color: #E22C2C;");
|
||||
QObject::connect(alert_notif, &QPushButton::clicked, [=] { center_layout->setCurrentIndex(2); });
|
||||
header_layout->addWidget(alert_notif, 0, Qt::AlignHCenter | Qt::AlignLeft);
|
||||
|
||||
version = new ElidedLabel();
|
||||
header_layout->addWidget(version, 0, Qt::AlignHCenter | Qt::AlignRight);
|
||||
|
||||
main_layout->addLayout(header_layout);
|
||||
|
||||
// main content
|
||||
main_layout->addSpacing(25);
|
||||
center_layout = new QStackedLayout();
|
||||
|
||||
home_widget = new QWidget(this);
|
||||
{
|
||||
home_layout = new QHBoxLayout(home_widget);
|
||||
home_layout->setContentsMargins(0, 0, 0, 0);
|
||||
home_layout->setSpacing(30);
|
||||
|
||||
// left: PrimeAdWidget
|
||||
left_widget = new QStackedWidget(this);
|
||||
QVBoxLayout *left_prime_layout = new QVBoxLayout();
|
||||
QWidget *prime_user = new PrimeUserWidget();
|
||||
prime_user->setStyleSheet(R"(
|
||||
border-radius: 10px;
|
||||
background-color: #333333;
|
||||
)");
|
||||
left_prime_layout->addWidget(prime_user);
|
||||
left_prime_layout->addStretch();
|
||||
left_widget->addWidget(new LayoutWidget(left_prime_layout));
|
||||
left_widget->addWidget(new PrimeAdWidget);
|
||||
left_widget->setStyleSheet("border-radius: 10px;");
|
||||
|
||||
left_widget->setCurrentIndex(uiState()->hasPrime() ? 0 : 1);
|
||||
connect(uiState(), &UIState::primeChanged, [=](bool prime) {
|
||||
left_widget->setCurrentIndex(prime ? 0 : 1);
|
||||
});
|
||||
|
||||
home_layout->addWidget(left_widget, 1);
|
||||
|
||||
// right: ExperimentalModeButton, SetupWidget
|
||||
QWidget* right_widget = new QWidget(this);
|
||||
QVBoxLayout* right_column = new QVBoxLayout(right_widget);
|
||||
right_column->setContentsMargins(0, 0, 0, 0);
|
||||
right_widget->setFixedWidth(750);
|
||||
right_column->setSpacing(30);
|
||||
|
||||
ExperimentalModeButton *experimental_mode = new ExperimentalModeButton(this);
|
||||
QObject::connect(experimental_mode, &ExperimentalModeButton::openSettings, this, &OffroadHome::openSettings);
|
||||
right_column->addWidget(experimental_mode, 1);
|
||||
|
||||
SetupWidget *setup_widget = new SetupWidget;
|
||||
QObject::connect(setup_widget, &SetupWidget::openSettings, this, &OffroadHome::openSettings);
|
||||
right_column->addWidget(setup_widget, 1);
|
||||
|
||||
home_layout->addWidget(right_widget, 1);
|
||||
}
|
||||
center_layout->addWidget(home_widget);
|
||||
|
||||
// add update & alerts widgets
|
||||
update_widget = new UpdateAlert();
|
||||
QObject::connect(update_widget, &UpdateAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); });
|
||||
center_layout->addWidget(update_widget);
|
||||
alerts_widget = new OffroadAlert();
|
||||
QObject::connect(alerts_widget, &OffroadAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); });
|
||||
center_layout->addWidget(alerts_widget);
|
||||
|
||||
main_layout->addLayout(center_layout, 1);
|
||||
|
||||
// set up refresh timer
|
||||
timer = new QTimer(this);
|
||||
timer->callOnTimeout(this, &OffroadHome::refresh);
|
||||
|
||||
setStyleSheet(R"(
|
||||
* {
|
||||
color: white;
|
||||
}
|
||||
OffroadHome {
|
||||
background-color: black;
|
||||
}
|
||||
OffroadHome > QPushButton {
|
||||
padding: 15px 30px;
|
||||
border-radius: 5px;
|
||||
font-size: 40px;
|
||||
font-weight: 500;
|
||||
}
|
||||
OffroadHome > QLabel {
|
||||
font-size: 55px;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
void OffroadHome::showEvent(QShowEvent *event) {
|
||||
refresh();
|
||||
timer->start(10 * 1000);
|
||||
}
|
||||
|
||||
void OffroadHome::hideEvent(QHideEvent *event) {
|
||||
timer->stop();
|
||||
}
|
||||
|
||||
void OffroadHome::refresh() {
|
||||
version->setText(getBrand() + " " + QString::fromStdString(params.get("UpdaterCurrentDescription")));
|
||||
|
||||
bool updateAvailable = update_widget->refresh();
|
||||
int alerts = alerts_widget->refresh();
|
||||
|
||||
// pop-up new notification
|
||||
int idx = center_layout->currentIndex();
|
||||
if (!updateAvailable && !alerts) {
|
||||
idx = 0;
|
||||
} else if (updateAvailable && (!update_notif->isVisible() || (!alerts && idx == 2))) {
|
||||
idx = 1;
|
||||
} else if (alerts && (!alert_notif->isVisible() || (!updateAvailable && idx == 1))) {
|
||||
idx = 2;
|
||||
}
|
||||
center_layout->setCurrentIndex(idx);
|
||||
|
||||
update_notif->setVisible(updateAvailable);
|
||||
alert_notif->setVisible(alerts);
|
||||
if (alerts) {
|
||||
alert_notif->setText(QString::number(alerts) + (alerts > 1 ? tr(" ALERTS") : tr(" ALERT")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <QStackedWidget>
|
||||
#include <QWidget>
|
||||
|
||||
#include "common/params.h"
|
||||
#include "selfdrive/ui/qt/body.h"
|
||||
#include "selfdrive/ui/qt/onroad/onroad_home.h"
|
||||
#include "selfdrive/ui/qt/widgets/offroad_alerts.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/sidebar.h"
|
||||
#define OnroadWindow OnroadWindowSP
|
||||
#define OffroadHomeImp OffroadHomeSP
|
||||
#define LayoutWidget LayoutWidgetSP
|
||||
#define Sidebar SidebarSP
|
||||
#define ElidedLabel ElidedLabelSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/onroad/onroad_home.h"
|
||||
#include "selfdrive/ui/qt/sidebar.h"
|
||||
#endif
|
||||
|
||||
class OffroadHome : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void do_work(QWidget*& home_widget);
|
||||
explicit OffroadHome(QWidget* parent = 0);
|
||||
|
||||
signals:
|
||||
void openSettings(int index = 0, const QString ¶m = "");
|
||||
|
||||
protected:
|
||||
QStackedLayout* center_layout;
|
||||
QWidget* home_widget;
|
||||
QHBoxLayout *home_layout;
|
||||
QStackedWidget *left_widget;
|
||||
|
||||
private:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void refresh();
|
||||
|
||||
Params params;
|
||||
|
||||
QTimer* timer;
|
||||
ElidedLabel* version;
|
||||
UpdateAlert *update_widget;
|
||||
OffroadAlert* alerts_widget;
|
||||
QPushButton* alert_notif;
|
||||
QPushButton* update_notif;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,14 +2,10 @@
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <memory>
|
||||
#include <QTimer>
|
||||
|
||||
#include "selfdrive/ui/qt/onroad/buttons.h"
|
||||
#include "selfdrive/ui/qt/widgets/cameraview.h"
|
||||
|
||||
const int subsign_img_size = 35;
|
||||
const int blinker_size = 120;
|
||||
|
||||
class AnnotatedCameraWidget : public CameraWidget {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -17,68 +13,8 @@ public:
|
||||
explicit AnnotatedCameraWidget(VisionStreamType type, QWidget* parent = 0);
|
||||
void updateState(const UIState &s);
|
||||
|
||||
MapSettingsButton *map_settings_btn;
|
||||
OnroadSettingsButton *onroad_settings_btn;
|
||||
|
||||
private:
|
||||
void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255);
|
||||
void drawCenteredText(QPainter &p, int x, int y, const QString &text, QColor color);
|
||||
void drawVisionTurnControllerUI(QPainter &p, int x, int y, int size, const QColor &color, const QString &speed,
|
||||
int alpha);
|
||||
void drawCircle(QPainter &p, int x, int y, int r, QBrush bg);
|
||||
void drawSpeedSign(QPainter &p, QRect rc, const QString &speed, const QString &sub_text, int subtext_size,
|
||||
bool is_map_sourced, bool is_active);
|
||||
void drawTrunSpeedSign(QPainter &p, QRect rc, const QString &speed, const QString &sub_text, int curv_sign,
|
||||
bool is_active);
|
||||
|
||||
void drawColoredText(QPainter &p, int x, int y, const QString &text, QColor color);
|
||||
void drawStandstillTimer(QPainter &p, int x, int y);
|
||||
|
||||
// ############################## DEV UI START ##############################
|
||||
void drawRightDevUi(QPainter &p, int x, int y);
|
||||
int drawDevUiElementRight(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color);
|
||||
int drawNewDevUiElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color);
|
||||
void drawNewDevUi2(QPainter &p, int x, int y);
|
||||
void drawCenteredLeftText(QPainter &p, int x, int y, const QString &text1, QColor color1, const QString &text2, const QString &text3, QColor color2);
|
||||
struct UiElement {
|
||||
QString value;
|
||||
QString label;
|
||||
QString units;
|
||||
QColor color;
|
||||
|
||||
UiElement(const QString &value, const QString &label, const QString &units, const QColor &color = QColor(255, 255, 255, 255))
|
||||
: value(value), label(label), units(units), color(color) {}
|
||||
};
|
||||
|
||||
UiElement getDRel();
|
||||
UiElement getVRel();
|
||||
UiElement getSteeringAngleDeg();
|
||||
UiElement getActualLateralAccel();
|
||||
UiElement getSteeringAngleDesiredDeg();
|
||||
UiElement getMemoryUsagePercent();
|
||||
|
||||
UiElement getAEgo();
|
||||
UiElement getVEgoLead();
|
||||
UiElement getFrictionCoefficientFiltered();
|
||||
UiElement getLatAccelFactorFiltered();
|
||||
UiElement getSteeringTorqueEps();
|
||||
UiElement getBearingDeg();
|
||||
UiElement getAltitude();
|
||||
|
||||
// ############################## DEV UI END ##############################
|
||||
|
||||
void drawE2eStatus(QPainter &p, int x, int y, int w, int h, int e2e_long_status);
|
||||
|
||||
void drawLeftTurnSignal(QPainter &painter, int x, int y, int circle_size, int state);
|
||||
void drawRightTurnSignal(QPainter &painter, int x, int y, int circle_size, int state);
|
||||
int blinkerPulse(int frame);
|
||||
void updateButtonsLayout(bool is_rhd);
|
||||
|
||||
void drawFeatureStatusText(QPainter &p, int x, int y);
|
||||
void speedLimitSignPulse(int frame);
|
||||
void speedLimitWarning(QPainter &p, QRect sign_rect, const int sign_margin);
|
||||
void mousePressEvent(QMouseEvent* e) override;
|
||||
void drawRoadNameText(QPainter &p, int x, int y, const QString &text, QColor color);
|
||||
|
||||
QVBoxLayout *main_layout;
|
||||
ExperimentalButton *experimental_btn;
|
||||
@@ -86,15 +22,12 @@ private:
|
||||
float speed;
|
||||
QString speedUnit;
|
||||
float setSpeed;
|
||||
float speedLimit;
|
||||
bool is_cruise_set = false;
|
||||
bool is_metric = false;
|
||||
bool dmActive = false;
|
||||
bool hideBottomIcons = false;
|
||||
bool rightHandDM = false;
|
||||
float dm_fade_state = 1.0;
|
||||
bool has_us_speed_limit = false;
|
||||
bool has_eu_speed_limit = false;
|
||||
bool v_ego_cluster_seen = false;
|
||||
int status = STATUS_DISENGAGED;
|
||||
std::unique_ptr<PubMaster> pm;
|
||||
@@ -102,126 +35,19 @@ private:
|
||||
int skip_frame_count = 0;
|
||||
bool wide_cam_requested = false;
|
||||
|
||||
Params params;
|
||||
QHBoxLayout *buttons_layout;
|
||||
QPixmap map_img;
|
||||
QPixmap left_img;
|
||||
QPixmap right_img;
|
||||
bool left_blindspot = false;
|
||||
bool right_blindspot = false;
|
||||
std::unique_ptr<PubMaster> e2e_state;
|
||||
|
||||
bool steerOverride = false;
|
||||
bool gasOverride = false;
|
||||
bool latActive = false;
|
||||
bool madsEnabled = false;
|
||||
|
||||
bool brakeLights;
|
||||
|
||||
bool standStillTimer;
|
||||
bool standStill;
|
||||
float standstillElapsedTime;
|
||||
|
||||
bool showVTC = false;
|
||||
QString vtcSpeed;
|
||||
QColor vtcColor;
|
||||
|
||||
bool showDebugUI = false;
|
||||
|
||||
QString roadName = "";
|
||||
|
||||
bool showSpeedLimit = false;
|
||||
float speedLimitSLC;
|
||||
float speedLimitSLCOffset;
|
||||
float speedLimitWarningOffset;
|
||||
QString slcSubText;
|
||||
float slcSubTextSize = 0.0;
|
||||
bool overSpeedLimit;
|
||||
bool mapSourcedSpeedLimit = false;
|
||||
bool slcActive = false;
|
||||
|
||||
bool showTurnSpeedLimit = false;
|
||||
QString turnSpeedLimit;
|
||||
QString tscSubText;
|
||||
bool tscActive = false;
|
||||
int curveSign = 0;
|
||||
|
||||
bool hideVEgoUi;
|
||||
|
||||
bool splitPanelVisible;
|
||||
|
||||
// ############################## DEV UI START ##############################
|
||||
bool lead_status;
|
||||
float lead_d_rel = 0;
|
||||
float lead_v_rel = 0;
|
||||
QString lateralState;
|
||||
float angleSteers = 0;
|
||||
float steerAngleDesired = 0;
|
||||
float curvature;
|
||||
float roll;
|
||||
int memoryUsagePercent;
|
||||
int devUiInfo;
|
||||
float gpsAccuracy;
|
||||
float altitude;
|
||||
float vEgo;
|
||||
float aEgo;
|
||||
float steeringTorqueEps;
|
||||
float bearingAccuracyDeg;
|
||||
float bearingDeg;
|
||||
bool torquedUseParams;
|
||||
float latAccelFactorFiltered;
|
||||
float frictionCoefficientFiltered;
|
||||
bool liveValid;
|
||||
// ############################## DEV UI END ##############################
|
||||
|
||||
float btnPerc;
|
||||
|
||||
bool reversing;
|
||||
|
||||
int e2eState;
|
||||
int e2eStatus;
|
||||
|
||||
bool left_blinker, right_blinker, lane_change_edge_block;
|
||||
int blinker_frame;
|
||||
int blinker_state = 0;
|
||||
|
||||
cereal::LongitudinalPlanSP::SpeedLimitControlState slcState;
|
||||
int longitudinalPersonality;
|
||||
int dynamicLaneProfile;
|
||||
QString mpcMode;
|
||||
|
||||
int speed_limit_frame;
|
||||
bool slcShowSign = true;
|
||||
QPixmap plus_arrow_up_img;
|
||||
QPixmap minus_arrow_down_img;
|
||||
QRect sl_sign_rect;
|
||||
int rn_offset = 0;
|
||||
bool e2eLongAlertUi, dynamicExperimentalControlToggle, speedLimitControlToggle, speedLimitWarningFlash;
|
||||
cereal::CarParams::Reader car_params;
|
||||
bool cruiseStateEnabled;
|
||||
bool experimentalMode;
|
||||
|
||||
bool featureStatusToggle;
|
||||
|
||||
cereal::ModelGeneration drivingModelGen;
|
||||
|
||||
protected:
|
||||
void paintGL() override;
|
||||
void initializeGL() override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void updateFrameMat() override;
|
||||
void drawLaneLines(QPainter &painter, const UIState *s);
|
||||
void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd,
|
||||
int num, const cereal::CarState::Reader &car_data, int chevron_data);
|
||||
void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd);
|
||||
void drawHud(QPainter &p);
|
||||
void drawDriverState(QPainter &painter, const UIState *s);
|
||||
inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); }
|
||||
inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); }
|
||||
inline QColor blackColor(int alpha = 255) { return QColor(0, 0, 0, alpha); }
|
||||
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void rocketFuel(QPainter &p);
|
||||
|
||||
double prev_draw_t = 0;
|
||||
FirstOrderFilter fps_filter;
|
||||
};
|
||||
|
||||
@@ -15,18 +15,6 @@ void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrus
|
||||
p.setOpacity(1.0);
|
||||
}
|
||||
|
||||
static void drawCustomButtonIcon(QPainter &p, const int btn_size_x, const int btn_size_y, const QPixmap &img, const QBrush &bg, float opacity) {
|
||||
QPoint center(btn_size_x / 2, btn_size_y / 2);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.setOpacity(1.0); // bg dictates opacity of ellipse
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(bg);
|
||||
p.drawEllipse(center, btn_size_x / 2, btn_size_y / 2);
|
||||
p.setOpacity(opacity);
|
||||
p.drawPixmap(center - QPoint(img.width() / 2, img.height() / 2), img);
|
||||
p.setOpacity(1.0);
|
||||
}
|
||||
|
||||
// ExperimentalButton
|
||||
ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(false), engageable(false), QPushButton(parent) {
|
||||
setFixedSize(btn_size, btn_size);
|
||||
@@ -46,8 +34,7 @@ void ExperimentalButton::changeMode() {
|
||||
|
||||
void ExperimentalButton::updateState(const UIState &s) {
|
||||
const auto cs = (*s.sm)["controlsState"].getControlsState();
|
||||
const auto lp_sp = (*s.sm)["longitudinalPlanSP"].getLongitudinalPlanSP();
|
||||
bool eng = (cs.getEngageable() || cs.getEnabled()) && !(lp_sp.getVisionTurnControllerState() > cereal::LongitudinalPlanSP::VisionTurnControllerState::DISABLED);
|
||||
bool eng = cs.getEngageable() || cs.getEnabled();
|
||||
if ((cs.getExperimentalMode() != experimental_mode) || (eng != engageable)) {
|
||||
engageable = eng;
|
||||
experimental_mode = cs.getExperimentalMode();
|
||||
@@ -60,48 +47,3 @@ void ExperimentalButton::paintEvent(QPaintEvent *event) {
|
||||
QPixmap img = experimental_mode ? experimental_img : engage_img;
|
||||
drawIcon(p, QPoint(btn_size / 2, btn_size / 2), img, QColor(0, 0, 0, 166), (isDown() || !engageable) ? 0.6 : 1.0);
|
||||
}
|
||||
|
||||
|
||||
// MapSettingsButton
|
||||
MapSettingsButton::MapSettingsButton(QWidget *parent) : QPushButton(parent) {
|
||||
// btn_size: 192 * 80% ~= 152
|
||||
// img_size: (152 / 4) * 3 = 114
|
||||
setFixedSize(152, 152);
|
||||
settings_img = loadPixmap("../assets/navigation/icon_directions_outlined.svg", {114, 114});
|
||||
|
||||
// hidden by default, made visible if map is created (has prime or mapbox token)
|
||||
setVisible(false);
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
void MapSettingsButton::paintEvent(QPaintEvent *event) {
|
||||
QPainter p(this);
|
||||
drawCustomButtonIcon(p, 152, 152, settings_img, QColor(0, 0, 0, 166), isDown() ? 0.6 : 1.0);
|
||||
}
|
||||
|
||||
|
||||
// OnroadSettingsButton
|
||||
OnroadSettingsButton::OnroadSettingsButton(QWidget *parent) : QPushButton(parent) {
|
||||
// btn_size: 192 * 80% ~= 152
|
||||
// img_size: (152 / 4) * 3 = 114
|
||||
setFixedSize(152, 152);
|
||||
settings_img = loadPixmap("../assets/navigation/icon_settings.svg", {114, 114});
|
||||
|
||||
// hidden by default, made visible if Driving Personality / GAC, DLP, DEC, or SLC is enabled
|
||||
setVisible(false);
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
void OnroadSettingsButton::paintEvent(QPaintEvent *event) {
|
||||
QPainter p(this);
|
||||
drawCustomButtonIcon(p, 152, 152, settings_img, QColor(0, 0, 0, 166), isDown() ? 0.6 : 1.0);
|
||||
}
|
||||
|
||||
void OnroadSettingsButton::updateState(const UIState &s) {
|
||||
const auto cp = (*s.sm)["carParams"].getCarParams();
|
||||
auto dlp_enabled = s.scene.driving_model_generation == cereal::ModelGeneration::ONE;
|
||||
bool allow_btn = s.scene.onroad_settings_toggle && (dlp_enabled || hasLongitudinalControl(cp) || !cp.getPcmCruiseSpeed());
|
||||
|
||||
setVisible(allow_btn);
|
||||
setEnabled(allow_btn);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
const int btn_size = 192;
|
||||
const int img_size = (btn_size / 4) * 3;
|
||||
@@ -14,6 +18,10 @@ public:
|
||||
explicit ExperimentalButton(QWidget *parent = 0);
|
||||
void updateState(const UIState &s);
|
||||
|
||||
protected:
|
||||
bool experimental_mode;
|
||||
bool engageable;
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void changeMode();
|
||||
@@ -21,35 +29,6 @@ private:
|
||||
Params params;
|
||||
QPixmap engage_img;
|
||||
QPixmap experimental_img;
|
||||
bool experimental_mode;
|
||||
bool engageable;
|
||||
};
|
||||
|
||||
|
||||
class MapSettingsButton : public QPushButton {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MapSettingsButton(QWidget *parent = 0);
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
QPixmap settings_img;
|
||||
};
|
||||
|
||||
|
||||
class OnroadSettingsButton : public QPushButton {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OnroadSettingsButton(QWidget *parent = 0);
|
||||
void updateState(const UIState &s);
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
QPixmap settings_img;
|
||||
};
|
||||
|
||||
void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity);
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
#include <QPainter>
|
||||
#include <QStackedLayout>
|
||||
|
||||
#ifdef ENABLE_MAPS
|
||||
#include "selfdrive/ui/qt/maps/map_helpers.h"
|
||||
#include "selfdrive/ui/qt/maps/map_panel.h"
|
||||
#endif
|
||||
#include "selfdrive/ui/qt/onroad_settings_panel.h"
|
||||
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
|
||||
@@ -31,11 +25,6 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
|
||||
split->insertWidget(0, arCam);
|
||||
}
|
||||
|
||||
if (getenv("MAP_RENDER_VIEW")) {
|
||||
CameraWidget *map_render = new CameraWidget("navd", VISION_STREAM_MAP, false, this);
|
||||
split->insertWidget(0, map_render);
|
||||
}
|
||||
|
||||
stacked_layout->addWidget(split_wrapper);
|
||||
|
||||
alerts = new OnroadAlerts(this);
|
||||
@@ -46,9 +35,12 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
|
||||
alerts->raise();
|
||||
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
// We handle the connection of the signals on the derived class
|
||||
#ifndef SUNNYPILOT
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &OnroadWindow::updateState);
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &OnroadWindow::offroadTransition);
|
||||
QObject::connect(uiState(), &UIState::primeChanged, this, &OnroadWindow::primeChanged);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnroadWindow::updateState(const UIState &s) {
|
||||
@@ -56,12 +48,6 @@ void OnroadWindow::updateState(const UIState &s) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s.scene.map_on_left || s.scene.mapbox_fullscreen) {
|
||||
split->setDirection(QBoxLayout::LeftToRight);
|
||||
} else {
|
||||
split->setDirection(QBoxLayout::RightToLeft);
|
||||
}
|
||||
|
||||
alerts->updateState(s);
|
||||
nvg->updateState(s);
|
||||
|
||||
@@ -73,99 +59,10 @@ void OnroadWindow::updateState(const UIState &s) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OnroadWindow::mousePressEvent(QMouseEvent* e) {
|
||||
#ifdef ENABLE_MAPS
|
||||
UIState *s = uiState();
|
||||
UIScene &scene = s->scene;
|
||||
if (map != nullptr && !isOnroadSettingsVisible()) {
|
||||
if (wakeScreenTimeout()) {
|
||||
// Switch between map and sidebar when using navigate on openpilot
|
||||
bool sidebarVisible = geometry().x() > 0;
|
||||
bool show_map = uiState()->scene.navigate_on_openpilot_deprecated ? sidebarVisible : !sidebarVisible;
|
||||
updateMapSize(scene);
|
||||
map->setVisible(show_map && !map->isVisible());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (onroad_settings != nullptr && !isMapVisible()) {
|
||||
if (wakeScreenTimeout()) {
|
||||
onroad_settings->setVisible(false);
|
||||
}
|
||||
}
|
||||
// propagation event to parent(HomeWindow)
|
||||
QWidget::mousePressEvent(e);
|
||||
}
|
||||
|
||||
void OnroadWindow::createMapWidget() {
|
||||
#ifdef ENABLE_MAPS
|
||||
auto m = new MapPanel(get_mapbox_settings());
|
||||
map = m;
|
||||
|
||||
QObject::connect(m, &MapPanel::mapPanelRequested, this, &OnroadWindow::mapPanelRequested);
|
||||
QObject::connect(m, &MapPanel::mapPanelRequested, this, &OnroadWindow::onroadSettingsPanelNotRequested);
|
||||
QObject::connect(nvg->map_settings_btn, &MapSettingsButton::clicked, m, &MapPanel::toggleMapSettings);
|
||||
nvg->map_settings_btn->setEnabled(true);
|
||||
|
||||
m->setFixedWidth(uiState()->scene.mapbox_fullscreen ? topWidget(this)->width() :
|
||||
topWidget(this)->width() / 2 - UI_BORDER_SIZE);
|
||||
split->insertWidget(0, m);
|
||||
|
||||
// hidden by default, made visible when navRoute is published
|
||||
m->setVisible(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnroadWindow::createOnroadSettingsWidget() {
|
||||
auto os = new OnroadSettingsPanel(this);
|
||||
onroad_settings = os;
|
||||
|
||||
QObject::connect(os, &OnroadSettingsPanel::onroadSettingsPanelRequested, this, &OnroadWindow::onroadSettingsPanelRequested);
|
||||
QObject::connect(os, &OnroadSettingsPanel::onroadSettingsPanelRequested, this, &OnroadWindow::mapPanelNotRequested);
|
||||
QObject::connect(nvg->onroad_settings_btn, &OnroadSettingsButton::clicked, os, &OnroadSettingsPanel::toggleOnroadSettings);
|
||||
nvg->onroad_settings_btn->setEnabled(true);
|
||||
|
||||
os->setFixedWidth(topWidget(this)->width() / 2.6 - UI_BORDER_SIZE);
|
||||
split->insertWidget(0, os);
|
||||
|
||||
// hidden by default
|
||||
os->setVisible(false);
|
||||
}
|
||||
|
||||
void OnroadWindow::offroadTransition(bool offroad) {
|
||||
if (!offroad) {
|
||||
#ifdef ENABLE_MAPS
|
||||
if (map == nullptr && (uiState()->hasPrime() || !MAPBOX_TOKEN.isEmpty())) {
|
||||
createMapWidget();
|
||||
}
|
||||
#endif
|
||||
if (onroad_settings == nullptr) {
|
||||
createOnroadSettingsWidget();
|
||||
}
|
||||
}
|
||||
|
||||
alerts->clear();
|
||||
}
|
||||
|
||||
void OnroadWindow::updateMapSize(const UIScene &scene) {
|
||||
map->setFixedWidth(scene.mapbox_fullscreen ? topWidget(this)->width() :
|
||||
topWidget(this)->width() / 2 - UI_BORDER_SIZE);
|
||||
split->insertWidget(0, map);
|
||||
}
|
||||
|
||||
void OnroadWindow::primeChanged(bool prime) {
|
||||
#ifdef ENABLE_MAPS
|
||||
if (map && (!prime && MAPBOX_TOKEN.isEmpty())) {
|
||||
nvg->map_settings_btn->setEnabled(false);
|
||||
nvg->map_settings_btn->setVisible(false);
|
||||
map->deleteLater();
|
||||
map = nullptr;
|
||||
} else if (!map && (prime || !MAPBOX_TOKEN.isEmpty())) {
|
||||
createMapWidget();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnroadWindow::paintEvent(QPaintEvent *event) {
|
||||
QPainter p(this);
|
||||
p.fillRect(rect(), QColor(bg.red(), bg.green(), bg.blue(), 255));
|
||||
|
||||
@@ -1,51 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/params.h"
|
||||
#include "selfdrive/ui/qt/onroad/alerts.h"
|
||||
|
||||
#if SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h"
|
||||
#define AnnotatedCameraWidget AnnotatedCameraWidgetSP
|
||||
#define UIState UIStateSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/onroad/annotated_camera.h"
|
||||
#endif
|
||||
|
||||
class OnroadWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OnroadWindow(QWidget* parent = 0);
|
||||
bool isMapVisible() const { return map && map->isVisible(); }
|
||||
void showMapPanel(bool show) { if (map) map->setVisible(show); }
|
||||
|
||||
bool isOnroadSettingsVisible() const { return onroad_settings && onroad_settings->isVisible(); }
|
||||
bool isMapAvailable() const { return map; }
|
||||
void mapPanelNotRequested() { if (map) map->setVisible(false); }
|
||||
void onroadSettingsPanelNotRequested() { if (onroad_settings) onroad_settings->setVisible(false); }
|
||||
|
||||
bool wakeScreenTimeout() {
|
||||
if ((uiState()->scene.sleep_btn != 0 && uiState()->scene.sleep_btn_opacity != 0) ||
|
||||
(uiState()->scene.sleep_time != 0 && uiState()->scene.onroadScreenOff != -2)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
signals:
|
||||
void mapPanelRequested();
|
||||
void onroadSettingsPanelRequested();
|
||||
|
||||
private:
|
||||
void createMapWidget();
|
||||
void createOnroadSettingsWidget();
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void mousePressEvent(QMouseEvent* e) override;
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
OnroadAlerts *alerts;
|
||||
AnnotatedCameraWidget *nvg;
|
||||
QColor bg = bg_colors[STATUS_DISENGAGED];
|
||||
QWidget *map = nullptr;
|
||||
QWidget *onroad_settings = nullptr;
|
||||
QHBoxLayout* split;
|
||||
|
||||
Params params;
|
||||
|
||||
private slots:
|
||||
void offroadTransition(bool offroad);
|
||||
void primeChanged(bool prime);
|
||||
void updateState(const UIState &s);
|
||||
void updateMapSize(const UIScene &scene);
|
||||
protected slots:
|
||||
virtual void offroadTransition(bool offroad);
|
||||
virtual void updateState(const UIState &s);
|
||||
};
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#include "selfdrive/ui/qt/onroad_settings_panel.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include "selfdrive/ui/qt/onroad_settings.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
OnroadSettingsPanel::OnroadSettingsPanel(QWidget *parent) : QFrame(parent) {
|
||||
content_stack = new QStackedLayout(this);
|
||||
content_stack->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
auto onroad_settings = new OnroadSettings(true, parent);
|
||||
QObject::connect(onroad_settings, &OnroadSettings::closeSettings, this, &OnroadSettings::hide);
|
||||
content_stack->addWidget(onroad_settings);
|
||||
}
|
||||
|
||||
void OnroadSettingsPanel::toggleOnroadSettings() {
|
||||
if (isVisible()) {
|
||||
hide();
|
||||
} else {
|
||||
emit onroadSettingsPanelRequested();
|
||||
show();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#ifdef ENABLE_MAPS
|
||||
#include <QMapLibre/Settings>
|
||||
#endif
|
||||
#include <QStackedLayout>
|
||||
|
||||
class OnroadSettingsPanel : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OnroadSettingsPanel(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void onroadSettingsPanelRequested();
|
||||
|
||||
public slots:
|
||||
void toggleOnroadSettings();
|
||||
|
||||
private:
|
||||
QStackedLayout *content_stack;
|
||||
};
|
||||
@@ -1,36 +1,36 @@
|
||||
#include "selfdrive/ui/qt/request_repeater.h"
|
||||
|
||||
#include "common/swaglog.h"
|
||||
|
||||
RequestRepeater::RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey,
|
||||
int period, bool whileOnroad, bool sunnylink) : HttpRequest(parent, true, 20000, sunnylink) {
|
||||
request_url = requestURL;
|
||||
while_onroad = whileOnroad;
|
||||
int period, bool while_onroad) : HttpRequest(parent) {
|
||||
timer = new QTimer(this);
|
||||
timer->setTimerType(Qt::VeryCoarseTimer);
|
||||
connect(timer, &QTimer::timeout, [=]() { this->timerTick(); });
|
||||
|
||||
connectTimer(requestURL, while_onroad);
|
||||
|
||||
timer->start(period * 1000);
|
||||
|
||||
setupCacheProcess(cacheKey);
|
||||
}
|
||||
|
||||
void RequestRepeater::connectTimer(const QString &requestURL, bool while_onroad) {
|
||||
QObject::connect(timer, &QTimer::timeout, [=]() {
|
||||
if ((!uiState()->scene.started || while_onroad) && device()->isAwake() && !active()) {
|
||||
sendRequest(requestURL);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RequestRepeater::setupCacheProcess(const QString &cacheKey) {
|
||||
if (!cacheKey.isEmpty()) {
|
||||
prevResp = QString::fromStdString(params.get(cacheKey.toStdString()));
|
||||
if (!prevResp.isEmpty()) {
|
||||
QTimer::singleShot(500, [=]() { emit requestDone(prevResp, true, QNetworkReply::NoError); });
|
||||
}
|
||||
connect(this, &HttpRequest::requestDone, [=](const QString &resp, bool success) {
|
||||
QObject::connect(this, &HttpRequest::requestDone, [=](const QString &resp, bool success) {
|
||||
if (success && resp != prevResp) {
|
||||
params.put(cacheKey.toStdString(), resp.toStdString());
|
||||
prevResp = resp;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Don't wait for the timer to fire to send the first request
|
||||
ForceUpdate();
|
||||
}
|
||||
|
||||
void RequestRepeater::timerTick() {
|
||||
if ((!uiState()->scene.started || while_onroad) && device()->isAwake() && !active()) {
|
||||
LOGD("Sending request for %s", qPrintable(request_url));
|
||||
sendRequest(request_url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "common/util.h"
|
||||
#include "selfdrive/ui/qt/api.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/api.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/api.h"
|
||||
#endif
|
||||
|
||||
class RequestRepeater : public HttpRequest {
|
||||
public:
|
||||
void connectTimer(const QString& requestURL, bool while_onroad);
|
||||
void setupCacheProcess(const QString& cacheKey);
|
||||
RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey = "", int period = 0, bool while_onroad=false);
|
||||
|
||||
private:
|
||||
Params params;
|
||||
QTimer *timer;
|
||||
QString prevResp;
|
||||
QString request_url;
|
||||
bool while_onroad;
|
||||
void timerTick();
|
||||
|
||||
public:
|
||||
RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey = "", int period = 0, bool whileOnroad=false, bool sunnylink = false);
|
||||
void ForceUpdate() {
|
||||
LOGD("Forcing update for %s", qPrintable(request_url));
|
||||
timerTick();
|
||||
}
|
||||
};
|
||||
|
||||
+13
-76
@@ -1,11 +1,8 @@
|
||||
#include "selfdrive/ui/qt/sidebar.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "common/params.h"
|
||||
|
||||
void Sidebar::drawMetric(QPainter &p, const QPair<QString, QString> &label, QColor c, int y) {
|
||||
const QRect rect = {30, y, 240, 126};
|
||||
@@ -93,58 +90,16 @@ void Sidebar::updateState(const UIState &s) {
|
||||
}
|
||||
setProperty("connectStatus", QVariant::fromValue(connectStatus));
|
||||
|
||||
if (sm.frame % UI_FREQ == 0) { // Update every 1 Hz
|
||||
switch (s.scene.sidebar_temp_options) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
sidebar_temp = QString::number((int)deviceState.getMemoryTempC());
|
||||
break;
|
||||
case 2: {
|
||||
const auto& cpu_temp_list = deviceState.getCpuTempC();
|
||||
float max_cpu_temp = std::numeric_limits<float>::lowest();
|
||||
|
||||
for (const float& temp : cpu_temp_list) {
|
||||
max_cpu_temp = std::max(max_cpu_temp, temp);
|
||||
}
|
||||
|
||||
if (max_cpu_temp >= 0) {
|
||||
sidebar_temp = QString::number(std::nearbyint(max_cpu_temp));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
const auto& gpu_temp_list = deviceState.getGpuTempC();
|
||||
float max_gpu_temp = std::numeric_limits<float>::lowest();
|
||||
|
||||
for (const float& temp : gpu_temp_list) {
|
||||
max_gpu_temp = std::max(max_gpu_temp, temp);
|
||||
}
|
||||
|
||||
if (max_gpu_temp >= 0) {
|
||||
sidebar_temp = QString::number(std::nearbyint(max_gpu_temp));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
sidebar_temp = QString::number((int)deviceState.getMaxTempC());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
setProperty("sidebarTemp", sidebar_temp + "°C");
|
||||
}
|
||||
|
||||
bool show_sidebar_temp = s.scene.sidebar_temp_options != 0;
|
||||
ItemStatus tempStatus = {{tr("TEMP"), show_sidebar_temp ? sidebar_temp_str : tr("HIGH")}, danger_color};
|
||||
#ifndef SUNNYPILOT
|
||||
ItemStatus tempStatus = {{tr("TEMP"), tr("HIGH")}, danger_color};
|
||||
auto ts = deviceState.getThermalStatus();
|
||||
if (ts == cereal::DeviceState::ThermalStatus::GREEN) {
|
||||
tempStatus = {{tr("TEMP"), show_sidebar_temp ? sidebar_temp_str : tr("GOOD")}, good_color};
|
||||
tempStatus = {{tr("TEMP"), tr("GOOD")}, good_color};
|
||||
} else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) {
|
||||
tempStatus = {{tr("TEMP"), show_sidebar_temp ? sidebar_temp_str : tr("OK")}, warning_color};
|
||||
tempStatus = {{tr("TEMP"), tr("OK")}, warning_color};
|
||||
}
|
||||
setProperty("tempStatus", QVariant::fromValue(tempStatus));
|
||||
#endif
|
||||
|
||||
ItemStatus pandaStatus = {{tr("VEHICLE"), tr("ONLINE")}, good_color};
|
||||
if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) {
|
||||
@@ -153,32 +108,14 @@ void Sidebar::updateState(const UIState &s) {
|
||||
pandaStatus = {{tr("GPS"), tr("SEARCH")}, warning_color};
|
||||
}
|
||||
setProperty("pandaStatus", QVariant::fromValue(pandaStatus));
|
||||
|
||||
ItemStatus sunnylinkStatus;
|
||||
auto sl_dongle_id = getSunnylinkDongleId();
|
||||
auto last_sunnylink_ping_str = params.get("LastSunnylinkPingTime");
|
||||
auto last_sunnylink_ping = std::stoull(last_sunnylink_ping_str.empty() ? "0" : last_sunnylink_ping_str);
|
||||
auto elapsed_sunnylink_ping = nanos_since_boot() - last_sunnylink_ping;
|
||||
auto sunnylink_enabled = params.getBool("SunnylinkEnabled");
|
||||
|
||||
QString status = tr("DISABLED");
|
||||
QColor color = disabled_color;
|
||||
|
||||
if (sunnylink_enabled && last_sunnylink_ping == 0) {
|
||||
// If sunnylink is enabled, but we don't have a dongle id, and we haven't received a ping yet, we are registering
|
||||
status = sl_dongle_id.has_value() ? tr("OFFLINE") : tr("REGIST...");
|
||||
color = sl_dongle_id.has_value() ? warning_color : progress_color;
|
||||
} else if (sunnylink_enabled) {
|
||||
// If sunnylink is enabled, we are considered online if we have received a ping in the last 80 seconds, else error.
|
||||
status = elapsed_sunnylink_ping < 80000000000ULL ? tr("ONLINE") : tr("ERROR");
|
||||
color = elapsed_sunnylink_ping < 80000000000ULL ? good_color : danger_color;
|
||||
}
|
||||
sunnylinkStatus = ItemStatus{{tr("SUNNYLINK"), status}, color };
|
||||
setProperty("sunnylinkStatus", QVariant::fromValue(sunnylinkStatus));
|
||||
}
|
||||
|
||||
void Sidebar::paintEvent(QPaintEvent *event) {
|
||||
QPainter p(this);
|
||||
DrawSidebar(p); // Because derived classes implement this. Otherwise QPainter gets terminated before time.
|
||||
}
|
||||
|
||||
void Sidebar::DrawSidebar(QPainter &p){
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
@@ -204,10 +141,10 @@ void Sidebar::paintEvent(QPaintEvent *event) {
|
||||
p.setPen(QColor(0xff, 0xff, 0xff));
|
||||
const QRect r = QRect(50, 247, 100, 50);
|
||||
p.drawText(r, Qt::AlignCenter, net_type);
|
||||
RETURN_IF_SUNNYPILOT // Because we draw ourselves
|
||||
|
||||
// metrics
|
||||
drawMetric(p, temp_status.first, temp_status.second, 310);
|
||||
drawMetric(p, panda_status.first, panda_status.second, 440);
|
||||
drawMetric(p, connect_status.first, connect_status.second, 570);
|
||||
drawMetric(p, sunnylink_status.first, sunnylink_status.second, 700);
|
||||
drawMetric(p, temp_status.first, temp_status.second, 338);
|
||||
drawMetric(p, panda_status.first, panda_status.second, 496);
|
||||
drawMetric(p, connect_status.first, connect_status.second, 654);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
|
||||
#include <QFrame>
|
||||
#include <QMap>
|
||||
#include "cereal/messaging/messaging.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
typedef QPair<QPair<QString, QString>, QColor> ItemStatus;
|
||||
Q_DECLARE_METATYPE(ItemStatus);
|
||||
@@ -13,12 +18,10 @@ Q_DECLARE_METATYPE(ItemStatus);
|
||||
class Sidebar : public QFrame {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(ItemStatus connectStatus MEMBER connect_status NOTIFY valueChanged);
|
||||
Q_PROPERTY(ItemStatus sunnylinkStatus MEMBER sunnylink_status NOTIFY valueChanged);
|
||||
Q_PROPERTY(ItemStatus pandaStatus MEMBER panda_status NOTIFY valueChanged);
|
||||
Q_PROPERTY(ItemStatus tempStatus MEMBER temp_status NOTIFY valueChanged);
|
||||
Q_PROPERTY(QString netType MEMBER net_type NOTIFY valueChanged);
|
||||
Q_PROPERTY(int netStrength MEMBER net_strength NOTIFY valueChanged);
|
||||
Q_PROPERTY(QString sidebarTemp MEMBER sidebar_temp_str NOTIFY valueChanged);
|
||||
|
||||
public:
|
||||
explicit Sidebar(QWidget* parent = 0);
|
||||
@@ -36,6 +39,7 @@ protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void drawMetric(QPainter &p, const QPair<QString, QString> &label, QColor c, int y);
|
||||
virtual void DrawSidebar(QPainter &p);
|
||||
|
||||
QPixmap home_img, flag_img, settings_img;
|
||||
bool onroad, flag_pressed, settings_pressed;
|
||||
@@ -52,19 +56,13 @@ protected:
|
||||
const QRect home_btn = QRect(60, 860, 180, 180);
|
||||
const QRect settings_btn = QRect(50, 35, 200, 117);
|
||||
const QColor good_color = QColor(255, 255, 255);
|
||||
const QColor progress_color = QColor(3, 132, 252);
|
||||
const QColor warning_color = QColor(218, 202, 37);
|
||||
const QColor danger_color = QColor(201, 34, 49);
|
||||
const QColor disabled_color = QColor(128, 128, 128);
|
||||
|
||||
ItemStatus connect_status, panda_status, temp_status, sunnylink_status;
|
||||
ItemStatus connect_status, panda_status, temp_status;
|
||||
QString net_type;
|
||||
int net_strength = 0;
|
||||
|
||||
private:
|
||||
Params params;
|
||||
std::unique_ptr<PubMaster> pm;
|
||||
|
||||
QString sidebar_temp = "0";
|
||||
QString sidebar_temp_str = "0";
|
||||
};
|
||||
|
||||
@@ -4,41 +4,12 @@
|
||||
#include <QScrollBar>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <QtConcurrent>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
|
||||
#include "common/params.h"
|
||||
#include "common/swaglog.h"
|
||||
#include "system/hardware/hw.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
std::string executeCommand(const char* cmd) {
|
||||
std::array<char, 128> buffer{};
|
||||
std::ostringstream result;
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
||||
if (!pipe) {
|
||||
LOGW("Failed to open pipe");
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
result << buffer.data();
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
|
||||
// The format is intentional!
|
||||
QString text = QString("%1\n%2\n%3\n%4\n%5\n%6\n%7")
|
||||
.arg(" ________________________________________")
|
||||
.arg("| |")
|
||||
.arg("| " + QObject::tr("Update downloaded. Ready to reboot.") + " |")
|
||||
.arg("| |")
|
||||
.arg("| " + QObject::tr("Update: Check and Download Update") + " |")
|
||||
.arg("| " + QObject::tr("Reboot: Reboot Device") + " |")
|
||||
.arg("|________________________________________|");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
initApp(argc, argv);
|
||||
QApplication a(argc, argv);
|
||||
@@ -51,7 +22,6 @@ int main(int argc, char *argv[]) {
|
||||
QLabel *label = new QLabel(argv[1]);
|
||||
label->setWordWrap(true);
|
||||
label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
|
||||
label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||
ScrollView *scroll = new ScrollView(label);
|
||||
scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
main_layout->addWidget(scroll, 0, 0, Qt::AlignTop);
|
||||
@@ -62,54 +32,16 @@ int main(int argc, char *argv[]) {
|
||||
});
|
||||
|
||||
QPushButton *btn = new QPushButton();
|
||||
QPushButton *update_btn = new QPushButton();
|
||||
update_btn->setText(QObject::tr("Update"));
|
||||
#ifdef __aarch64__
|
||||
btn->setText(QObject::tr("Reboot"));
|
||||
QFutureWatcher<void> watcher;
|
||||
QObject::connect(btn, &QPushButton::clicked, [=]() {
|
||||
Hardware::reboot();
|
||||
});
|
||||
QObject::connect(update_btn, &QPushButton::clicked, [=, &watcher]() {
|
||||
btn->setEnabled(false);
|
||||
update_btn->setEnabled(false);
|
||||
update_btn->setText(QObject::tr("Updating..."));
|
||||
const std::string git_branch = Params().get("GitBranch");
|
||||
const std::string git_remote = Params().get("GitRemote");
|
||||
const std::string to_home_dir = "cd /data/openpilot";
|
||||
const std::string check_remote = "git remote | grep origin-update";
|
||||
const std::string reset_remote = "git remote remove origin-update && git remote add origin-update " + git_remote;
|
||||
const std::string add_remote = "git remote add origin-update " + git_remote;
|
||||
const std::string fetch_remote = "git fetch origin-update " + git_branch;
|
||||
const std::string reset_branch = "git reset --hard origin-update/" + git_branch + " 2>&1";
|
||||
|
||||
std::string remote_cmd = add_remote;
|
||||
if (!std::system((to_home_dir + " && " + check_remote).c_str())) {
|
||||
remote_cmd = reset_remote;
|
||||
}
|
||||
const std::string cmd = to_home_dir + "; " + remote_cmd + "; " + fetch_remote + "; " + reset_branch;
|
||||
|
||||
QFuture<void> future = QtConcurrent::run([=]() {
|
||||
label->clear();
|
||||
std::string output = executeCommand(cmd.c_str());
|
||||
//LOGW("CHECK OUTPUT PLS\n%s", output.c_str());
|
||||
QMetaObject::invokeMethod(label, "setText", Qt::QueuedConnection,
|
||||
Q_ARG(QString, QString::fromStdString(output) + text));
|
||||
});
|
||||
QObject::connect(&watcher, &QFutureWatcher<void>::finished, [=]() {
|
||||
btn->setEnabled(true);
|
||||
update_btn->setEnabled(true);
|
||||
update_btn->setText(QObject::tr("Update"));
|
||||
});
|
||||
watcher.setFuture(future);
|
||||
});
|
||||
#else
|
||||
update_btn->setEnabled(false);
|
||||
btn->setText(QObject::tr("Exit"));
|
||||
QObject::connect(btn, &QPushButton::clicked, &a, &QApplication::quit);
|
||||
#endif
|
||||
main_layout->addWidget(btn, 0, 0, Qt::AlignRight | Qt::AlignBottom);
|
||||
main_layout->addWidget(update_btn, 0, 0, Qt::AlignLeft | Qt::AlignBottom);
|
||||
|
||||
window.setStyleSheet(R"(
|
||||
* {
|
||||
@@ -126,10 +58,6 @@ int main(int argc, char *argv[]) {
|
||||
border-radius: 20px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
color: #33FFFFFF;
|
||||
border: 2px solid #33FFFFFF;
|
||||
}
|
||||
)");
|
||||
|
||||
return a.exec();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user