IQ.Pilot Release Commit @ 67fd9c2

This commit is contained in:
IQ.Lvbs CI [bot]
2026-09-01 20:09:51 -05:00
parent f8f9335ba3
commit 4efaff4cb2
58 changed files with 494 additions and 92 deletions

View File

@@ -506,8 +506,8 @@
},
"python/_iqclosure/iqpilot/system/hardware/usb.py": {
"mode": 420,
"sha256": "7c2cd7c6d5a859fb8454059da1b36e3b5ce4639aca6fea296b4f91096b46c1ba",
"size": 7257
"sha256": "8c5b26f3967100ce0e5af7043a47a852fb5e8311f00ac95e7a263934c38e4ec0",
"size": 8069
},
"python/_iqclosure/iqpilot/system/micd.py": {
"mode": 420,
@@ -536,28 +536,28 @@
},
"python/iqpilot_private/emac/bulk_transport.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "2130f52658e9e6bbb2c3354b497c84a80fd29d0cd81c2c7d524ad31de56dc3f1",
"sha256": "f42a1bab373092b3010ca45b02d7ea7b27cd1e1e574c97f701129b2fad01f833",
"size": 333888
},
"python/iqpilot_private/emac/ffs_holder.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "4dea04cbb68903af8af7745b4691941d4dfd703e9b01bc238791d03d103192aa",
"size": 68072
"sha256": "306f0362e86558d33072f800b736fa71bfaf4ee5e4383c4e743b72b74724d2e3",
"size": 68064
},
"python/iqpilot_private/emac/mac_client.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "87db24c0c6c5cc200cadaaf0348a3f969da3a9fdc99c3fc9e7624b6664d4f895",
"size": 267952
"sha256": "31339f53f093c3877e13eac90a6647cbca2de92f339c47e5006a85bcd2e3656c",
"size": 267960
},
"python/iqpilot_private/emac/mac_protocol.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "1db2acc63c5538d47b336bb9703bcfbfa0de89f431d102fd727bb0c3e1a2248f",
"size": 203544
"sha256": "d5e855d1784a8ba66844639b871d2747ccce264c55359cf0e641ce7e3d66460d",
"size": 203512
},
"python/iqpilot_private/emac/maciqmodeld.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "a7a3ca084886882e8d61e3511a59c621bb44ff5e80a27ed6fcee36e9687d31d3",
"size": 333336
"sha256": "34d4ef1746143ea714f84f3c325e2ddaecec6a19c544fed68d8fc4080578c73f",
"size": 399040
},
"runtime": {
"entries": {
@@ -568,10 +568,10 @@
}
},
"signatures": {
"python/iqpilot_private/emac/bulk_transport.cpython-312-aarch64-linux-gnu.so": "ufSruB5sta4eGn6fuqxIp5v+uBkUTrot/V+Yf2kiZbrA3xcgOU2qG2AllwWDrn7Hg7a+eczvhJDHLzupuRZaAQ==",
"python/iqpilot_private/emac/ffs_holder.cpython-312-aarch64-linux-gnu.so": "G+hzeZYCDOph6YPDRVGbcWxojtJcBGjXcm6EPfUtfvYxvAu3QDjHXd+B3XdtOSekE/6AiH2CWURpDIwDqgZSBw==",
"python/iqpilot_private/emac/mac_client.cpython-312-aarch64-linux-gnu.so": "8byO3iMIYoPD9r9SoS1LcxekC+9vdQaFW9s+CZ4MIZmq6h9scsIHNCq3peh6tUcScj/WRFuES/bdZxTItHycAg==",
"python/iqpilot_private/emac/mac_protocol.cpython-312-aarch64-linux-gnu.so": "YYmTLXA024Dgu8zxXxfXMWIv/lmMvhuH1/C7aaNumZD/b5pkV6gihKomGlM7v/EnE8lYVtWo5wsnUCvl9a9BCQ==",
"python/iqpilot_private/emac/maciqmodeld.cpython-312-aarch64-linux-gnu.so": "f59Fh4UaquFHnDXTAmKdtOwc+++QN5MWi3Zx74L2qZgMLgk3T0/ouTb0WMSTbHgoWn61r+/g/2bH1//Y+NUeAw=="
"python/iqpilot_private/emac/bulk_transport.cpython-312-aarch64-linux-gnu.so": "7BtEAP11moL2lbQW5dYt1hDqJmDV1EuiEoSfJ0Tfislun2kS+/rwPiy7Ws8kjgrKLv+ZlXlWz6G5IBWk6z+aAw==",
"python/iqpilot_private/emac/ffs_holder.cpython-312-aarch64-linux-gnu.so": "Sv2riVgvm+4PDVTDLTuy1wpf15JObbP8hSAD4iiwF4RUs49GVGhulXkjzO28mLmF6tEuNDNWHRucxmuZrCKNAg==",
"python/iqpilot_private/emac/mac_client.cpython-312-aarch64-linux-gnu.so": "d4kaBPAEwe55BrQEVHWmxcVlEoQPsMVLOAYgpZVd6uiBnwWSUxl1X5nmqdKtxWSk8TFqU2xZkhfw4OOgG9JmDw==",
"python/iqpilot_private/emac/mac_protocol.cpython-312-aarch64-linux-gnu.so": "hvBkDKSMKjpxmRzhhGoRZT5WuOWLY+g3p2NIMlA7b6qYYpVaApoZNuquOerywEF1zJnwPiwpsg5QtQVe/5DfAA==",
"python/iqpilot_private/emac/maciqmodeld.cpython-312-aarch64-linux-gnu.so": "d3JAlH7P/X87II6iobeQ51melHy1vxdlXn0Nzo2DG65rcdVLM2B66YETPpwlX6Qv9NxhUlDcl/364CR+V+eyDQ=="
}
}

View File

@@ -1 +1 @@
OSV+ZbTBvP8stU4KDyT4wavo+fGUZEqcuvN7ltBw4LyMopdaMcbz9jYyIimicnQQniA1d4vaGuWRRQmvm0emAg==
KylnzVsK5XC3Jq1G7bBbKa5lv+oJSlfBpBsNpWMEEUgHDyOEj7+5EeeHDOgy8Lt4LEFgEeIV2WEJW0GJVpxUCQ==

View File

