mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-07 22:52:06 +08:00
Add HKG EV App Start Climate wake
Add a StarPilot vehicle toggle that selects alternate Panda firmware for Hyundai/Kia/Genesis CAN-FD EVs. The firmware keeps the HKG CAN bus active while Panda is in power save and treats the app climate-active frame, bus 1 address 0x384 with byte 3 nonzero, as a Panda boot wake source without publishing it as CAN ignition. Wire the toggle through StarPilot vehicle settings, Galaxy device settings, parameter definitions, and pandad firmware selection. Disabling the toggle selects the default Panda firmware again. Tested on a Kia EV9 and 2023 Kia EV6. EV9 remote climate active used 0x384 byte 3 equal to 0x01; EV6 remote climate active used 0x0a. Both stopped/off states observed byte 3 equal to 0x00. Toggle-off negative testing on EV9 saw the remote climate frame on CAN but pandaStates.ignitionCan stayed false. Toggle-on testing verified the active Panda signature matched panda_h7_hkg_remote.bin.signed. Follow-up testing changed the HKG path to wake-only after remote climate caused partial-car fingerprinting and Dashcam Mode; wake-only firmware was built, flashed, and verified on both devices.
This commit is contained in:
@@ -289,6 +289,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"FlashPanda", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||
{"GMDashSpoofOffsets", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"GMPedalLongitudinal", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||
{"HKGRemoteStartBootsComma", {PERSISTENT, BOOL, "0", "0"}},
|
||||
{"IgnoreIgnitionLine", {PERSISTENT, BOOL, "0", "0"}},
|
||||
{"LongPitch", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"RemoteStartBootsComma", {PERSISTENT, BOOL, "0", "0"}},
|
||||
|
||||
@@ -169,10 +169,14 @@ build_project("panda", base_project_f4, "./board/main.c", [])
|
||||
build_project("panda_h7", base_project_h7, "./board/main.c", [])
|
||||
build_project("panda_remote", base_project_f4, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9"])
|
||||
build_project("panda_h7_remote", base_project_h7, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9"])
|
||||
build_project("panda_hkg_remote", base_project_f4, "./board/main.c", ["-DPANDA_HKG_REMOTE_START"])
|
||||
build_project("panda_h7_hkg_remote", base_project_h7, "./board/main.c", ["-DPANDA_HKG_REMOTE_START"])
|
||||
build_project("panda_can_ignition_only", base_project_f4, "./board/main.c", ["-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_h7_can_ignition_only", base_project_h7, "./board/main.c", ["-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_remote_can_ignition_only", base_project_f4, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9", "-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_h7_remote_can_ignition_only", base_project_h7, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9", "-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_hkg_remote_can_ignition_only", base_project_f4, "./board/main.c", ["-DPANDA_HKG_REMOTE_START", "-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_h7_hkg_remote_can_ignition_only", base_project_h7, "./board/main.c", ["-DPANDA_HKG_REMOTE_START", "-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
|
||||
# panda jungle fw
|
||||
flags = [
|
||||
|
||||
@@ -10,6 +10,10 @@ can_health_t can_health[PANDA_CAN_CNT] = {{0}, {0}, {0}};
|
||||
// Ignition detected from CAN meessages
|
||||
bool ignition_can = false;
|
||||
uint32_t ignition_can_cnt = 0U;
|
||||
#ifdef PANDA_HKG_REMOTE_START
|
||||
bool hkg_remote_climate_wake = false;
|
||||
uint32_t hkg_remote_climate_wake_cnt = 0U;
|
||||
#endif
|
||||
|
||||
bool can_silent = true;
|
||||
bool can_loopback = false;
|
||||
@@ -161,9 +165,16 @@ void can_set_forwarding(uint8_t from, uint8_t to) {
|
||||
#endif
|
||||
|
||||
void ignition_can_hook(CANPacket_t *msg) {
|
||||
if (msg->bus == 0U) {
|
||||
int len = GET_LEN(msg);
|
||||
int len = GET_LEN(msg);
|
||||
|
||||
#ifdef PANDA_HKG_REMOTE_START
|
||||
if ((msg->bus == 1U) && (msg->addr == 0x384U) && (len == 8)) {
|
||||
hkg_remote_climate_wake = msg->data[3] != 0U;
|
||||
hkg_remote_climate_wake_cnt = 0U;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (msg->bus == 0U) {
|
||||
// GM exception
|
||||
// Remote-start mode uses 0xC9 bit 4 (SystemPowerMode=Run) for ignition detection.
|
||||
// Stock mode uses 0x1F1 bit 1 (SystemPowerMode=Run/Crank Request).
|
||||
|
||||
@@ -189,6 +189,9 @@ static void tick_handler(void) {
|
||||
|
||||
// tick drivers at 1Hz
|
||||
bool started = panda_ignition_line() || ignition_can;
|
||||
#ifdef PANDA_HKG_REMOTE_START
|
||||
started = started || hkg_remote_climate_wake;
|
||||
#endif
|
||||
bootkick_tick(started, recent_heartbeat);
|
||||
|
||||
// increase heartbeat counter and cap it at the uint32 limit
|
||||
@@ -267,11 +270,19 @@ static void tick_handler(void) {
|
||||
if (ignition_can_cnt > 2U) {
|
||||
ignition_can = false;
|
||||
}
|
||||
#ifdef PANDA_HKG_REMOTE_START
|
||||
if (hkg_remote_climate_wake_cnt > 2U) {
|
||||
hkg_remote_climate_wake = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// on to the next one
|
||||
uptime_cnt += 1U;
|
||||
safety_mode_cnt += 1U;
|
||||
ignition_can_cnt += 1U;
|
||||
#ifdef PANDA_HKG_REMOTE_START
|
||||
hkg_remote_climate_wake_cnt += 1U;
|
||||
#endif
|
||||
|
||||
// synchronous safety check
|
||||
safety_tick(¤t_safety_config);
|
||||
|
||||
@@ -9,7 +9,12 @@ void enable_can_transceivers(bool enabled) {
|
||||
// Leave main CAN always on for CAN-based ignition detection
|
||||
uint8_t main_bus = (harness.status == HARNESS_STATUS_FLIPPED) ? 3U : 1U;
|
||||
for(uint8_t i=1U; i<=4U; i++){
|
||||
current_board->enable_can_transceiver(i, (i == main_bus) || enabled);
|
||||
bool transceiver_enabled = (i == main_bus) || enabled;
|
||||
#ifdef PANDA_HKG_REMOTE_START
|
||||
uint8_t hkg_bus = (harness.status == HARNESS_STATUS_FLIPPED) ? 4U : 2U;
|
||||
transceiver_enabled = transceiver_enabled || (i == hkg_bus);
|
||||
#endif
|
||||
current_board->enable_can_transceiver(i, transceiver_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +31,9 @@ void set_power_save_state(int state) {
|
||||
} else {
|
||||
llcan_irq_disable(cans[2]);
|
||||
}
|
||||
#ifndef PANDA_HKG_REMOTE_START
|
||||
llcan_irq_disable(cans[1]);
|
||||
#endif
|
||||
} else {
|
||||
print("disable power savings\n");
|
||||
|
||||
|
||||
+22
-12
@@ -13,22 +13,24 @@ from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
|
||||
def get_selected_firmware_name(app_fn: str, remote_start: bool, ignore_ignition_line: bool) -> str:
|
||||
if not remote_start and not ignore_ignition_line:
|
||||
def get_selected_firmware_name(app_fn: str, remote_start: bool, hkg_remote_start: bool, ignore_ignition_line: bool) -> str:
|
||||
if not remote_start and not hkg_remote_start and not ignore_ignition_line:
|
||||
return app_fn
|
||||
|
||||
h7 = app_fn == "panda_h7.bin.signed"
|
||||
name_parts = ["panda_h7" if h7 else "panda"]
|
||||
if remote_start:
|
||||
if hkg_remote_start:
|
||||
name_parts.extend(["hkg", "remote"])
|
||||
elif remote_start:
|
||||
name_parts.append("remote")
|
||||
if ignore_ignition_line:
|
||||
name_parts.append("can_ignition_only")
|
||||
return "_".join(name_parts) + ".bin.signed"
|
||||
|
||||
|
||||
def get_expected_firmware_path(panda: Panda, remote_start: bool, ignore_ignition_line: bool) -> str:
|
||||
def get_expected_firmware_path(panda: Panda, remote_start: bool, hkg_remote_start: bool, ignore_ignition_line: bool) -> str:
|
||||
app_fn = panda.get_mcu_type().config.app_fn
|
||||
selected_fn = get_selected_firmware_name(app_fn, remote_start, ignore_ignition_line)
|
||||
selected_fn = get_selected_firmware_name(app_fn, remote_start, hkg_remote_start, ignore_ignition_line)
|
||||
if selected_fn != app_fn:
|
||||
selected_path = os.path.join(FW_PATH, selected_fn)
|
||||
if os.path.isfile(selected_path):
|
||||
@@ -37,9 +39,9 @@ def get_expected_firmware_path(panda: Panda, remote_start: bool, ignore_ignition
|
||||
return os.path.join(FW_PATH, app_fn)
|
||||
|
||||
|
||||
def get_expected_signature(panda: Panda, remote_start: bool, ignore_ignition_line: bool) -> bytes:
|
||||
def get_expected_signature(panda: Panda, remote_start: bool, hkg_remote_start: bool, ignore_ignition_line: bool) -> bytes:
|
||||
try:
|
||||
fn = get_expected_firmware_path(panda, remote_start, ignore_ignition_line)
|
||||
fn = get_expected_firmware_path(panda, remote_start, hkg_remote_start, ignore_ignition_line)
|
||||
return Panda.get_signature_from_firmware(fn)
|
||||
except Exception:
|
||||
cloudlog.exception("Error computing expected signature")
|
||||
@@ -53,6 +55,13 @@ def get_remote_start_boots_comma(params: Params) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def get_hkg_remote_start_boots_comma(params: Params) -> bool:
|
||||
try:
|
||||
return params.get_bool("HKGRemoteStartBootsComma")
|
||||
except UnknownKeyName:
|
||||
return False
|
||||
|
||||
|
||||
def get_ignore_ignition_line(params: Params) -> bool:
|
||||
try:
|
||||
return params.get_bool("IgnoreIgnitionLine")
|
||||
@@ -60,7 +69,7 @@ def get_ignore_ignition_line(params: Params) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def flash_panda(panda_serial: str, remote_start: bool, ignore_ignition_line: bool) -> Panda:
|
||||
def flash_panda(panda_serial: str, remote_start: bool, hkg_remote_start: bool, ignore_ignition_line: bool) -> Panda:
|
||||
try:
|
||||
panda = Panda(panda_serial)
|
||||
except PandaProtocolMismatch:
|
||||
@@ -68,8 +77,8 @@ def flash_panda(panda_serial: str, remote_start: bool, ignore_ignition_line: boo
|
||||
HARDWARE.recover_internal_panda()
|
||||
raise
|
||||
|
||||
fw_path = get_expected_firmware_path(panda, remote_start, ignore_ignition_line)
|
||||
fw_signature = get_expected_signature(panda, remote_start, ignore_ignition_line)
|
||||
fw_path = get_expected_firmware_path(panda, remote_start, hkg_remote_start, ignore_ignition_line)
|
||||
fw_signature = get_expected_signature(panda, remote_start, hkg_remote_start, ignore_ignition_line)
|
||||
internal_panda = panda.is_internal()
|
||||
|
||||
panda_version = "bootstub" if panda.bootstub else panda.get_version()
|
||||
@@ -153,9 +162,10 @@ def main() -> None:
|
||||
# Flash pandas
|
||||
pandas: list[Panda] = []
|
||||
remote_start = get_remote_start_boots_comma(params)
|
||||
hkg_remote_start = get_hkg_remote_start_boots_comma(params)
|
||||
ignore_ignition_line = get_ignore_ignition_line(params)
|
||||
for serial in panda_serials:
|
||||
pandas.append(flash_panda(serial, remote_start, ignore_ignition_line))
|
||||
pandas.append(flash_panda(serial, remote_start, hkg_remote_start, ignore_ignition_line))
|
||||
|
||||
# Ensure internal panda is present if expected
|
||||
internal_pandas = [panda for panda in pandas if panda.is_internal()]
|
||||
@@ -207,7 +217,7 @@ def main() -> None:
|
||||
first_run = False
|
||||
|
||||
# run pandad with all connected serials as arguments
|
||||
if get_remote_start_boots_comma(params) or get_ignore_ignition_line(params):
|
||||
if get_remote_start_boots_comma(params) or get_hkg_remote_start_boots_comma(params) or get_ignore_ignition_line(params):
|
||||
os.environ["BOARDD_SKIP_FW_CHECK"] = "1"
|
||||
else:
|
||||
os.environ.pop("BOARDD_SKIP_FW_CHECK", None)
|
||||
|
||||
@@ -209,6 +209,11 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
})
|
||||
|
||||
if cs.isHKGCanFd and cs.hasOpenpilotLongitudinal:
|
||||
toggles.append({
|
||||
"title": tr("EV Remote Climate"),
|
||||
"get_state": lambda: self._controller._params.get_bool("HKGRemoteStartBootsComma"),
|
||||
"set_state": lambda s: self._controller._on_panda_firmware_toggle("HKGRemoteStartBootsComma", tr("EV Remote Climate requires a Panda firmware update.")),
|
||||
})
|
||||
toggles.append({
|
||||
"title": tr("Nostalgia Mode"),
|
||||
"subtitle": tr("Use the left paddle to pause openpilot acceleration and braking."),
|
||||
|
||||
@@ -173,13 +173,15 @@ def extract_zip(zip_file, extract_path):
|
||||
print(f"Extraction completed!")
|
||||
|
||||
|
||||
def get_selected_panda_firmware_name(app_fn, remote_start, ignore_ignition_line):
|
||||
if not remote_start and not ignore_ignition_line:
|
||||
def get_selected_panda_firmware_name(app_fn, remote_start, hkg_remote_start, ignore_ignition_line):
|
||||
if not remote_start and not hkg_remote_start and not ignore_ignition_line:
|
||||
return app_fn
|
||||
|
||||
h7 = app_fn == "panda_h7.bin.signed"
|
||||
name_parts = ["panda_h7" if h7 else "panda"]
|
||||
if remote_start:
|
||||
if hkg_remote_start:
|
||||
name_parts.extend(["hkg", "remote"])
|
||||
elif remote_start:
|
||||
name_parts.append("remote")
|
||||
if ignore_ignition_line:
|
||||
name_parts.append("can_ignition_only")
|
||||
@@ -192,6 +194,10 @@ def flash_panda(params_memory):
|
||||
remote_start = params.get_bool("RemoteStartBootsComma")
|
||||
except Exception:
|
||||
remote_start = False
|
||||
try:
|
||||
hkg_remote_start = params.get_bool("HKGRemoteStartBootsComma")
|
||||
except Exception:
|
||||
hkg_remote_start = False
|
||||
try:
|
||||
ignore_ignition_line = params.get_bool("IgnoreIgnitionLine")
|
||||
except Exception:
|
||||
@@ -203,7 +209,7 @@ def flash_panda(params_memory):
|
||||
print(f"Flashing Panda {serial}")
|
||||
flash_fn = None
|
||||
app_fn = panda.get_mcu_type().config.app_fn
|
||||
selected_fn = get_selected_panda_firmware_name(app_fn, remote_start, ignore_ignition_line)
|
||||
selected_fn = get_selected_panda_firmware_name(app_fn, remote_start, hkg_remote_start, ignore_ignition_line)
|
||||
if selected_fn != app_fn:
|
||||
candidate = os.path.join(FW_PATH, selected_fn)
|
||||
if os.path.isfile(candidate):
|
||||
|
||||
@@ -1392,6 +1392,10 @@ class StarPilotVariables:
|
||||
condition=toggle.car_make == "gm" and toggle.has_pedal,
|
||||
)
|
||||
toggle.ignore_ignition_line = self.get_value("IgnoreIgnitionLine", condition=toggle.car_make == "gm")
|
||||
toggle.hkg_remote_start_boots_comma = self.get_value(
|
||||
"HKGRemoteStartBootsComma",
|
||||
condition=toggle.car_make == "hyundai" and toggle.openpilot_longitudinal and bool(CP.flags & HyundaiFlags.CANFD),
|
||||
)
|
||||
toggle.long_pitch = self.get_value(
|
||||
"LongPitch",
|
||||
condition=toggle.openpilot_longitudinal and toggle.car_make == "gm",
|
||||
|
||||
@@ -13,6 +13,7 @@ const FAVORITE_OPTION_COLLATOR = new Intl.Collator(undefined, { numeric: true, s
|
||||
let syncScheduled = false
|
||||
let lastParams = null
|
||||
const DYNAMIC_DEFAULT_DEP_KEYS = new Set(["AccelerationProfile", "EVTuning", "TruckTuning"])
|
||||
const PANDA_FIRMWARE_TOGGLE_KEYS = new Set(["HKGRemoteStartBootsComma"])
|
||||
|
||||
// Module-level state (persists across route changes)
|
||||
const state = reactive({
|
||||
@@ -574,7 +575,13 @@ function updateFavoriteFilter(index, event) {
|
||||
scheduleSyncInputs()
|
||||
}
|
||||
|
||||
async function updateFavoriteValue(key, checked) {
|
||||
async function updateFavoriteValue(key, checked, sourceEl = null) {
|
||||
if (!confirmPandaFirmwareToggle(key, checked)) {
|
||||
if (sourceEl) sourceEl.checked = !!state.values[key]
|
||||
scheduleSyncInputs()
|
||||
return
|
||||
}
|
||||
|
||||
const current = state.values[key]
|
||||
state.values = { ...state.values, [key]: checked }
|
||||
state.favoriteValues = { ...state.favoriteValues, [key]: checked }
|
||||
@@ -583,7 +590,7 @@ async function updateFavoriteValue(key, checked) {
|
||||
const res = await fetch("/api/params", {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ key, value: checked }),
|
||||
body: JSON.stringify({ key, value: checked, ...pandaFirmwareConfirmationPayload(key) }),
|
||||
})
|
||||
const data = await res.json()
|
||||
|
||||
@@ -673,6 +680,25 @@ function showParamSnackbar(message, level, timeout = 2200) {
|
||||
})
|
||||
}
|
||||
|
||||
function getParamDisplayLabel(key) {
|
||||
return state.paramMetaByKey[key]?.label || key
|
||||
}
|
||||
|
||||
function confirmPandaFirmwareToggle(key, enabled) {
|
||||
if (!PANDA_FIRMWARE_TOGGLE_KEYS.has(key)) return true
|
||||
|
||||
const label = getParamDisplayLabel(key)
|
||||
const action = enabled ? "Enable" : "Disable"
|
||||
return window.confirm(
|
||||
`${label} requires a Panda firmware update.\n\n` +
|
||||
`${action} ${label} and flash the Panda now?`
|
||||
)
|
||||
}
|
||||
|
||||
function pandaFirmwareConfirmationPayload(key) {
|
||||
return PANDA_FIRMWARE_TOGGLE_KEYS.has(key) ? { confirmedPandaFirmwareFlash: true } : {}
|
||||
}
|
||||
|
||||
function syncNumericDisplay(param, rawValue) {
|
||||
const displayEl = document.getElementById(`ds-display-${param.key}`)
|
||||
if (!displayEl) return
|
||||
@@ -831,11 +857,16 @@ async function updateParam(key, elType) {
|
||||
formattedVal = coerceValueByType(el.value, param.data_type)
|
||||
}
|
||||
|
||||
if (elType === "checkbox" && !confirmPandaFirmwareToggle(key, formattedVal)) {
|
||||
revertInput(key, current, elType)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch("/api/params", {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ key, value: formattedVal, label: selectedLabel }),
|
||||
body: JSON.stringify({ key, value: formattedVal, label: selectedLabel, ...pandaFirmwareConfirmationPayload(key) }),
|
||||
})
|
||||
const data = await res.json()
|
||||
|
||||
@@ -1025,7 +1056,7 @@ function renderFavoriteSlotsPanel() {
|
||||
class="ds-toggle ds-favorite-quick-toggle"
|
||||
data-favorite-value-key="${selectedKey}"
|
||||
checked="${() => selectedValue}"
|
||||
@change="${(e) => updateFavoriteValue(selectedKey, !!e.currentTarget.checked)}" />
|
||||
@change="${(e) => updateFavoriteValue(selectedKey, !!e.currentTarget.checked, e.currentTarget)}" />
|
||||
</label>
|
||||
`
|
||||
})}
|
||||
|
||||
@@ -2520,6 +2520,13 @@
|
||||
"data_type": "bool",
|
||||
"ui_type": "toggle"
|
||||
},
|
||||
{
|
||||
"key": "HKGRemoteStartBootsComma",
|
||||
"label": "EV Remote Climate",
|
||||
"description": "Use the remote-climate Hyundai/Kia/Genesis CAN-FD panda firmware at boot.\n\nRequired for EV remote-climate startup signal behavior.",
|
||||
"data_type": "bool",
|
||||
"ui_type": "toggle"
|
||||
},
|
||||
{
|
||||
"key": "VoltSNG",
|
||||
"label": "Stop-and-Go Hack",
|
||||
|
||||
@@ -113,6 +113,17 @@ _TESTING_GROUND_CUSTOM_RESERVED_INTERVAL_S = 15.0
|
||||
_TESTING_GROUND_CUSTOM_RESERVED_PM = None
|
||||
_TESTING_GROUND_CUSTOM_RESERVED_LOCK = threading.Lock()
|
||||
_TESTING_GROUND_CUSTOM_RESERVED_LAST_PUBLISH_MONO = 0.0
|
||||
PANDA_FIRMWARE_TOGGLE_KEYS = {"HKGRemoteStartBootsComma"}
|
||||
PANDA_FIRMWARE_CONFIRMATION_FIELD = "confirmedPandaFirmwareFlash"
|
||||
_PANDA_FLASH_REBOOT_LOCK = threading.Lock()
|
||||
|
||||
|
||||
def _flash_panda_then_reboot() -> None:
|
||||
with _PANDA_FLASH_REBOOT_LOCK:
|
||||
params_memory.put_bool("FlashPanda", True)
|
||||
while params_memory.get_bool("FlashPanda"):
|
||||
time.sleep(0.1)
|
||||
HARDWARE.reboot()
|
||||
|
||||
|
||||
def _is_comma_device_runtime() -> bool:
|
||||
@@ -3960,6 +3971,11 @@ def setup(app):
|
||||
if key == "AutomaticUpdates" and params.get_bool("IsOnroad"):
|
||||
return jsonify({"error": "Cannot change Automatic Updates while driving."}), 403
|
||||
|
||||
if key in PANDA_FIRMWARE_TOGGLE_KEYS and params.get_bool("IsOnroad"):
|
||||
return jsonify({"error": "Cannot flash Panda firmware while driving."}), 403
|
||||
if key in PANDA_FIRMWARE_TOGGLE_KEYS and data.get(PANDA_FIRMWARE_CONFIRMATION_FIELD) is not True:
|
||||
return jsonify({"error": "Panda firmware changes require confirmation before flashing."}), 409
|
||||
|
||||
if key == "AllowImpossibleAcceleration":
|
||||
enabled = str_val.strip() in ("1", "true", "True")
|
||||
params.put_bool(key, enabled)
|
||||
@@ -4186,6 +4202,9 @@ def setup(app):
|
||||
|
||||
response = {"message": f"Parameter '{key}' updated successfully."}
|
||||
updated = {}
|
||||
if key in PANDA_FIRMWARE_TOGGLE_KEYS:
|
||||
threading.Thread(target=_flash_panda_then_reboot, daemon=True).start()
|
||||
response["message"] = f"Parameter '{key}' updated successfully. Panda flashing started; device will reboot when finished."
|
||||
if key == "RemapCancelToDistance" and params.get_bool("RemapCancelToDistance"):
|
||||
updated["RemapCancelToDistance"] = True
|
||||
response["message"] = "Remap Cancel Button enabled."
|
||||
|
||||
@@ -155,16 +155,19 @@ StarPilotVehiclesPanel::StarPilotVehiclesPanel(StarPilotSettingsWindow *parent,
|
||||
settingsList->addItem(disableOpenpilotLong);
|
||||
|
||||
StarPilotListWidget *gmList = new StarPilotListWidget(this);
|
||||
StarPilotListWidget *hkgList = new StarPilotListWidget(this);
|
||||
StarPilotListWidget *subaruList = new StarPilotListWidget(this);
|
||||
StarPilotListWidget *toyotaList = new StarPilotListWidget(this);
|
||||
StarPilotListWidget *vehicleInfoList = new StarPilotListWidget(this);
|
||||
|
||||
ScrollView *gmPanel = new ScrollView(gmList, this);
|
||||
ScrollView *hkgPanel = new ScrollView(hkgList, this);
|
||||
ScrollView *subaruPanel = new ScrollView(subaruList, this);
|
||||
ScrollView *toyotaPanel = new ScrollView(toyotaList, this);
|
||||
ScrollView *vehicleInfoPanel = new ScrollView(vehicleInfoList, this);
|
||||
|
||||
vehiclesLayout->addWidget(gmPanel);
|
||||
vehiclesLayout->addWidget(hkgPanel);
|
||||
vehiclesLayout->addWidget(subaruPanel);
|
||||
vehiclesLayout->addWidget(toyotaPanel);
|
||||
vehiclesLayout->addWidget(vehicleInfoPanel);
|
||||
@@ -179,6 +182,8 @@ StarPilotVehiclesPanel::StarPilotVehiclesPanel(StarPilotSettingsWindow *parent,
|
||||
{"RemapCancelToDistance", tr("Remap Cancel Button"), tr("<b>On pedal-interceptor Bolts, treat the steering-wheel CANCEL button as an extra mappable button.</b>"), ""},
|
||||
{"VoltSNG", tr("Stop-and-Go Hack"), tr("<b>Force stop-and-go</b> on the 2017 Chevy Volt."), ""},
|
||||
|
||||
{"HKGToggles", tr("Hyundai/Kia/Genesis Settings"), tr("<b>StarPilot features for Hyundai/Kia/Genesis vehicles.</b>"), ""},
|
||||
{"HKGRemoteStartBootsComma", tr("EV Remote Climate"), tr("<b>Use the remote-climate Hyundai/Kia/Genesis CAN-FD panda firmware at boot.</b><br><br>Required for EV remote-climate startup signal behavior."), ""},
|
||||
|
||||
{"SubaruToggles", tr("Subaru Settings"), tr("<b>StarPilot features for Subaru vehicles.</b>"), ""},
|
||||
{"SubaruSNG", tr("Stop and Go"), tr("Stop and go for supported Subaru vehicles."), ""},
|
||||
@@ -212,6 +217,14 @@ StarPilotVehiclesPanel::StarPilotVehiclesPanel(StarPilotSettingsWindow *parent,
|
||||
});
|
||||
vehicleToggle = gmButton;
|
||||
|
||||
} else if (param == "HKGToggles") {
|
||||
ButtonControl *hkgButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(hkgButton, &ButtonControl::clicked, [vehiclesLayout, hkgPanel, this]() {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
vehiclesLayout->setCurrentWidget(hkgPanel);
|
||||
});
|
||||
vehicleToggle = hkgButton;
|
||||
|
||||
} else if (param == "SubaruToggles") {
|
||||
ButtonControl *subaruButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(subaruButton, &ButtonControl::clicked, [vehiclesLayout, subaruPanel, this]() {
|
||||
@@ -264,6 +277,8 @@ StarPilotVehiclesPanel::StarPilotVehiclesPanel(StarPilotSettingsWindow *parent,
|
||||
|
||||
if (gmKeys.contains(param)) {
|
||||
gmList->addItem(vehicleToggle);
|
||||
} else if (hkgKeys.contains(param)) {
|
||||
hkgList->addItem(vehicleToggle);
|
||||
} else if (subaruKeys.contains(param)) {
|
||||
subaruList->addItem(vehicleToggle);
|
||||
} else if (toyotaKeys.contains(param)) {
|
||||
@@ -322,6 +337,7 @@ StarPilotVehiclesPanel::StarPilotVehiclesPanel(StarPilotSettingsWindow *parent,
|
||||
};
|
||||
|
||||
connectPandaFlashToggle("IgnoreIgnitionLine", tr("CAN Ignition Only requires a Panda firmware update. Flash the Panda now?"));
|
||||
connectPandaFlashToggle("HKGRemoteStartBootsComma", tr("EV Remote Climate requires a Panda firmware update. Flash the Panda now?"));
|
||||
connectPandaFlashToggle("RemoteStartBootsComma", tr("Remote Start requires a Panda firmware update. Flash the Panda now?"));
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
@@ -393,6 +409,8 @@ void StarPilotVehiclesPanel::updateToggles() {
|
||||
if (!showAllToggles) {
|
||||
if (gmKeys.contains(key)) {
|
||||
setVisible &= parent->isGM;
|
||||
} else if (hkgKeys.contains(key)) {
|
||||
setVisible &= parent->isHKGCanFd && parent->hasOpenpilotLongitudinal;
|
||||
} else if (subaruKeys.contains(key)) {
|
||||
setVisible &= parent->isSubaru;
|
||||
} else if (toyotaKeys.contains(key)) {
|
||||
@@ -439,6 +457,8 @@ void StarPilotVehiclesPanel::updateToggles() {
|
||||
if (setVisible) {
|
||||
if (gmKeys.contains(key)) {
|
||||
toggles["GMToggles"]->setVisible(true);
|
||||
} else if (hkgKeys.contains(key)) {
|
||||
toggles["HKGToggles"]->setVisible(true);
|
||||
} else if (subaruKeys.contains(key)) {
|
||||
toggles["SubaruToggles"]->setVisible(true);
|
||||
} else if (toyotaKeys.contains(key)) {
|
||||
|
||||
@@ -24,6 +24,7 @@ private:
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
QSet<QString> gmKeys = {"GMPedalLongitudinal", "GMDashSpoofOffsets", "IgnoreIgnitionLine", "LongPitch", "RemoteStartBootsComma", "RemapCancelToDistance", "VoltSNG"};
|
||||
QSet<QString> hkgKeys = {"HKGRemoteStartBootsComma"};
|
||||
QSet<QString> longitudinalKeys = {"FrogsGoMoosTweak", "GMDashSpoofOffsets", "LongPitch", "RemapCancelToDistance", "SNGHack", "VoltSNG"};
|
||||
QSet<QString> subaruKeys = {"SubaruSNG", "SubaruSNGManualParkingBrake"};
|
||||
QSet<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
|
||||
|
||||
@@ -114,6 +114,7 @@ ForceTorqueController
|
||||
FrogsGoMoosTweak
|
||||
GMDashSpoofOffsets
|
||||
GMPedalLongitudinal
|
||||
HKGRemoteStartBootsComma
|
||||
IgnoreIgnitionLine
|
||||
GoatScream
|
||||
GoatScreamCriticalAlerts
|
||||
|
||||
Reference in New Issue
Block a user