@@ -13,6 +13,7 @@ The USB eGPU dock is identified by VID/PID only. comma's internal codename for
it is deliberately not used here: IQ.Pilot runs these models on several
backends (eGPU dock, eMac), so the naming stays about the role, not the vendor.
"""
import subprocess
from pathlib import Path
# comma's USB eGPU dock, both shipped USB IDs. The ROM ids are the same board
@@ -124,6 +125,26 @@ def get_link_error_count(soc: Path = SOC_PLATFORM_PATH) -> int:
return sum(link_errors(c) for c in usb_controllers(soc))
def host_role_controller(soc: Path = SOC_PLATFORM_PATH, udc_root: Path = UDC_PATH) -> Path | None:
ctrl = link_controller(udc_root)
return (soc / ctrl / "mode") if ctrl else None
def ensure_host_role(mode_path: Path | None = None) -> bool:
"""A usbpd blip mid-drive can leave the Type-C controller in 'none'/'peripheral', and the
dock can never re-enumerate until something puts the port back into host mode."""
path = mode_path if mode_path is not None else host_role_controller()
if path is None:
return False
current = read(path)
if current == "host":
return True
if current is None:
return False
rc = subprocess.run(["sudo", "-n", "sh", "-c", f"echo host > {path}"], check=False, capture_output=True)
return rc.returncode == 0 and read(path) == "host"
def egpu_dock_present(root: Path = USB_DEVICES_PATH) -> bool:
"""A dock in ROM/bootloader state is deliberately NOT counted as present: it
enumerates but cannot serve a GPU until vendor firmware is flashed."""

View File

@@ -1 +0,0 @@
3184657cdc4d4fc1c69a924491f8a52466f10ec2

View File

@@ -186,7 +186,7 @@
},
"python/iqpilot_private/navd/__init__.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "9459a9e4551e5fd87cd98457a4cebcdd6f4763fc2ce03e13202011659289f8d3",
"sha256": "6e6de2f3270ad097c9b847fa10e833bac6b8eaab8ddad955603d163474a3c846",
"size": 67616
},
"python/iqpilot_private/navd/__init__.py": {
@@ -196,107 +196,122 @@
},
"python/iqpilot_private/navd/alpr_matcher.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "ea3451196fa13a2a8e2f9be7abff1b084308c856c52f001260f8340cc22e220f",
"sha256": "516370d0603f5134955826a3d8e9fea8ec0a9d27c116ad05af149a5c7ac15bcc",
"size": 269936
},
"python/iqpilot_private/navd/amap_client.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "96398bb3c989d670b641582e15bcd3ebc73f43f20b081dfaecd3d26fa81dc873",
"sha256": "dc8f27970c61a3b60c383ea69804896ee356d76c8bf7af5532a9338525fbc956",
"size": 202040
},
"python/iqpilot_private/navd/event_builder.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "bdd6cc139cdac78d3b6bf93e7930764bbd0538f24799b939fedd1e32f25c5266",
"sha256": "96eb02a86cab08d557f8df0adebd2cc72232b9348e9896acd9b71784a86b42d5",
"size": 136960
},
"python/iqpilot_private/navd/helpers.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "2df3400081a717f6ed6a819d3f5789ceda0707f89a6f6851dd77bd827b4721c6",
"sha256": "8fb8cc47f47971c530a68ccd81b9b5d9fc8ce82cdd1270967fa845399009e519",
"size": 135960
},
"python/iqpilot_private/navd/incident_feed.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "fe29e5f6eb290d17c7fab03e55db700772d9b6abc77e34954d952175a9a8dd45",
"size": 135528
"sha256": "b49f7ce7e9a33777ffa896a95fc4a5580988b4966d5a9330efd8c79a5116be91",
"size": 135584
},
"python/iqpilot_private/navd/iqmapd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "f6104209fc944accc4bca9d76598c14ea7bb32b5c06c6675c69ed71abbc18692",
"sha256": "747ae769bb35650dcd16b94a0a6260213373e352ede88bc1e57f114f27761d5a",
"size": 135632
},
"python/iqpilot_private/navd/long_decel.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "b9a69dc97ff120e5efc5a41b0e24d14d9b57a4e83faf4a2fb9c414cc5feae407",
"sha256": "eae425cd9bf60286fff4b980c6057351cb940f28981556269f05022258d80f0c",
"size": 69752
},
"python/iqpilot_private/navd/mapbox_client.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "c6e2f1e77e0ef71ddb7ae6178e3a22990b11b224b4b62e5db767e0f78d854402",
"sha256": "0fc4356fe57a11538e4a248dc803ceee61781d7c700640f78241a2d57cbb4574",
"size": 68144
},
"python/iqpilot_private/navd/nav_cameras.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "fcabb4944766db54e4ef13849886339b352f9604b620b93e7b09bbddc5172a58",
"sha256": "92521da14a5bf334324f32315b13773d37d5f7d209d4bad6d62afc12ab5d1705",
"size": 203056
},
"python/iqpilot_private/navd/nav_turn_signals.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "f95c6ae94b726d5c6634a0867e60cb433fcf41a07270512ee02ae422f580fb2a",
"sha256": "67454e461abb76c7a3053a7f728baa0beb30fba235639a0a2a927a9c80443a4a",
"size": 135560
},
"python/iqpilot_private/navd/navd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "4b04550554f61540c72d7657d172e699f17535faaf29b8223f6640eb71a9c0dc",
"size": 797328
"sha256": "9e0d5e929bfcd960fdba11804d1f70848ba40a68a65093c025a6d48171d0b2cc",
"size": 797392
},
"python/iqpilot_private/navd/navincidentd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "9a51d7c696a819e5ba47ba552bd1e7d21c28cdcb91fc9e0c22eb4b8d7c6d37e8",
"sha256": "33d40decd32e8cfe3f9a267ebfccf48e8bfc67bf9609206ef230a9566bf5581d",
"size": 135344
},
"python/iqpilot_private/navd/navrenderd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "fd120500f581eb408700c1c43dc6789b0391041b7a1b4341ee9352e5edeb1cf1",
"sha256": "edf0d16511686ed3d4d7d6bf2b6b44fd8d484af348dab0eb415999656eb1d0af",
"size": 135584
},
"python/iqpilot_private/navd/osm_cameras.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "89ca86442a4cad9c79046c6a7d5a96dd65c352829b6234e41d131997e27ef28b",
"sha256": "b11bec6f1b49f169f218a87467781b6d62d64c367e0c3df5356341adce8c3f6b",
"size": 202384
},
"python/iqpilot_private/navd/reroute.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "8850331bcad9b7d708cb5cabff7c80364ed75b4dd000f1f3cca0098fb02bc5a7",
"sha256": "d38218a6787234730ed39bdb04c00ab0778b1b56eefcedcb9ecfb31346d36378",
"size": 136216
},
"python/iqpilot_private/navd/road_incidents.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "9faab3cc244eeba8dfae46b6ec57f4e8d9d03ca0c465b5ce2da836f1988aa0f6",
"sha256": "f89f69e128b02eebc31b4c3702d62e12747f837863ad390026ea5004e506ea7c",
"size": 203136
},
"python/iqpilot_private/navd/route_manager.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "92e599dc73871b128be19c80057f983423023d7e2e3f9589ee8fe3c308ef2297",
"size": 877864
"sha256": "311926ffa2b4474320411240e6656ee676ce8b61d1cea444c34cd9520113a6a6",
"size": 943640
},
"python/iqpilot_private/navd/runtime_common.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "e24efc1da92e76a996549c22d8c56708e8713193be36c6365868de29be9a0276",
"sha256": "dc08b2e6bf7be3fe0b4a7ccdfceab6c434317e7626efd9b40ea5bf15739647ba",
"size": 135760
},
"python/iqpilot_private/navd/traffic.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "b97fae21d32dee6f240b79e3090c94f06e0328b8bf511b869667e56a23836901",
"sha256": "f47146eddd7c8b499359d411150533c0e28e80851096d076ee8552a4d45175d9",
"size": 69720
},
"python/iqpilot_private/navd/traffic_sources.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "98845f8be1fd44009acf88fe685f6985ffb996d5d508858bdbb3edd2984a5146",
"size": 135968
},
"python/iqpilot_private/navd/traffic_writer.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "15aba494968b9673987d2d0168d797bfbd307046555cb89efa2378acc8bb042a",
"size": 136936
},
"python/iqpilot_private/navd/turn_desire.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "822c67671b249a96bb5de1a83bd7c047ffb780bd252c62791a25a0ea7c2101fc",
"sha256": "715f94a985599a983750affa5bf36e1fc2e6502871f1af7de553f9aaf29028cb",
"size": 69768
},
"python/iqpilot_private/navd/valhalla_process.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "2658d1a9f08f49e1294a3c26be733170ac7943970a79ee2969d9404cd4b55758",
"size": 204072
},
"python/iqpilot_private/navd/web_server.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "2c1c671d8d933d6896387894fe62b213b99b9d75085b54c61806e2bb7d381d7b",
"sha256": "d03bf4d8d7d1547c5fcd085dea2ff78f8071e04e51e7f4d002f7ba23b431038e",
"size": 201400
},
"runtime": {
@@ -336,27 +351,30 @@
}
},
"signatures": {
"python/iqpilot_private/navd/__init__.cpython-312-aarch64-linux-gnu.so": "lg9M4QXLrh1ynX/Hev+0FAPnbN9mDoqv8diic0U+aYqjLMgkW+wHcB4r78J8oTrpDC+vF1wWztWj3cQOx98NCw==",
"python/iqpilot_private/navd/alpr_matcher.cpython-312-aarch64-linux-gnu.so": "DGacFfOsQ9paqF8ytUgX572A/wPOZi7rJefAl9vydnAFbQv5NL+c9ot5YDGI1s4mXs/SHPbn0WtTOOU2aS/hDQ==",
"python/iqpilot_private/navd/amap_client.cpython-312-aarch64-linux-gnu.so": "r0vM+nE7A00o362Oj745OQzat76z889uBd/niFp18Qds4P1Wpvynd1ctrbOlo9H1yESeC09NuP/Qw4k1pvt1Cg==",
"python/iqpilot_private/navd/event_builder.cpython-312-aarch64-linux-gnu.so": "JkfNSqU9uM4oZqxteomIbPo6abywxUzzdBx5B2myJNtUjGW5bHEii2D2DAUKuO+gd7x+6+IwgPwSOJJyN+QYBQ==",
"python/iqpilot_private/navd/helpers.cpython-312-aarch64-linux-gnu.so": "/CNm/bxjvo/IgjjDTde0p8c1Gl6I54dSwiSS0sEVUcrTRP3Y31S0dh8dnBqn1VTH3PIGlUDBF7EmTavXUOAfDg==",
"python/iqpilot_private/navd/incident_feed.cpython-312-aarch64-linux-gnu.so": "3IB5k4NEsFoKHckxlqoOZVXBAyVhYkVWRCvRdBnH4H+8udEuW5EpRXHv0rxtqBAs82ozbpOcZ7QjtfFgQPbXCQ==",
"python/iqpilot_private/navd/iqmapd.cpython-312-aarch64-linux-gnu.so": "Dp4PpzIqDJ5ySg1lIi0b5V49g7U2aOx1T+SeKGGKhOaEcCLnUEAd2EilrXt2luq8Xj+nnHWbMrZUho0KV7MfBQ==",
"python/iqpilot_private/navd/long_decel.cpython-312-aarch64-linux-gnu.so": "z87MDJLWKyqWqsXzTnoxjNfjkPxi6W0wsUt+Cafw5QWHMB6jGkJ1ZedYeS83qqdaxZGR3OaBdKohMSi9JKQHDA==",
"python/iqpilot_private/navd/mapbox_client.cpython-312-aarch64-linux-gnu.so": "FtOYM9RJA3LudYiGW9h4+EO94TqJVV4/hhEb9DOIL3hrbJYMWCctCTfo70UmgL+v8+8MSCyHgL3KBqPsW58gCg==",
"python/iqpilot_private/navd/nav_cameras.cpython-312-aarch64-linux-gnu.so": "XfkYcx/mj7TT57RjfAdlleSW5kgdGkLYt0h+SpJV+UdQeb+NTVHYa3+PgglT1KP8WjO5Tbyr6i5V4pq4ZwbhCQ==",
"python/iqpilot_private/navd/nav_turn_signals.cpython-312-aarch64-linux-gnu.so": "GGhf7FRjRzg9uLp4ClSosUUXJk+ocH4NETh8wetaqTkXev1smeJCd2OWbTqgWmlGRfjLqsnXzpv+bxBIKishAw==",
"python/iqpilot_private/navd/navd.cpython-312-aarch64-linux-gnu.so": "YwIAOpt1komu3aFiqx1uhCJFpFZ/tCub2RNrJMyh8RS7SI0ySxmiQ9MXMyuXt5Gxnt9ReGmxVSKo7x3UDsuCCg==",
"python/iqpilot_private/navd/navincidentd.cpython-312-aarch64-linux-gnu.so": "2agJVQwkglB5XE1acDWp+u/ZzwP0qJcEklPATDv4jez1KkftYqQb47J1/iGSxOtwh9NuXe//MNg+EEmwSlzvAQ==",
"python/iqpilot_private/navd/navrenderd.cpython-312-aarch64-linux-gnu.so": "G2ccii+ezg3lFQcNXI15EMVXWpszZlJJ4dy+nylF0OLEWWKRGFofb+vq4fYfwrJXmbn4nK9F+286nt4Q81WQAQ==",
"python/iqpilot_private/navd/osm_cameras.cpython-312-aarch64-linux-gnu.so": "+zTVSWeyZBkJFOC95QdK0LGd0EzLBZVB/GbKd3RiMsiQw83oAwNomLWs3SbsUhRBCZyGF56n2TQXEZQWjknaCg==",
"python/iqpilot_private/navd/reroute.cpython-312-aarch64-linux-gnu.so": "V+CQv3lqojsqJ/1gJJCuaR94ncCkRX4fT0iD+mxvJNmTLBGvw90hKl9v6IgtUvCOhqnHo2nJf30iH07C8R7iBA==",
"python/iqpilot_private/navd/road_incidents.cpython-312-aarch64-linux-gnu.so": "y5v5qBwMoKEvcYxjEy5tOwEB2BXaCAKIaKEBQKUuUfZpEZw7IpvPDGZbD5P5f1j05EJBde6jV9XbPB1mHIiHCg==",
"python/iqpilot_private/navd/route_manager.cpython-312-aarch64-linux-gnu.so": "BIpSZfiTIaOZucyCX3pGiAtNAtRIg8WNQyfaMqnMEy52Ttowb1NheURl/qn11wqKaKeQN5+wgDmTwIkx3Eu6CQ==",
"python/iqpilot_private/navd/runtime_common.cpython-312-aarch64-linux-gnu.so": "pyRMyI5u6/IG5LKIgCuZf4rcquMN19P8M2rcmr+yjnfO50o8SRT18+iklNXj0VY96LKMyQx/ejV7y7Jgt+qnDw==",
"python/iqpilot_private/navd/traffic.cpython-312-aarch64-linux-gnu.so": "MVSL4IXTQ8SFa6zDY5Y/QWN5yhcFBx6LaujCzLJQfALs0bYb7jyy7XVbxlyQshpOy4n151YggEBhuNSCGHSaCA==",
"python/iqpilot_private/navd/turn_desire.cpython-312-aarch64-linux-gnu.so": "A6QTQvEit2o797TrW2PuahnLODdACAAIahBw3UWtOTKHhD+vQaXke0yvxBcgVxgaBJLfpIz8SjKaZuEeIPphDg==",
"python/iqpilot_private/navd/web_server.cpython-312-aarch64-linux-gnu.so": "Qe32cW7+K4rQR6eRvi9vM8BZta5mPsK/xo9/dF4IZnfPYTP0bHzBFXZjsO4LVntwY/bUwMagp4fnRgXxwhNFCw=="
"python/iqpilot_private/navd/__init__.cpython-312-aarch64-linux-gnu.so": "9i3/SfFfCLGyTzyQQYpsSxbA3ASc1OSK7fCYXpIiIMnX+jKB288Qy7TzJnr3uINt+LhRW1wwnMI6hWBXjgv5AA==",
"python/iqpilot_private/navd/alpr_matcher.cpython-312-aarch64-linux-gnu.so": "5K4w4dDRtts8QvxBAXL0qrYofb/bg9PV/rKn/GrVmtAVDMd0DhAiKAugoxkhl8n4JviFY8ZmsHwWBrQPIMdkAA==",
"python/iqpilot_private/navd/amap_client.cpython-312-aarch64-linux-gnu.so": "X+hzm32FyMwE9fSIaGZH/GQqHn78izqrX8o1FdATb0Fg4+62tcgI9LHe9PIM8VY6+IaryaWyKqFtATaq6BZrDw==",
"python/iqpilot_private/navd/event_builder.cpython-312-aarch64-linux-gnu.so": "dQnA8CCeRMXqiARr/Kzf2x736DuaT1/ALC8ZLDZep2/nY2IJ7StZeZ8DwOBuRPRK8KJ5HNU424QMZkVzQcDnBg==",
"python/iqpilot_private/navd/helpers.cpython-312-aarch64-linux-gnu.so": "tdLykhS2t9M7R115Rse80M2Urg/8sNQTLaOz3YFyUTTkEzpaBlk3JnbgOQVpzDjrPB7y22y6mNORCkYI3cKfCw==",
"python/iqpilot_private/navd/incident_feed.cpython-312-aarch64-linux-gnu.so": "MJ/i1ZvGb3bYBVxKvT/zBk43CM/XT37GZa6la52Tfmqp9mrx6oz98PpvLZMgJ+18J4lSdMf2uGuJ2IHx5wWTAQ==",
"python/iqpilot_private/navd/iqmapd.cpython-312-aarch64-linux-gnu.so": "+ULQz9iDSDBtYRYSVVWz63TImB3DizGV2oFER6pmNttfJ6vA4SBVToxKV1YjHAebdMiSrTBrEkgPd5K4unE0Bg==",
"python/iqpilot_private/navd/long_decel.cpython-312-aarch64-linux-gnu.so": "PB+q882Oo/cOi+fN0IahlaBP7xEQrjF7BykAnCsxrnK8zJGkFZdrVUcLCS4T5DYjXhwlXbdveb3ZHdG/LoMcBQ==",
"python/iqpilot_private/navd/mapbox_client.cpython-312-aarch64-linux-gnu.so": "vqQRU0t5AS/oUs1JWxZlwHC5mrpaaHD10jgQCLzDGUL4Yv1aFHWAoM6KfFdUldmdSG1d4e6VGu+Y2bMdBIwAAw==",
"python/iqpilot_private/navd/nav_cameras.cpython-312-aarch64-linux-gnu.so": "OfuUD6/swlx5ggtvLfUVjGqpJbZWf+Ezwia5fE81FXA6RcuR4SMx1t/D38+TaMKDGvaBV31s08TJgh+/hXiiDA==",
"python/iqpilot_private/navd/nav_turn_signals.cpython-312-aarch64-linux-gnu.so": "WQOzntcyeraddagnvnxAwH/ciLFMztjfEhg07HFHy+++XJPCSGctdaxlgPWX6xq9kiE7aEkcTsW2CwOwYo3tDw==",
"python/iqpilot_private/navd/navd.cpython-312-aarch64-linux-gnu.so": "5c68ZgFSkAXf9m32zKbBDSNHF0rVTwZPVu0puTiIcM7laHyHVtkQJduq6g4SUm+wz634nLK2u5pggaNf+mkhAw==",
"python/iqpilot_private/navd/navincidentd.cpython-312-aarch64-linux-gnu.so": "LBV8K1SPj+bN8idsPR/3B24grXQYRNarYsCUbVaRdkfORuib70gRlGz4KtyOyYT/vpCU4iuDhnSRsd4ltH4RAg==",
"python/iqpilot_private/navd/navrenderd.cpython-312-aarch64-linux-gnu.so": "ZT4bVD2W2w9w2AdbKkZ7AgfQv+zqTmJH5126ngiDDRFFuW2Bnp+E/4M+6U912uGZsV5xayCw8QmJbM9EeSqgDQ==",
"python/iqpilot_private/navd/osm_cameras.cpython-312-aarch64-linux-gnu.so": "jjmBJtLWRVkPsO4n7/N/pDVD9jrC4SCMm0lIT/P8HCzsMhIIAkXhRAMGKdl1kYDxK8VMGRMMF7eoiCKEFPq2AA==",
"python/iqpilot_private/navd/reroute.cpython-312-aarch64-linux-gnu.so": "A0FeGUh384rTKZJLOL6wNdX3bLTTsmUX7kF3ysax7WjnyUSlctbms15E+3Ww87qmXwjMGbyPdlTdsnhvpcstAA==",
"python/iqpilot_private/navd/road_incidents.cpython-312-aarch64-linux-gnu.so": "J/I+XcODFE7LKvtyImt/Dw8fh2uvQeEhZ1IWx2IHZPH8sXhuVGVQIECVFGQJGfsckjzoUpgZq8AYNReRF62sBw==",
"python/iqpilot_private/navd/route_manager.cpython-312-aarch64-linux-gnu.so": "n/RFD32mlinaYGrWvKWGv8ziTTSFP8+qCS/I1ibFXRYU6gtwx/+03eUR+p2jh5hzPteo5RxLUfHDwxFvJMJzDA==",
"python/iqpilot_private/navd/runtime_common.cpython-312-aarch64-linux-gnu.so": "/5mYKn9um2aBLipkFsEptfM3sOId3SKkV8AHXGslWdH9Evp2ll8XENvirAX5tV1X35WslGYIybK3Xv3cZ4o8DQ==",
"python/iqpilot_private/navd/traffic.cpython-312-aarch64-linux-gnu.so": "kfl1Mm7G3CguQGtUvDutvbd4StDnKr0pW7ojLn6gydVTyxEiD/VAEFfTKBK/CAyUcw3eeX5+U8Qq2+6o0zEUBA==",
"python/iqpilot_private/navd/traffic_sources.cpython-312-aarch64-linux-gnu.so": "SzicVJ2/F8aMjcOHVCmEeJ952a+JPL8NLI6wsVkA2f5xiOSKMdynvcf7EgvrvBA4bgTRUGOmtpoqzMiCcNh2AA==",
"python/iqpilot_private/navd/traffic_writer.cpython-312-aarch64-linux-gnu.so": "tMmnyV9knGA0eoRq1+bYLaQRAmLLrpSC9KraH9iNWMgleg+xdY3dIpx+uyP77de/oOQ2Bovsp3Vq2MobcDACCQ==",
"python/iqpilot_private/navd/turn_desire.cpython-312-aarch64-linux-gnu.so": "kFb5U48pTMYRWee+JbH6CbOpE2je60Xk5ntJZIUCw66KWLTOUGFtQqMcUUcQ1b2/3xnCz7sb3Yt0GdbyyspMDg==",
"python/iqpilot_private/navd/valhalla_process.cpython-312-aarch64-linux-gnu.so": "u6o5lRGFT3PA7XPM0IXyr7iEsngyLKqh+kJhHNW7U7+iTI3hH25ag73YFQjnCfIuzPk2NtB4v2JKqcqBaNaQAQ==",
"python/iqpilot_private/navd/web_server.cpython-312-aarch64-linux-gnu.so": "4AB7oakyIWLG7OFuGpO+SidZnJzq3rC7/uWemSbhFVn9oOZBMQZ5IWN5Y3WfImyqoZXjZVGqxE9Yf0d8gmWdDA=="
}
}

View File

@@ -1 +1 @@
Fhs5w4K9yXGTe1Y9xpYpVEnHRHUsq4pJ0opKgllTGam0njHeskbHsYQmlj3n94vPeCJhQw52x9Bd1S2/R37WAg==
NH/aexXGu1jWh6ks/x7lbVEUX9VZPhETrwkIozXSjmPR2isUyVlaZppveq23NB7BeIQTJuS/+KAuZ/pbL/kaDQ==

View File

@@ -129,6 +129,8 @@ class CarInterface(CarInterfaceBase):
car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release_iq: bool, docs: bool) -> structs.IQCarParams:
if candidate in UNSUPPORTED_DSU_CAR:
ret.iqSafetyFlags |= ToyotaSafetyFlagsIQ.UNSUPPORTED_DSU
if candidate in TSS2_CAR:
ret.iqSafetyFlags |= ToyotaSafetyFlagsIQ.LKAS_HUD
# Detect smartDSU, which intercepts ACC_CMD from the DSU (or radar) allowing openpilot to send it
# 0x2AA is sent by a similar device which intercepts the radar instead of DSU on NO_DSU_CARs

View File

@@ -1,7 +1,7 @@
from iqdbc.car import gen_empty_fingerprint, structs
from iqdbc.car.toyota.interface import CarInterface
from iqdbc.car.toyota.values import CAR, ToyotaFlags
from iqdbc.lvbs.car.toyota.values import ToyotaFlagsIQ
from iqdbc.lvbs.car.toyota.values import ToyotaFlagsIQ, ToyotaSafetyFlagsIQ
def test_secoc_toyota_not_dashcam_on_release():
@@ -34,3 +34,11 @@ def test_smart_dsu_clears_disable_radar_on_radar_acc_toyota():
assert not (cp.flags & ToyotaFlags.DISABLE_RADAR.value)
assert cp.alphaLongitudinalAvailable
assert cp.openpilotLongitudinalControl
def test_lkas_hud_safety_flag_tracks_tss2():
for candidate, expected in ((CAR.TOYOTA_CHR_TSS2, True), (CAR.TOYOTA_PRIUS_V, False)):
fingerprint = gen_empty_fingerprint()
cp = CarInterface.get_params(candidate, fingerprint, [], False, False, False)
cp_iq = CarInterface.get_params_iq(cp, candidate, fingerprint, [], False, False, False)
assert bool(cp_iq.iqSafetyFlags & ToyotaSafetyFlagsIQ.LKAS_HUD) is expected

View File

@@ -679,7 +679,7 @@ class CarState(CarStateBase):
if self.CP.carFingerprint == CAR.PORSCHE_MACAN_MK1:
ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["Getriebe_03"]["GE_Waehlhebel"], None))
elif self.CP.transmissionType == TransmissionType.manual:
reverse = bool(pt_cp.vl["Gateway_05"]["BCM1_Rueckfahrlicht_Schalter"])
reverse = bool(br_cp.vl["Gateway_05"]["BCM1_Rueckfahrlicht_Schalter"])
ret.gearShifter = GearShifter.reverse if reverse else GearShifter.drive
else:
ret.gearShifter = GearShifter.drive

View File

@@ -8,7 +8,7 @@ from iqdbc.car.volkswagen.carcontroller import CarController
from iqdbc.car.volkswagen.carstate import CarState
from iqdbc.car.volkswagen.values import (
CAR, CanBus, DashcamOnlyReason, MLB_ACC_COORDINATOR_MSGS, MLB_GEARBOX_MSGS, MLB_MSG_ACC_10,
MLB_MSG_LH_EPS_03, NetworkLocation, RADAR_DISABLE_STATE, TransmissionType,
MLB_MSG_GATEWAY_05, MLB_MSG_LH_EPS_03, NetworkLocation, RADAR_DISABLE_STATE, TransmissionType,
VolkswagenFlags, VolkswagenSafetyFlags, VolkswagenFlagsIQ, get_longitudinal_stopping_speed_override,
)
from iqdbc.car.volkswagen.radar_interface import RadarInterface
@@ -115,7 +115,11 @@ class CarInterface(CarInterfaceBase):
if fingerprinted and MLB_MSG_LH_EPS_03 not in pt_msgs:
ret.flags |= VolkswagenFlagsIQ.IQ_MLB_NO_HCA_EPS.value
if fingerprinted and not any(msg in pt_msgs for msg in MLB_GEARBOX_MSGS):
all_msgs = ecan_msgs | fingerprint[1]
gearbox_seen = any(msg in all_msgs for msg in MLB_GEARBOX_MSGS)
transmission_ecu = any(fw.ecu == structs.CarParams.Ecu.transmission for fw in car_fw)
reverse_switch_seen = MLB_MSG_GATEWAY_05 in fingerprint[1]
if fingerprinted and not gearbox_seen and not transmission_ecu and reverse_switch_seen:
ret.transmissionType = TransmissionType.manual
elif ret.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):

View File

@@ -9,9 +9,9 @@ from iqdbc.car import Bus, DT_CTRL, structs
from iqdbc.car.volkswagen.carstate import CarState
from iqdbc.car.structs import CarParams
from iqdbc.car.volkswagen.interface import CarInterface
from iqdbc.car.volkswagen.values import (CAR, FW_QUERY_CONFIG, MLB_ACC_COORDINATOR_MSGS, MLB_MSG_ACC_10,
MLB_MSG_LH_EPS_03, WMI, VolkswagenFlags, VolkswagenFlagsIQ,
VolkswagenSafetyFlags)
from iqdbc.car.volkswagen.values import (CAR, FW_QUERY_CONFIG, MLB_ACC_COORDINATOR_MSGS, MLB_GEARBOX_MSGS, MLB_MSG_ACC_10,
MLB_MSG_GATEWAY_05, MLB_MSG_GETRIEBE_01, MLB_MSG_LH_EPS_03, WMI, VolkswagenFlags,
VolkswagenFlagsIQ, VolkswagenSafetyFlags)
from iqdbc.car.volkswagen.fingerprints import FW_VERSIONS
Ecu = CarParams.Ecu
@@ -333,6 +333,58 @@ def test_mlb_manual_gear_follows_the_reverse_light_switch():
assert _run(a4, lambda: _a4_mk4_frames(packer, reverse=False)).gearShifter == structs.CarState.GearShifter.drive
def _q5_params(bus0, bus1=(), car_fw=()):
fingerprints = _mlb_fingerprint(0, bus0)
fingerprints[1] = {msg: 8 for msg in bus1}
fingerprints[2] = {msg: 8 for msg in MLB_ECAN_CAMERA}
return CarInterface.get_params(CAR.AUDI_Q5_MK1, fingerprints, list(car_fw), alpha_long=False, is_release=False, docs=False)
MLB_ECAN_GATEWAY_NO_GEARBOX = tuple(msg for msg in MLB_ECAN_GATEWAY if msg not in MLB_GEARBOX_MSGS)
def test_mlb_gearbox_on_the_powertrain_bus_keeps_automatic():
params = _q5_params(MLB_ECAN_GATEWAY_NO_GEARBOX, bus1=(MLB_MSG_GETRIEBE_01, MLB_MSG_GATEWAY_05))
assert params.transmissionType == CarParams.TransmissionType.automatic
def test_mlb_transmission_ecu_firmware_keeps_automatic():
transmission = CarParams.CarFw.new_message(ecu=Ecu.transmission, address=0x7e1)
params = _q5_params(MLB_ECAN_GATEWAY_NO_GEARBOX, bus1=(MLB_MSG_GATEWAY_05,), car_fw=(transmission,))
assert params.transmissionType == CarParams.TransmissionType.automatic
def test_mlb_reverse_switch_on_the_extended_can_alone_keeps_automatic():
params = _q5_params(MLB_ECAN_GATEWAY_NO_GEARBOX + (MLB_MSG_GATEWAY_05,))
assert params.transmissionType == CarParams.TransmissionType.automatic
def test_mlb_manual_needs_no_gearbox_anywhere_and_a_reverse_switch_on_the_powertrain_bus():
params = _q5_params(MLB_ECAN_GATEWAY_NO_GEARBOX, bus1=(MLB_MSG_GATEWAY_05,))
assert params.transmissionType == CarParams.TransmissionType.manual
def test_mlb_manual_gateway_car_reads_reverse_from_the_powertrain_bus():
fingerprints = _mlb_fingerprint(0, MLB_ECAN_GATEWAY_NO_GEARBOX)
fingerprints[1] = {MLB_MSG_GATEWAY_05: 8}
fingerprints[2] = {msg: 8 for msg in MLB_ECAN_CAMERA}
q5 = _build_mlb_car(CAR.AUDI_Q5_MK1, fingerprints)
assert q5.CP.transmissionType == CarParams.TransmissionType.manual
packer = CANPacker("vw_mlb")
frames = lambda reverse: [packer.make_can_msg("Gateway_05", 1, {"BCM1_Rueckfahrlicht_Schalter": int(reverse)})]
assert _run(q5, lambda: frames(True)).gearShifter == structs.CarState.GearShifter.reverse
assert _run(q5, lambda: frames(False)).gearShifter == structs.CarState.GearShifter.drive
assert MLB_MSG_GATEWAY_05 not in q5.can_parsers[Bus.pt].addresses
def test_mlb_automatic_never_subscribes_gateway_05():
q5 = _q5_mk1_car()
q5.update([(int(DT_CTRL * 1e9), [])])
assert MLB_MSG_GATEWAY_05 not in q5.can_parsers[Bus.pt].addresses
assert MLB_MSG_GATEWAY_05 not in q5.can_parsers[Bus.aux].addresses
@pytest.mark.parametrize("button_type", (
structs.CarState.ButtonEvent.Type.setCruise,
structs.CarState.ButtonEvent.Type.resumeCruise,

View File

@@ -348,6 +348,7 @@ MLB_MSG_ACC_01 = 0x109
MLB_MSG_ACC_05 = 0x10D
MLB_MSG_ACC_02 = 0x30C
MLB_MSG_ACC_10 = 0x117
MLB_MSG_GATEWAY_05 = 0x39C
MLB_ACC_COORDINATOR_MSGS = (MLB_MSG_ACC_01, MLB_MSG_ACC_05, MLB_MSG_ACC_02)
MLB_GEARBOX_MSGS = (MLB_MSG_GETRIEBE_01, MLB_MSG_GETRIEBE_02, MLB_MSG_GETRIEBE_03, MLB_MSG_GETRIEBE_04)

View File

@@ -17,5 +17,5 @@ class ToyotaSafetyFlagsIQ:
DEFAULT = 0
UNSUPPORTED_DSU = 1
GAS_INTERCEPTOR = 2
LKAS_HUD = 4

View File

@@ -39,7 +39,6 @@
#define TOYOTA_COMMON_RX_CHECKS(lta) \
{.msg = {{ 0xaa, 0, 8, 83U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
{.msg = {{0x260, 0, 8, 50U, .ignore_counter = true, .ignore_quality_flag=!(lta)}, { 0 }, { 0 }}}, \
{.msg = {{0x412, 2, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 1U}, { 0 }, { 0 }}}, \
#define TOYOTA_RX_CHECKS(lta) \
TOYOTA_COMMON_RX_CHECKS(lta) \
@@ -66,6 +65,9 @@
#define TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK \
{.msg = {{0x201, 0, 6, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
#define TOYOTA_LKAS_HUD_ADDR_CHECK \
{.msg = {{0x412, 2, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 1U}, { 0 }, { 0 }}}, \
static bool toyota_secoc = false;
static bool toyota_alt_brake = false;
static bool toyota_stock_longitudinal = false;
@@ -433,6 +435,7 @@ static safety_config toyota_init(uint16_t param) {
const uint16_t TOYOTA_PARAM_IQ_UNSUPPORTED_DSU = 1;
const uint16_t TOYTOA_PARAM_IQ_GAS_INTERCEPTOR = 2;
const uint16_t TOYOTA_PARAM_IQ_LKAS_HUD = 4;
#ifdef ALLOW_DEBUG
const uint32_t TOYOTA_PARAM_SECOC = 8UL << TOYOTA_PARAM_OFFSET;
@@ -446,6 +449,7 @@ static safety_config toyota_init(uint16_t param) {
const bool toyota_unsupported_dsu = GET_FLAG(current_safety_param_iq, TOYOTA_PARAM_IQ_UNSUPPORTED_DSU);
enable_gas_interceptor = GET_FLAG(current_safety_param_iq, TOYTOA_PARAM_IQ_GAS_INTERCEPTOR);
const bool toyota_lkas_hud = GET_FLAG(current_safety_param_iq, TOYOTA_PARAM_IQ_LKAS_HUD);
// gas interceptor should not be used if openpilot is not controlling longitudinal or is a TSK car
if (toyota_stock_longitudinal || toyota_secoc) {
@@ -471,6 +475,7 @@ static safety_config toyota_init(uint16_t param) {
static RxCheck toyota_secoc_rx_checks[] = {
TOYOTA_SECOC_RX_CHECKS
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
SET_RX_CHECKS(toyota_secoc_rx_checks, ret);
@@ -479,6 +484,7 @@ static safety_config toyota_init(uint16_t param) {
static RxCheck toyota_lta_rx_checks[] = {
TOYOTA_RX_CHECKS(true)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
SET_RX_CHECKS(toyota_lta_rx_checks, ret);
@@ -486,18 +492,22 @@ static safety_config toyota_init(uint16_t param) {
static RxCheck toyota_lka_rx_checks[] = {
TOYOTA_RX_CHECKS(false)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_alt_brake_rx_checks[] = {
TOYOTA_ALT_BRAKE_RX_CHECKS(false)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_unsupported_dsu_rx_checks[] = {
TOYOTA_RX_CHECKS(false)
TOYOTA_DSU_CRUISE_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_alt_brake_unsupported_dsu_rx_checks[] = {
TOYOTA_ALT_BRAKE_RX_CHECKS(false)
TOYOTA_DSU_CRUISE_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
if (!toyota_alt_brake) {
@@ -523,6 +533,7 @@ static safety_config toyota_init(uint16_t param) {
TOYOTA_RX_CHECKS(true)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
SET_RX_CHECKS(toyota_lta_interceptor_rx_checks, ret);
@@ -531,21 +542,25 @@ static safety_config toyota_init(uint16_t param) {
TOYOTA_RX_CHECKS(false)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_alt_brake_interceptor_rx_checks[] = {
TOYOTA_ALT_BRAKE_RX_CHECKS(false)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_unsupported_dsu_interceptor_rx_checks[] = {
TOYOTA_RX_CHECKS(false)
TOYOTA_DSU_CRUISE_ADDR_CHECK
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_alt_brake_unsupported_dsu_interceptor_rx_checks[] = {
TOYOTA_ALT_BRAKE_RX_CHECKS(false)
TOYOTA_DSU_CRUISE_ADDR_CHECK
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
if (!toyota_alt_brake) {
@@ -564,6 +579,10 @@ static safety_config toyota_init(uint16_t param) {
}
}
if (!toyota_lkas_hud) {
ret.rx_checks_len -= 1;
}
return ret;
}

View File

@@ -21,8 +21,8 @@ TOYOTA_COMMON_LONG_TX_MSGS = [[0x283, 0], [0x2E6, 0], [0x2E7, 0], [0x33E, 0], [0
GAS_INTERCEPTOR_TX_MSGS = [[0x200, 0]]
UNSUPPORTED_DSU = [
{"SAFETY_PARAM_IQ": ToyotaSafetyFlagsIQ.DEFAULT},
{"SAFETY_PARAM_IQ": ToyotaSafetyFlagsIQ.UNSUPPORTED_DSU},
{"SAFETY_PARAM_IQ": ToyotaSafetyFlagsIQ.LKAS_HUD},
{"SAFETY_PARAM_IQ": ToyotaSafetyFlagsIQ.UNSUPPORTED_DSU | ToyotaSafetyFlagsIQ.LKAS_HUD},
]
@@ -33,7 +33,7 @@ class TestToyotaSafetyBase(common.CarSafetyTest, common.LongitudinalAccelSafetyT
FWD_BLACKLISTED_ADDRS = {2: [0x2E4, 0x412, 0x191, 0x343]}
EPS_SCALE = 73
SAFETY_PARAM_IQ: int = 0
SAFETY_PARAM_IQ: int = ToyotaSafetyFlagsIQ.LKAS_HUD
packer: CANPackerSafety
safety: libsafety_py.LibSafety
@@ -96,6 +96,9 @@ class TestToyotaSafetyBase(common.CarSafetyTest, common.LongitudinalAccelSafetyT
return self.packer.make_can_msg_safety("LKAS_HUD", 2, values)
def test_enable_control_allowed_with_aol_button(self):
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ | ToyotaSafetyFlagsIQ.LKAS_HUD)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.safety.get_current_safety_param())
self.safety.init_tests()
for enable_aol in (True, False):
with self.subTest("enable_aol", aol_enabled=enable_aol):
self.safety.set_aol_params(enable_aol, False, False)
@@ -120,6 +123,16 @@ class TestToyotaSafetyBase(common.CarSafetyTest, common.LongitudinalAccelSafetyT
self.safety.set_controls_allowed_lat(False)
self.safety.set_aol_params(False, False, False)
def test_lkas_button_requires_lkas_hud(self):
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ & ~ToyotaSafetyFlagsIQ.LKAS_HUD)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.safety.get_current_safety_param())
self.safety.init_tests()
self.safety.set_aol_params(True, False, False)
button_state = self.safety.get_aol_button_press()
self._rx(self._lkas_button_msg(True))
self.assertEqual(button_state, self.safety.get_aol_button_press())
self.assertFalse(self.safety.get_controls_allowed_lat())
def test_diagnostics(self, stock_longitudinal: bool = False, ecu_disabled: bool = True):
for should_tx, msg in ((False, b"\x6D\x02\x3E\x00\x00\x00\x00\x00"), # fwdCamera tester present
(False, b"\x0F\x03\xAA\xAA\x00\x00\x00\x00"), # non-tester present
@@ -250,6 +263,7 @@ class TestToyotaSafetyAngle(TestToyotaSafetyBase, common.AngleSteeringSafetyTest
def setUp(self):
self.packer = CANPackerSafety("toyota_nodsu_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.EPS_SCALE | ToyotaSafetyFlags.LTA)
self.safety.init_tests()
@@ -431,6 +445,7 @@ class TestToyotaStockLongitudinalAngle(TestToyotaStockLongitudinalBase, TestToyo
def setUp(self):
self.packer = CANPackerSafety("toyota_nodsu_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota,
self.EPS_SCALE | ToyotaSafetyFlags.STOCK_LONGITUDINAL | ToyotaSafetyFlags.LTA)
self.safety.init_tests()
@@ -445,6 +460,7 @@ class TestToyotaSecOcSafetyBase(TestToyotaSafetyBase):
def setUp(self):
self.packer = CANPackerSafety("toyota_secoc_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota,
self.EPS_SCALE | ToyotaSafetyFlags.SECOC)
self.safety.init_tests()
@@ -485,6 +501,7 @@ class TestToyotaSecOcSafetyStockLongitudinal(TestToyotaSecOcSafetyBase, TestToyo
def setUp(self):
self.packer = CANPackerSafety("toyota_secoc_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota,
self.EPS_SCALE | ToyotaSafetyFlags.STOCK_LONGITUDINAL | ToyotaSafetyFlags.SECOC)
self.safety.init_tests()
@@ -498,6 +515,7 @@ class TestToyotaSecOcSafety(TestToyotaSecOcSafetyBase):
def setUp(self):
self.packer = CANPackerSafety("toyota_secoc_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.EPS_SCALE | ToyotaSafetyFlags.SECOC)
self.safety.init_tests()

View File

@@ -249,6 +249,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"MacModelFailed", {CLEAR_ON_MANAGER_START, BOOL}},
{"MacModelLastError", {CLEAR_ON_MANAGER_START, STRING}},
{"MacModelLatencyMs", {CLEAR_ON_MANAGER_START, FLOAT, "0.0"}},
{"MacModelRetryBackoff", {CLEAR_ON_MANAGER_START, STRING, "10.0"}},
// comma USB eGPU big-model backend. Mutually exclusive with eMac at
// runtime (eMac wins). UsbGpu* naming/flags mirror comma's handover branch
@@ -363,6 +364,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"IQLateralCurvatureLookahead", {PERSISTENT, BOOL, "0"}},
{"IQSoftwareSteerDelay", {PERSISTENT, FLOAT, "0.2"}},
{"IQSteerDelayCache", {PERSISTENT, FLOAT, "0.2"}},
{"IQLatJerkGain", {PERSISTENT, STRING, "1.0"}},
{"LaneChangeBsd", {PERSISTENT, INT, "0"}}, // -1 ignore BSD, 0 default, 1 block lane change on BSD
{"LaneChangeContinuous", {PERSISTENT, BOOL, "0"}}, // 0 one-shot per blinker, 1 chain on held blinker (torque-gated)
{"LaneChangeDelay", {PERSISTENT, FLOAT, "0.0"}}, // tenths of a second; scaled by 0.1 in desire_helper

View File

@@ -209,6 +209,25 @@ def region_bundle_path(selector: str) -> Path:
return region_bundle_dir(selector) / "tiles" / "offline.mbtiles"
def region_valhalla_path(selector: str) -> Path:
# valhalla mmaps this tar in place, so it stays uncompressed on disk
return region_bundle_dir(selector) / "valhalla" / "tiles.tar"
def region_valhalla_installed(selector: str) -> bool:
return region_valhalla_path(selector).exists()
def installed_valhalla_selectors() -> list[str]:
regions_root = offline_map_root() / "regions"
if not regions_root.exists():
return []
return sorted(
child.name for child in regions_root.iterdir()
if child.is_dir() and (child / "valhalla" / "tiles.tar").exists()
)
def region_bundle_installed(selector: str) -> bool:
return region_bundle_path(selector).exists()
@@ -313,6 +332,22 @@ class TileBundleDownloader:
)
if not day_ok:
cloudlog.warning(f"iq_maps: day-style bundle failed for {selector}; night set installed")
if entry.get("valhalla_path"):
# routing is additive: a region whose extract is missing or corrupt must still end up
# with a usable map rather than failing the whole download
try:
nav_ok = self._download_file(
selector, base_url, entry["valhalla_path"], int(entry.get("valhalla_bytes", 0)),
str(entry.get("valhalla_sha256", "")).strip().lower(),
region_valhalla_path(selector),
progress_offset + int(entry.get("bytes", 0)) + int(entry.get("day_bytes", 0)),
progress_total, 1, entry.get("valhalla_objects"),
)
except Exception as exc:
nav_ok = False
cloudlog.warning(f"iq_maps: routing extract errored for {selector}: {exc}")
if not nav_ok:
cloudlog.warning(f"iq_maps: routing extract failed for {selector}; map tiles installed")
_write_manifest(selector, entry)
cloudlog.info(f"iq_maps: installed tile bundle {selector}")
return True

View File

@@ -186,6 +186,8 @@ class NNTorqueModel:
PLAN_SAMPLE_START = 5
LAG_EXTRA_S = 0.0
JERK_AHEAD_TAU_S = 0.15 # low-pass on the model-derived jerk feed-forward (kills big-model accel.y noise)
JERK_PARAM_REFRESH = 100 # cycles (~1s at 100Hz)
BASE_P = 0.8
BASE_I = 0.15
@@ -264,6 +266,15 @@ class PilotLateralBrain:
self.friction_look_ahead_bp = [9.0, 30.0]
self.lat_jerk_friction_factor = 0.4
self.lat_accel_friction_factor = 0.7
# The model-derived jerk term is a frame-to-frame derivative of model_v2.acceleration.y; on
# spatial/big models that array is slightly noisy and the raw derivative drives in-lane steering
# oscillation (sunny/stock has no such term). Low-pass it, and expose a live gain so it can be
# tuned to 0 (== stock friction ff) without a software push.
self._jerk_lp = FirstOrderFilter(0.0, JERK_AHEAD_TAU_S, 0.01)
self._jerk_gain = 1.0
self._jerk_param_frame = 0
self._jerk_param_ok = True
self._params = Params()
self.t_diffs = np.diff(ModelConstants.T_IDXS)
self.desired_lat_jerk_time = cp.steerActuatorDelay + LAG_EXTRA_S
@@ -294,6 +305,17 @@ class PilotLateralBrain:
self.jerk_ahead = 0.0
def update_calculations(self, car_state, vehicle_model, desired_lat_accel):
self._jerk_param_frame += 1
if self._jerk_param_ok and self._jerk_param_frame % JERK_PARAM_REFRESH == 0:
try:
raw = self._params.get("IQLatJerkGain")
self._jerk_gain = float(raw) if raw not in (None, b"", "") else 1.0
except (ValueError, TypeError):
self._jerk_gain = 1.0
except Exception:
# param key absent (params not rebuilt) — never let a param read touch lateral control
self._jerk_param_ok = False
self._jerk_gain = 1.0
self._reset_jerk_estimates(car_state, vehicle_model)
if not self.model_valid:
return
@@ -305,6 +327,7 @@ class PilotLateralBrain:
forecast = _pointwise_jerk(accel_y, self.t_diffs)
window = forecast[PLAN_SAMPLE_START:self._horizon_index(car_state.vEgo)]
self.jerk_ahead = sign_locked_min(window, desired_jerk)
self.jerk_ahead = self._jerk_lp.update(self.jerk_ahead) * self._jerk_gain
if self.jerk_ahead == 0.0:
self.jerk_now = 0.0

View File

@@ -0,0 +1,81 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos/
"""
import numpy as np
from iqpilot.cereal import car, log
from iqdbc.car.car_helpers import interfaces
from iqdbc.car.toyota.values import CAR as TOYOTA
from iqdbc.car.vehicle_model import VehicleModel
from iqpilot.common.realtime import DT_CTRL
from iqpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
from iqpilot.selfdrive.car.helpers import convert_to_capnp
from iqpilot.selfdrive.car import interfaces as iqpilot_interfaces
from iqpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N
CAR_NAME = TOYOTA.TOYOTA_COROLLA_TSS2
def _brain():
CI_cls = interfaces[CAR_NAME]
CP = CI_cls.get_non_essential_params(CAR_NAME)
CP_IQ = CI_cls.get_non_essential_params_iq(CP, CAR_NAME)
CI = CI_cls(CP, CP_IQ)
iqpilot_interfaces.apply_iq_car_config(CI)
ctrl = LatControlTorque(CP.as_reader(), convert_to_capnp(CP_IQ).as_reader(), CI, DT_CTRL)
return ctrl.nnff_assist, VehicleModel(CP)
def _model(rng):
# same-sign accel ramp (so sign_locked_min yields a real jerk) whose slope jitters frame to
# frame the way a spatial big model's path does — this is what drives jerk_ahead to swing.
n = max(CONTROL_N, 33)
slope = abs(0.5 + rng.normal(0, 0.25))
m = log.ModelDataV2.new_message()
m.acceleration.y = (slope * np.arange(n) * 0.1).tolist()
m.orientation.x = [0.0] * n
return m
def _cs():
cs = car.CarState.new_message()
cs.vEgo = 25.0
cs.steeringRateDeg = 0.0
return cs
def _run(lp_on):
brain, VM = _brain()
rng = np.random.default_rng(7)
cs = _cs()
out = []
for _ in range(400):
brain.update_model_v2(_model(rng))
if not lp_on:
brain._jerk_lp.update = lambda x: x # bypass low-pass == pre-fix behavior
brain.update_calculations(cs, VM, 0.0)
out.append(brain.jerk_ahead)
return np.array(out)
def test_lowpass_cuts_jerk_command_swing():
old = _run(lp_on=False)
new = _run(lp_on=True)
# the path must actually exercise the jerk feed-forward (guard against a vacuous test)
assert np.abs(np.diff(old)).mean() > 0.02, "input did not exercise jerk_ahead"
old_swing = np.abs(np.diff(old)).mean()
new_swing = np.abs(np.diff(new)).mean()
# low-pass must cut the frame-to-frame jerk swing (the wheel oscillation) by a large margin
assert new_swing < 0.3 * old_swing, (old_swing, new_swing)
def test_gain_zero_matches_stock():
brain, VM = _brain()
brain._jerk_param_ok = False
brain._jerk_gain = 0.0
rng = np.random.default_rng(1)
cs = _cs()
for _ in range(60):
brain.update_model_v2(_model(rng))
brain.update_calculations(cs, VM, 0.0)
assert brain.jerk_ahead == 0.0 # no model-jerk term == sunny/stock feedforward

View File

@@ -357,6 +357,7 @@ def main() -> None:
}))
if run_count % 100 == 0:
cloudlog.warning(f"modeld_selector misses: {miss_reasons}")
pwriter.put_bool(keys["active"], latch.active)
cloudlog.warning(f"modeld_selector: big_used={big_used_count}/{run_count} "
f"last_big_peek={big_peek} target={target} active={latch.active} "
f"max_big_lag={BIG_MAX_LAG_FRAMES}")

View File

@@ -13,7 +13,9 @@ import time
os.environ.setdefault("FLOAT16", "1")
os.environ.setdefault("JIT_BATCH_SIZE", "0")
os.environ.setdefault("GMMU", "0")
os.environ.setdefault("TC_OPT", "2")
# TC_OPT=2 lets tinygrad pick tensor-core kernels; on some models a TC kernel miscompiles and biases
# the output (documented on Metal). A parity gate below catches it and re-compiles with TC off.
os.environ.setdefault("TC_OPT", "0" if ("--tc-off" in sys.argv or os.environ.get("IQ_EGPU_TC_OFF")) else "2")
HOST = "--host" in sys.argv
if HOST:
@@ -32,6 +34,10 @@ INPUT_SPEC = dict(MODEL_INPUT_SPEC)
patch_tinygrad_fetch_fw()
SEED = 42
class _ParityFail(RuntimeError):
pass
KERNEL_PROGRESS_SCALE = 260.0
@@ -151,6 +157,25 @@ def _policy_frame(seed: int, input_spec: dict):
return warped
def _tc_off_reference(onnx_path: str, meta: dict):
"""Compile+run the model with tensor cores OFF in a child process and return the last of 3
policy frames. This is the trusted reference: TC-off kernels are the conservative path the
eMac gate also trusts. Used to catch a TC kernel miscompile that would bias steering."""
import subprocess
import tempfile
with tempfile.TemporaryDirectory() as td:
ref = os.path.join(td, "ref.npy")
env = {k: v for k, v in os.environ.items() if k not in ("TC_OPT", "BEAM")}
env["TC_OPT"] = "0"
env["IQ_EGPU_REFERENCE"] = ref
r = subprocess.run([sys.executable, "-m", "iqpilot.selfdrive.iqmodeld.tools.compile_egpu_model",
"--model", meta["key"], "--onnx", onnx_path, "--tc-off"],
env=env, capture_output=True, text=True, timeout=14400)
if r.returncode != 0 or not os.path.isfile(ref):
raise RuntimeError(f"parity reference compile failed:\n{r.stderr[-2000:]}")
return np.load(ref)
def compile_policy_model(meta: dict, onnx_path: str, out_path: str) -> str:
from tinygrad.device import Device
from tinygrad.engine.jit import TinyJit
@@ -216,6 +241,10 @@ def compile_policy_model(meta: dict, onnx_path: str, out_path: str) -> str:
flat = out.numpy().reshape(-1)
packed.views["prev_feat"][:] = flat[meta["output_slices"]["hidden_state"]].reshape(packed.views["prev_feat"].shape)
outs.append(flat)
ref_target = os.environ.get("IQ_EGPU_REFERENCE")
if ref_target:
np.save(ref_target, outs[-1])
return out_path
if HOST:
os.replace(tmp, out_path)
return out_path
@@ -229,6 +258,13 @@ def compile_policy_model(meta: dict, onnx_path: str, out_path: str) -> str:
from iqpilot.selfdrive.iqmodeld.tools.compile_supercombo import _slice_outputs, _validate_pose_outputs
_validate_pose_outputs(PhaseParser().parse_vision_outputs(_slice_outputs(outs[-1], meta["output_slices"])))
if os.environ.get("TC_OPT") != "0" and not os.environ.get("IQ_EGPU_SKIP_PARITY"):
ref = _tc_off_reference(onnx_path, meta)
rel = float(np.abs(outs[-1] - ref).mean() / max(1e-3, float(np.abs(ref).mean())))
if rel > 0.01:
raise _ParityFail(f"PARITY FAIL: TC kernels miscompiled {meta['key']} (rel={rel:.4f} vs TC-off); recompiling with tensor cores disabled")
print(f" parity vs TC-off reference: rel={rel:.6f} OK")
os.replace(tmp, out_path)
return out_path
@@ -244,6 +280,7 @@ def main() -> None:
p.add_argument("--format", type=int, default=2, choices=(1, 2))
p.add_argument("--host", action="store_true", help="compile on a mock dock (no AMD hardware); outputs need a dock parity gate")
p.add_argument("--arch", default=None, help="target gfx arch for --host")
p.add_argument("--tc-off", action="store_true", help="disable tensor-core kernels (conservative; auto-set on parity failure)")
args = p.parse_args()
if args.host and args.format != 2:
raise SystemExit("--host supports format 2 only")
@@ -275,7 +312,15 @@ def main() -> None:
sampler.start()
try:
build = compile_policy_model if args.format == 2 else compile_model
out = build(meta, onnx_path, args.output or egpu_pkl_path(meta))
try:
out = build(meta, onnx_path, args.output or egpu_pkl_path(meta))
except _ParityFail as e:
if os.environ.get("TC_OPT") == "0" or args.format != 2:
raise
print(f"{e}\nretrying compile with tensor cores disabled", flush=True)
os.environ["TC_OPT"] = "0"
os.environ["IQ_EGPU_TC_OFF"] = "1"
out = compile_policy_model(meta, onnx_path, args.output or egpu_pkl_path(meta))
finally:
if stop is not None:
stop.set()

View File

@@ -274,7 +274,10 @@ class SelfdriveD(GapButtonActions):
dock_present = self.sm['deviceState'].egpuDockPresent
mac_active = self.params.get_bool("MacModelActive")
model_unavailable = big_active is True and self.sm.seen['modelV2'] and not self.sm.alive['modelV2']
big_failed = (big_active is False or model_unavailable
# an explicit False before this session's first activation is just the selector arming
# (it pre-clears the param on startup); alerting on it pops "big model failed" on every
# return to the road until the latch warms up
big_failed = ((self.big_model_active and big_active is False) or model_unavailable
or (self.big_model_active and not dock_present)) and not mac_active
if big_failed:
self.events.add(EventName.bigModelFailed)

View File

@@ -152,7 +152,7 @@ class MainLayout(Widget):
self._layouts[MainState.ROUTES].set_on_play(self.open_video)
self._layouts[MainState.VIDEO].set_on_back(self.open_routes)
self._layouts[MainState.ONROAD].set_click_callback(self._on_onroad_clicked)
device.add_interactive_timeout_callback(self._set_mode_for_state)
device.add_interactive_timeout_callback(self._on_interactive_timeout)
def _update_layout_rects(self):
self._sidebar_rect = rl.Rectangle(self._rect.x, self._rect.y, SIDEBAR_WIDTH, self._rect.height)
@@ -166,6 +166,20 @@ class MainLayout(Widget):
self._set_mode_for_state()
def _car_stationary(self) -> bool:
if not ui_state.sm.valid["carState"]:
return False
return ui_state.sm["carState"].vEgo < 0.1
def _on_interactive_timeout(self):
# The idle timeout normally returns the UI to the road view. Don't yank the user out of Settings
# while the car is stationary - e.g. a hybrid parked with the engine running to charge reads as
# onroad (ignition tracks the ICE), so this would otherwise make Settings unusable while parked.
# A moving car still returns to the road view.
if self._current_mode == MainState.SETTINGS and ui_state.started and self._car_stationary():
return
self._set_mode_for_state()
def _set_mode_for_state(self):
if ui_state.started:
# Don't hide sidebar from interactive timeout

View File

@@ -0,0 +1,56 @@
from types import SimpleNamespace
import pytest
from iqpilot.selfdrive.ui.layouts.main import MainLayout, MainState
def make_layout(current_mode):
layout = object.__new__(MainLayout)
layout._current_mode = current_mode
layout._set_mode_calls = []
layout._set_mode_for_state = lambda: layout._set_mode_calls.append(current_mode)
return layout
class FakeSm:
def __init__(self, v_ego, carstate_valid):
self.valid = {"carState": carstate_valid}
self._v_ego = v_ego
def __getitem__(self, key):
return SimpleNamespace(vEgo=self._v_ego)
class TestSettingsInteractiveTimeout:
def _run(self, current_mode, started, v_ego, carstate_valid=True):
layout = make_layout(current_mode)
fake = SimpleNamespace(started=started, sm=FakeSm(v_ego, carstate_valid))
monkeypatch = pytest.MonkeyPatch()
monkeypatch.setattr("iqpilot.selfdrive.ui.layouts.main.ui_state", fake)
try:
layout._on_interactive_timeout()
finally:
monkeypatch.undo()
return layout._set_mode_calls
def test_stationary_in_settings_stays(self):
# parked/charging hybrid reads onroad; the timeout must not eject from Settings
assert self._run(MainState.SETTINGS, started=True, v_ego=0.0) == []
def test_moving_in_settings_returns_to_road(self):
assert self._run(MainState.SETTINGS, started=True, v_ego=5.0) == [MainState.SETTINGS]
def test_onroad_layout_always_handled(self):
assert self._run(MainState.ONROAD, started=True, v_ego=0.0) == [MainState.ONROAD]
def test_home_layout_always_handled(self):
assert self._run(MainState.HOME, started=True, v_ego=0.0) == [MainState.HOME]
def test_offroad_in_settings_handled(self):
# car off (offroad): existing behavior is unchanged
assert self._run(MainState.SETTINGS, started=False, v_ego=0.0) == [MainState.SETTINGS]
def test_invalid_carstate_treated_as_moving(self):
# if speed is unknown, fail safe to the road view rather than trapping in settings
assert self._run(MainState.SETTINGS, started=True, v_ego=0.0, carstate_valid=False) == [MainState.SETTINGS]

View File

@@ -67,14 +67,14 @@
},
{
"name": "boot",
"url": "https://git.konn3kt.com/IQ.Lvbs/iqos/raw/branch/master/boot-aea4aecefd188d9c95726b699902378676c6266a7ae37008b5c2aa0e1e1190fb.img.xz",
"hash": "aea4aecefd188d9c95726b699902378676c6266a7ae37008b5c2aa0e1e1190fb",
"hash_raw": "aea4aecefd188d9c95726b699902378676c6266a7ae37008b5c2aa0e1e1190fb",
"url": "https://git.konn3kt.com/IQ.Lvbs/iqos/raw/branch/master/boot-4258981292746f5622f4a03a1e0c1d77379660e46bbaa455c504d638b5307906.img.xz",
"hash": "4258981292746f5622f4a03a1e0c1d77379660e46bbaa455c504d638b5307906",
"hash_raw": "4258981292746f5622f4a03a1e0c1d77379660e46bbaa455c504d638b5307906",
"size": 18216960,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "f568e4394e36a367de58cce2b982bf597963e088b6a00b1ac88ca03cce8f62fd"
"ondevice_hash": "7be61ba2be5617ac22d6beb8ba8b896109a554347021f5e44b72458748336975"
},
{
"name": "system",

View File

@@ -1 +1 @@
qT72MCHtDUWnARJbSsLUcPaISRZxjFPNf282R9ZC1SXvFJz6X6NmjgknK3OLDLijOQWlGvvJZGsDgz2vsdPVAg==
Myu8k7msX7pt28JKl1Lx5/NnXu9i15nT8bFWnwGsip8wdCYPJqj69AWrfCtlg9YrR98O6ThCAEA1uzUfsrTeDQ==

View File

@@ -56,14 +56,14 @@
},
{
"name": "boot",
"url": "https://git.konn3kt.com/IQ.Lvbs/iqos/raw/branch/master/boot-aea4aecefd188d9c95726b699902378676c6266a7ae37008b5c2aa0e1e1190fb.img.xz",
"hash": "aea4aecefd188d9c95726b699902378676c6266a7ae37008b5c2aa0e1e1190fb",
"hash_raw": "aea4aecefd188d9c95726b699902378676c6266a7ae37008b5c2aa0e1e1190fb",
"url": "https://git.konn3kt.com/IQ.Lvbs/iqos/raw/branch/master/boot-4258981292746f5622f4a03a1e0c1d77379660e46bbaa455c504d638b5307906.img.xz",
"hash": "4258981292746f5622f4a03a1e0c1d77379660e46bbaa455c504d638b5307906",
"hash_raw": "4258981292746f5622f4a03a1e0c1d77379660e46bbaa455c504d638b5307906",
"size": 18216960,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "f568e4394e36a367de58cce2b982bf597963e088b6a00b1ac88ca03cce8f62fd"
"ondevice_hash": "7be61ba2be5617ac22d6beb8ba8b896109a554347021f5e44b72458748336975"
},
{
"name": "system",

View File

@@ -1 +1 @@
fL46Z+k/wqjavP3J1S/VzE90BXcvvRF+S41MgHEXYjW+Jlnu5REOp6rvp3SJFEkKIEaiSf9PsHyiDgQkC6J2Aw==
aGtkoy//jP3MWJmd5uvb/mxKu1KsE8ZlhrTUr1CPCotwjIVzsxOncUGN9HnUcMXoUWZbUWz9H8Q+ARYxz41/Ag==