Compare commits

..

1 Commits

Author SHA1 Message Date
github-actions[bot] 549ad134d8 sunnypilot v2026.11.13-5031
version: sunnypilot v2026.003.000 (feature-branch)
date: 2026-11-13T17:56:57
master commit: 44077845e4
2026-11-13 17:56:57 +00:00
48 changed files with 586 additions and 302 deletions
+1 -7
View File
@@ -4,7 +4,7 @@
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
# 357 Supported Cars
# 351 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br>&nbsp;|Video|Setup Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
@@ -139,7 +139,6 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona 2020">Buy Here</a></sub></details>|||
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Kona (without HDA II) 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona (without HDA II) 2024-25">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2018-21">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg" /></a>||
@@ -153,23 +152,19 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata 2018-19">Buy Here</a></sub></details>|||
|Hyundai|Sonata 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg" /></a>||
|Hyundai|Sonata (without HDA II) 2024-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata (without HDA II) 2024-26">Buy Here</a></sub></details>|||
|Hyundai|Sonata Hybrid 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata Hybrid 2020-23">Buy Here</a></sub></details>|||
|Hyundai|Sonata Hybrid (without HDA II) 2024-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata Hybrid (without HDA II) 2024-26">Buy Here</a></sub></details>|||
|Hyundai|Staria 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Staria 2023">Buy Here</a></sub></details>|||
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2021">Buy Here</a></sub></details>|||
|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2022">Buy Here</a></sub></details>|||
|Hyundai|Tucson 2023-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2023-24">Buy Here</a></sub></details>|||
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Diesel 2019">Buy Here</a></sub></details>|||
|Hyundai|Tucson Hybrid 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Hybrid 2022-24">Buy Here</a></sub></details>|||
|Hyundai|Tucson Hybrid (without HDA II) 2025-26|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Hybrid (without HDA II) 2025-26">Buy Here</a></sub></details>|||
|Hyundai|Tucson Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Plug-in Hybrid 2024">Buy Here</a></sub></details>|||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Veloster 2019-20">Buy Here</a></sub></details>|||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Jeep Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg" /></a>||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Jeep Grand Cherokee 2019-21">Buy Here</a></sub></details>|||
|Kia|Carnival 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival 2022-24">Buy Here</a></sub></details>|||
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival (China only) 2023">Buy Here</a></sub></details>|||
|Kia|Carnival Hybrid (with HDA II) 2025-26|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival Hybrid (with HDA II) 2025-26">Buy Here</a></sub></details>|||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed 2019-21">Buy Here</a></sub></details>|||
|Kia|Ceed Plug-in Hybrid 2021|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed Plug-in Hybrid 2021">Buy Here</a></sub></details>|||
|Kia|EV6 (Southeast Asia only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>|||
@@ -195,7 +190,6 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Niro Plug-in Hybrid 2020|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Niro Plug-in Hybrid 2020">Buy Here</a></sub></details>|||
|Kia|Niro Plug-in Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Niro Plug-in Hybrid 2021">Buy Here</a></sub></details>|||
|Kia|Niro Plug-in Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Niro Plug-in Hybrid 2022">Buy Here</a></sub></details>|||
|Kia|Niro Plus EV 2024|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Niro Plus EV 2024">Buy Here</a></sub></details>|||
|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Optima 2017">Buy Here</a></sub></details>|||
|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Optima 2019-20">Buy Here</a></sub></details>|||
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Optima Hybrid 2019">Buy Here</a></sub></details>|||
@@ -131,6 +131,7 @@ class CarHarness(EnumBase):
hyundai_p = BaseCarHarness("Hyundai P connector")
hyundai_q = BaseCarHarness("Hyundai Q connector")
hyundai_r = BaseCarHarness("Hyundai R connector")
hyundai_s = BaseCarHarness("Hyundai S connector")
custom = BaseCarHarness("Developer connector")
obd_ii = BaseCarHarness("OBD-II connector", parts=[Cable.long_obdc_cable], has_connector=False)
gm = BaseCarHarness("GM connector", parts=[Accessory.harness_box])
-1
View File
@@ -336,7 +336,6 @@ MIGRATION = {
"SKODA SUPERB 3RD GEN": VW.SKODA_SUPERB_MK3,
"RIVIAN_R1_GEN1": RIVIAN.RIVIAN_R1,
"RIVIAN_R1_GEN2": RIVIAN.RIVIAN_R1,
"HYUNDAI_SONATA_HEV_2024": HYUNDAI.HYUNDAI_SONATA_2024,
"mock": MOCK.MOCK,
}
@@ -235,10 +235,10 @@ class CarController(CarControllerBase, CcncCarController, EsccCarController, Lea
# cruise cancel
if CC.cruiseControl.cancel:
# Here we send ACC message to cancel, not buttons. Don't delay
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS and not lka_steering:
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
self.last_button_frame = self.frame
elif not self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS and self.cancel_counter > CANCEL_BUTTON_DELAY_FRAMES:
elif self.cancel_counter > CANCEL_BUTTON_DELAY_FRAMES:
for _ in range(20):
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.CANCEL))
self.last_button_frame = self.frame
@@ -209,17 +209,6 @@ class CarInterface(CarInterfaceBase):
if ret.flags & HyundaiFlagsSP.CCNC and not lka_steering:
ret.safetyParam |= HyundaiSafetyFlagsSP.CCNC
if ret.flags & HyundaiFlagsSP.CCNC and lka_steering:
# this needs to be figured out for ccNC cars with an ADAS Driving ECU
stock_cp.alphaLongitudinalAvailable = False
stock_cp.openpilotLongitudinalControl = False
stock_cp.pcmCruise = True
stock_cp.safetyConfigs[-1].safetyParam &= ~HyundaiSafetyFlags.LONG.value
if 0x1cf not in fingerprint[CAN.ECAN]:
stock_cp.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
stock_cp.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_ALT_BUTTONS.value
if ret.flags & HyundaiFlagsSP.NON_SCC:
stock_cp.alphaLongitudinalAvailable = False
stock_cp.openpilotLongitudinalControl = False
@@ -22,7 +22,11 @@ NO_DATES_PLATFORMS = {
# CAN FD
CAR.KIA_SPORTAGE_5TH_GEN,
CAR.HYUNDAI_SANTA_CRUZ_1ST_GEN,
CAR.HYUNDAI_SANTA_CRUZ_2025,
CAR.HYUNDAI_TUCSON_4TH_GEN,
CAR.HYUNDAI_TUCSON_2025,
CAR.HYUNDAI_TUCSON_HEV_2025,
CAR.HYUNDAI_TUCSON_PHEV_2025,
# CAN
CAR.HYUNDAI_ELANTRA,
CAR.HYUNDAI_ELANTRA_GT_I30,
+56 -15
View File
@@ -298,8 +298,11 @@ class CAR(Platforms):
flags=HyundaiFlags.CAMERA_SCC | HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS,
)
HYUNDAI_KONA_EV_2ND_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Kona Electric (with HDA II, Korea only) 2023", video="https://www.youtube.com/watch?v=U2fOCmcQ8hw",
car_parts=CarParts.common([CarHarness.hyundai_r]))],
[
HyundaiCarDocs("Hyundai Kona Electric (with HDA II, Korea only) 2023", video="https://www.youtube.com/watch?v=U2fOCmcQ8hw",
car_parts=CarParts.common([CarHarness.hyundai_r])),
HyundaiCarDocs("Hyundai Kona Electric (without HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_a])),
],
CarSpecs(wheelbase=2.66, steerRatio=13.6, tireStiffnessFactor=0.385),
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_NO_RADAR_DISABLE,
)
@@ -398,7 +401,6 @@ class CAR(Platforms):
HyundaiCarDocs("Hyundai Tucson 2022", car_parts=CarParts.common([CarHarness.hyundai_n])),
HyundaiCarDocs("Hyundai Tucson 2023-24", "All", car_parts=CarParts.common([CarHarness.hyundai_n])),
HyundaiCarDocs("Hyundai Tucson Hybrid 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_n])),
HyundaiCarDocs("Hyundai Tucson Hybrid (without HDA II) 2025-26", car_parts=CarParts.common([CarHarness.hyundai_n])),
HyundaiCarDocs("Hyundai Tucson Plug-in Hybrid 2024", "All", car_parts=CarParts.common([CarHarness.hyundai_n])),
],
CarSpecs(wheelbase=2.756, steerRatio=13.7, tireStiffnessFactor=0.385),
@@ -447,7 +449,6 @@ class CAR(Platforms):
HyundaiCarDocs("Kia Niro EV 2020", "All", video="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_f])),
HyundaiCarDocs("Kia Niro EV 2021", "All", video="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_c])),
HyundaiCarDocs("Kia Niro EV 2022", "All", video="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_h])),
HyundaiCarDocs("Kia Niro Plus EV 2024", car_parts=CarParts.common([CarHarness.hyundai_h])),
],
CarSpecs(wheelbase=2.7, steerRatio=13.6, tireStiffnessFactor=0.385), # average of all the cars
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.EV,
@@ -578,8 +579,7 @@ class CAR(Platforms):
KIA_CARNIVAL_4TH_GEN = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia Carnival 2022-24", car_parts=CarParts.common([CarHarness.hyundai_a])),
HyundaiCarDocs("Kia Carnival (China only) 2023", car_parts=CarParts.common([CarHarness.hyundai_k])),
HyundaiCarDocs("Kia Carnival Hybrid (with HDA II) 2025-26", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q])),
HyundaiCarDocs("Kia Carnival (China only) 2023", car_parts=CarParts.common([CarHarness.hyundai_k]))
],
CarSpecs(wheelbase=3.09, steerRatio=14.23),
flags=HyundaiFlags.CANFD_RADAR_SCC,
@@ -656,10 +656,6 @@ class CAR(Platforms):
HYUNDAI_ELANTRA_2021.specs,
flags=HyundaiFlags.CHECKSUM_CRC8,
)
HYUNDAI_KONA_2ND_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Kona (without HDA II) 2024-25", car_parts=CarParts.common([CarHarness.hyundai_l]))],
HYUNDAI_KONA_EV_2ND_GEN.specs,
)
HYUNDAI_KONA_NON_SCC = HyundaiNonSccPlatformConfig(
[HyundaiNonSccCarDocs("Hyundai Kona Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_b]))],
HYUNDAI_KONA.specs,
@@ -700,13 +696,58 @@ class CAR(Platforms):
flags=HyundaiFlags.CHECKSUM_CRC8,
sp_flags=HyundaiFlagsSP.NON_SCC_RADAR_FCA,
)
HYUNDAI_SONATA_2024 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Hyundai Sonata (without HDA II) 2024-26", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
HyundaiCarDocs("Hyundai Sonata Hybrid (without HDA II) 2024-26", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
],
HYUNDAI_SONATA_HEV_2024 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Sonata Hybrid (without HDA II) 2024-26", car_parts=CarParts.common([CarHarness.hyundai_a]))],
CarSpecs(wheelbase=2.84, steerRatio=13.27),
)
HYUNDAI_KONA_2ND_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Kona (without HDA II) 2024-25", car_parts=CarParts.common([CarHarness.hyundai_l]))],
CarSpecs(wheelbase=2.66, steerRatio=13.6, tireStiffnessFactor=0.385),
)
HYUNDAI_KONA_HEV_2ND_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Kona Hybrid (without HDA II) 2024-26", car_parts=CarParts.common([CarHarness.hyundai_l]))],
CarSpecs(wheelbase=2.66, steerRatio=13.6, tireStiffnessFactor=0.385),
)
HYUNDAI_SONATA_2024 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Sonata (without HDA II) 2024-26", car_parts=CarParts.common([CarHarness.hyundai_a]))],
CarSpecs(wheelbase=2.84, steerRatio=12.81),
)
HYUNDAI_IONIQ_5_N = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Ioniq 5 N (with HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_s]))],
CarSpecs(wheelbase=3.00, steerRatio=14.26, tireStiffnessFactor=1.3),
flags=HyundaiFlags.EV,
)
HYUNDAI_TUCSON_2025 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Tucson (without HDA II) 2025-26", car_parts=CarParts.common([CarHarness.hyundai_n]))],
CarSpecs(wheelbase=2.756, steerRatio=13.7, tireStiffnessFactor=0.385),
)
HYUNDAI_TUCSON_HEV_2025 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Tucson Hybrid (without HDA II) 2025-26", car_parts=CarParts.common([CarHarness.hyundai_n]))],
CarSpecs(wheelbase=2.756, steerRatio=13.7, tireStiffnessFactor=0.385),
)
HYUNDAI_TUCSON_PHEV_2025 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Tucson Plug-in Hybrid (without HDA II) 2025", car_parts=CarParts.common([CarHarness.hyundai_n]))],
CarSpecs(wheelbase=2.756, steerRatio=13.7, tireStiffnessFactor=0.385),
)
HYUNDAI_SANTA_CRUZ_2025 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Santa Cruz (without HDA II) 2025", car_parts=CarParts.common([CarHarness.hyundai_n]))],
CarSpecs(wheelbase=3, steerRatio=14.2),
)
KIA_K4_2025 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia K4 (without HDA II) 2025-26", car_parts=CarParts.common([CarHarness.hyundai_a])),
HyundaiCarDocs("Kia K4 (with HDA II) 2025", car_parts=CarParts.common([CarHarness.hyundai_r])),
],
CarSpecs(wheelbase=2.72, steerRatio=13.4),
)
KIA_K5_2025 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Kia K5 (without HDA II) 2025-26", car_parts=CarParts.common([CarHarness.hyundai_m]))],
CarSpecs(wheelbase=2.85, steerRatio=13.27),
)
KIA_SORENTO_2024 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Kia Sorento (without HDA II) 2024-25", car_parts=CarParts.common([CarHarness.hyundai_a]))],
CarSpecs(wheelbase=2.81, steerRatio=13.5),
)
class Buttons:
+13 -9
View File
@@ -48,6 +48,9 @@ non_tested_cars = [
HYUNDAI.KIA_FORTE_2021_NON_SCC,
HYUNDAI.KIA_SELTOS_2023_NON_SCC,
HYUNDAI.GENESIS_G70_2021_NON_SCC,
HYUNDAI.KIA_SORENTO_2024,
HYUNDAI.HYUNDAI_IONIQ_5_N,
HYUNDAI.HYUNDAI_TUCSON_PHEV_2025,
HONDA.HONDA_CLARITY,
GM.CHEVROLET_BOLT_NON_ACC,
GM.CHEVROLET_BOLT_NON_ACC_1ST_GEN,
@@ -390,14 +393,15 @@ routes = [
# port extensions
CarTestRoute("be7ad2b087973544/0000002b--ec261cc821", HYUNDAI.HYUNDAI_VENUE_2021_NON_SCC),
CarTestRoute("dc7bf18c8af12e37/00000006--ea06255cd0", HYUNDAI.KIA_CEED_PHEV_2022_NON_SCC),
CarTestRoute("d59ca223dca8da93/0000017a--5e6e4107f1", HYUNDAI.HYUNDAI_SONATA_2024), # 2024 hybrid, ccNC, LFA steering
CarTestRoute("d59ca223dca8da93/00000186--dd8cf07e6c", HYUNDAI.HYUNDAI_SONATA_2024, segment=0), # 2024 hybrid, ccNC, LFA steering, openpilot longitudinal
CarTestRoute("832a633bd4e730a0/00000114--ced749ff8b", HYUNDAI.HYUNDAI_SONATA_2024, segment=16), # 2025, ccNC, LFA steering
CarTestRoute("832a633bd4e730a0/00000117--b6875236d6", HYUNDAI.HYUNDAI_SONATA_2024, segment=10), # 2025, ccNC, LFA steering, openpilot longitudinal
CarTestRoute("20f0af20ed379890/00000005--d3298862a0", HYUNDAI.KIA_CARNIVAL_4TH_GEN, segment=3), # 2026 hybrid, ccNC, LKA steering, stock SCC 0x1AA resume
CarTestRoute("bb89d880ca0a4249/000000f8--ac95d3364a", HYUNDAI.HYUNDAI_TUCSON_4TH_GEN), # 2025 hybrid, ccNC, LFA steering
CarTestRoute("bb89d880ca0a4249/000000fb--275ef6d0d5", HYUNDAI.HYUNDAI_TUCSON_4TH_GEN, segment=5), # 2025 hybrid, ccNC, LFA steering, openpilot longitudinal
CarTestRoute("c36828a00b81bdab/000000e1--0186c21051", HYUNDAI.HYUNDAI_KONA_2ND_GEN, segment=8), # 2025, ccNC, LFA steering
CarTestRoute("c36828a00b81bdab/000000e2--04a43142f7", HYUNDAI.HYUNDAI_KONA_2ND_GEN, segment=8), # 2025, ccNC, LFA steering, openpilot longitudinal
CarTestRoute("d59ca223dca8da93/0000017a--5e6e4107f1", HYUNDAI.HYUNDAI_SONATA_HEV_2024),
CarTestRoute("d59ca223dca8da93/00000186--dd8cf07e6c", HYUNDAI.HYUNDAI_SONATA_HEV_2024, segment=0), # openpilot longitudinal
CarTestRoute("6e7904b03a4aafc2/00000010--31034184b6", HYUNDAI.HYUNDAI_SANTA_CRUZ_2025),
CarTestRoute("4267ea8a353cdb36/00000262--8a427003c7", HYUNDAI.HYUNDAI_SONATA_2024, segment=34),
CarTestRoute("a01ca5d4f394c812/00000000--e98b7e4414", HYUNDAI.HYUNDAI_TUCSON_2025),
CarTestRoute("22f9090014364a87/00000002--4cc739c0b2", HYUNDAI.HYUNDAI_TUCSON_HEV_2025),
CarTestRoute("32025f26789d8fab/00000022--a499e8ffa3", HYUNDAI.HYUNDAI_KONA_2ND_GEN),
CarTestRoute("97ca61196eb73e0d/00000052--4555329470", HYUNDAI.HYUNDAI_KONA_HEV_2ND_GEN),
CarTestRoute("baf39eeaba1217ca/00000002--b36e3fa031", HYUNDAI.KIA_K4_2025),
CarTestRoute("c4a804b067623789/0000007c--163f831540", HYUNDAI.KIA_K5_2025),
CarTestRoute("8bae07514ce06ad4/00000008--9f43d90441", CHRYSLER.RAM_HD_5TH_GEN), # 2024 Ram HD with alt cruise buttons
]
+9 -12
View File
@@ -44,7 +44,6 @@ RELAY_TRANSITION_TIMEOUT_US = 10_000_000
DOWNLOAD_CACHE_ROOT = Path(os.environ.get("COMMA_CACHE", "/tmp/comma_download_cache"))
OPENPILOT_CI_URL = "https://commadataci.blob.core.windows.net/openpilotci"
COMMA_API_URL = "https://api.commadotai.com"
SUNNYPILOT_CAR_SEGMENTS_URL = "https://huggingface.co/datasets/sunnypilot/sunnypilotCarSegments/resolve/main/segments"
def get_test_cases() -> list[tuple[str, CarTestRoute | None]]:
@@ -68,19 +67,17 @@ def get_cached_segment(route: str, segment: int) -> Path:
pass
canonical_route = route.replace("/", "|")
try:
with urlopen(f"{COMMA_API_URL}/v1/route/{quote(canonical_route, safe='')}/files") as response:
route_files = json.load(response)
for url in route_files["logs"]:
path = Path(urlparse(url).path)
if path.parent.name == str(segment) and path.name.startswith("rlog."):
return get_cached_url(url)
except (OSError, ValueError):
pass
with urlopen(f"{COMMA_API_URL}/v1/route/{quote(canonical_route, safe='')}/files") as response:
route_files = json.load(response)
for url in route_files["logs"]:
path = Path(urlparse(url).path)
if path.parent.name == str(segment) and path.name.startswith("rlog."):
return get_cached_url(url)
try:
return get_cached_url(f"{SUNNYPILOT_CAR_SEGMENTS_URL}/{route.replace('|', '/')}/{segment}/rlog.zst")
except OSError:
from openpilot.sunnypilot.tools.lib.sunnypilot_car_segments import get_url
return get_cached_url(get_url(route, segment))
except (ImportError, OSError):
pass
raise FileNotFoundError(f"no log found for {route}/{segment}")
@@ -119,5 +119,12 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"HONDA_HRV_3G" = [2.5, 1.2, 0.2]
# port extensions
"HYUNDAI_KONA_2ND_GEN" = [2.5, 2.5, 0.1]
"HYUNDAI_KONA_HEV_2ND_GEN" = [2.5, 2.5, 0.1]
"KIA_SORENTO_2024" = [2.5, 2.5, 0.1]
"KIA_K5_2025" = [2.5, 2.5, 0.1]
"KIA_K4_2025" = [2.5, 2.5, 0.1]
"HYUNDAI_SANTA_CRUZ_2025" = [2.5, 2.5, 0.1]
"HYUNDAI_IONIQ_5_N" = [2.5, 2.5, 0.005]
"HONDA_CLARITY" = [0.96, 0.4018518740819229, 0.19]
"CHEVROLET_MALIBU_NON_ACC_9TH_GEN" = [1.85, 1.85, 0.075]
@@ -96,12 +96,15 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"KIA_FORTE_2021_NON_SCC" = "HYUNDAI_SONATA"
"KIA_SELTOS_2023_NON_SCC" = "HYUNDAI_SONATA"
"HYUNDAI_KONA_NON_SCC" = "HYUNDAI_KONA_EV"
"HYUNDAI_KONA_2ND_GEN" = "HYUNDAI_KONA_EV_2ND_GEN"
"HYUNDAI_ELANTRA_2022_NON_SCC" = "HYUNDAI_ELANTRA_2021"
"GENESIS_G70_2021_NON_SCC" = "HYUNDAI_SONATA"
"HYUNDAI_BAYON_1ST_GEN_NON_SCC" = "HYUNDAI_SONATA"
"HYUNDAI_VENUE_2021_NON_SCC" = "HYUNDAI_KONA_EV"
"HYUNDAI_SONATA_2024" = "HYUNDAI_SONATA_HYBRID"
"HYUNDAI_SONATA_HEV_2024" = "HYUNDAI_SONATA_HYBRID"
"HYUNDAI_SONATA_2024" = "HYUNDAI_SONATA"
"HYUNDAI_TUCSON_2025" = "HYUNDAI_TUCSON_4TH_GEN"
"HYUNDAI_TUCSON_HEV_2025" = "HYUNDAI_TUCSON_4TH_GEN"
"HYUNDAI_TUCSON_PHEV_2025" = "HYUNDAI_TUCSON_4TH_GEN"
"CHEVROLET_BOLT_NON_ACC_2ND_GEN" = "CHEVROLET_BOLT_EUV"
"CHEVROLET_BOLT_NON_ACC" = "CHEVROLET_BOLT_EUV"
"CHEVROLET_BOLT_NON_ACC_1ST_GEN" = "CHEVROLET_BOLT_EUV"
@@ -951,7 +951,7 @@ CM_ SG_ 1041 COUNTER_ALT "only increments on change";
CM_ BO_ 1043 "Lamp signals do not seem universal on cars that use LKAS_ALT, but stalk signals do.";
CM_ SG_ 1043 COUNTER_ALT "only increments on change";
CM_ SG_ 1043 USE_ALT_LAMP "likely 1 on cars that use alt lamp signals";
VAL_ 53 GEAR 0 "P" 5 "D" 6 "N" 7 "R";
VAL_ 53 GEAR 0 "P" 4 "S" 5 "D" 6 "N" 7 "R";
VAL_ 64 GEAR 0 "P" 5 "D" 6 "N" 7 "R";
VAL_ 69 GEAR 0 "P" 5 "D" 6 "N" 7 "R";
VAL_ 96 TRACTION_AND_STABILITY_CONTROL 0 "On" 5 "Limited" 1 "Off";
@@ -6,9 +6,6 @@
#define HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(bus) \
{0x1CF, bus, 8, .check_relay = false}, /* CRUISE_BUTTON */ \
#define HYUNDAI_CANFD_CRUISE_BUTTON_ALT_TX_MSGS(bus) \
{0x1AA, bus, 16, .check_relay = false}, /* CRUISE_BUTTONS_ALT */ \
#define HYUNDAI_CANFD_LKA_STEER_MSG_COMMON_TX_MSGS(a_can, e_can) \
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(e_can) \
{0x50, a_can, 16, .check_relay = (a_can) == 0}, /* LKAS */ \
@@ -171,8 +168,8 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
}
// cruise buttons check
if (((msg->addr == 0x1cfU) || (msg->addr == 0x1aaU)) && !(hyundai_ccnc && hyundai_camera_scc && hyundai_longitudinal)) {
int button = (msg->addr == 0x1cfU) ? (msg->data[2] & 0x7U) : ((msg->data[4] >> 4) & 0x7U);
if ((msg->addr == 0x1cfU) && !(hyundai_ccnc && hyundai_camera_scc && hyundai_longitudinal)) {
int button = msg->data[2] & 0x7U;
bool is_cancel = (button == HYUNDAI_BTN_CANCEL);
bool is_resume = (button == HYUNDAI_BTN_RESUME);
bool is_set = (button == HYUNDAI_BTN_SET);
@@ -235,16 +232,6 @@ static safety_config hyundai_canfd_init(uint16_t param) {
HYUNDAI_CANFD_LKA_STEER_MSG_ALT_COMMON_TX_MSGS(0, 1)
};
static const CanMsg HYUNDAI_CANFD_LKA_STEER_MSG_ALT_BUTTONS_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEER_MSG_COMMON_TX_MSGS(0, 1)
HYUNDAI_CANFD_CRUISE_BUTTON_ALT_TX_MSGS(1)
};
static const CanMsg HYUNDAI_CANFD_LKA_STEER_MSG_ALT_ALT_BUTTONS_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEER_MSG_ALT_COMMON_TX_MSGS(0, 1)
HYUNDAI_CANFD_CRUISE_BUTTON_ALT_TX_MSGS(1)
};
static const CanMsg HYUNDAI_CANFD_LKA_STEER_MSG_LONG_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEER_MSG_COMMON_TX_MSGS(0, 1)
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(1)
@@ -317,6 +304,15 @@ static safety_config hyundai_canfd_init(uint16_t param) {
{0xEA, 2, 24, .check_relay = true}, // MDPS
};
static CanMsg hyundai_canfd_lfa_steering_camera_scc_ccnc_alt_buttons_tx_msgs[] = {
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0)
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(0, true)
{0x1AA, 2, 16, .check_relay = true}, // CRUISE_BUTTONS_ALT
{0x161, 0, 32, .check_relay = true}, // CCNC_0x161
{0x162, 0, 32, .check_relay = true}, // CCNC_0x162
{0xEA, 2, 24, .check_relay = true}, // MDPS
};
if (hyundai_canfd_alt_buttons) {
SET_RX_CHECKS(hyundai_canfd_alt_buttons_long_rx_checks, ret);
} else {
@@ -324,7 +320,9 @@ static safety_config hyundai_canfd_init(uint16_t param) {
}
if (hyundai_camera_scc) {
if (hyundai_ccnc) {
if (hyundai_ccnc && hyundai_canfd_alt_buttons) {
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_ccnc_alt_buttons_tx_msgs, ret);
} else if (hyundai_ccnc) {
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_ccnc_tx_msgs, ret);
} else {
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_tx_msgs, ret);
@@ -337,30 +335,17 @@ static safety_config hyundai_canfd_init(uint16_t param) {
if (hyundai_canfd_lka_steer_msg) {
// *** LKA steering checks ***
// E-CAN is on bus 1, SCC messages are sent on cars with ADRV ECU.
// Does not use the alt buttons message
static RxCheck hyundai_canfd_lka_steer_msg_rx_checks[] = {
HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(1)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
};
static RxCheck hyundai_canfd_lka_steer_msg_alt_buttons_rx_checks[] = {
HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(1)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
};
if (hyundai_canfd_alt_buttons) {
SET_RX_CHECKS(hyundai_canfd_lka_steer_msg_alt_buttons_rx_checks, ret);
if (hyundai_canfd_lka_steer_msg_alt) {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEER_MSG_ALT_ALT_BUTTONS_TX_MSGS, ret);
} else {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEER_MSG_ALT_BUTTONS_TX_MSGS, ret);
}
SET_RX_CHECKS(hyundai_canfd_lka_steer_msg_rx_checks, ret);
if (hyundai_canfd_lka_steer_msg_alt) {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEER_MSG_ALT_TX_MSGS, ret);
} else {
SET_RX_CHECKS(hyundai_canfd_lka_steer_msg_rx_checks, ret);
if (hyundai_canfd_lka_steer_msg_alt) {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEER_MSG_ALT_TX_MSGS, ret);
} else {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEER_MSG_TX_MSGS, ret);
}
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEER_MSG_TX_MSGS, ret);
}
} else if (!hyundai_camera_scc) {
// Radar sends SCC messages on these cars instead of camera
@@ -184,30 +184,6 @@ class TestHyundaiCanfdLKASteeringAltEV(TestHyundaiCanfdBase):
SCC_BUS = 1
STEER_MSG = "LKAS_ALT"
GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL")
class HyundaiCanfdLKASteeringAltButtonsMixin:
def _button_msg(self, buttons, main_button=0, bus=None):
values = {
"CRUISE_BUTTONS": buttons,
"ADAPTIVE_CRUISE_MAIN_BTN": main_button,
}
return self.packer.make_can_msg_safety("CRUISE_BUTTONS_ALT", self.PT_BUS if bus is None else bus, values)
def _lkas_button_msg(self, enabled):
values = {"LDA_BTN": enabled}
return self.packer.make_can_msg_safety("CRUISE_BUTTONS_ALT", self.PT_BUS, values)
class TestHyundaiCanfdLKASteeringAltButtonsHybrid(HyundaiCanfdLKASteeringAltButtonsMixin, TestHyundaiCanfdLKASteeringEV):
SAFETY_PARAM = HyundaiSafetyFlags.CANFD_LKA_STEER_MSG | HyundaiSafetyFlags.HYBRID_GAS | HyundaiSafetyFlags.CANFD_ALT_BUTTONS
TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0], [0x1AA, 1]]
GAS_MSG = ("ACCELERATOR_ALT", "ACCELERATOR_PEDAL")
class TestHyundaiCanfdLKASteeringAltAltButtonsHybrid(HyundaiCanfdLKASteeringAltButtonsMixin, TestHyundaiCanfdLKASteeringAltEV):
SAFETY_PARAM = HyundaiSafetyFlags.CANFD_LKA_STEER_MSG | HyundaiSafetyFlags.HYBRID_GAS | HyundaiSafetyFlags.CANFD_LKA_STEER_MSG_ALT | \
HyundaiSafetyFlags.CANFD_ALT_BUTTONS
TX_MSGS = [[0x110, 0], [0x1CF, 1], [0x362, 0], [0x1AA, 1]]
GAS_MSG = ("ACCELERATOR_ALT", "ACCELERATOR_PEDAL")
class TestHyundaiCanfdLKASteeringLongEV(HyundaiLongitudinalBase, TestHyundaiCanfdLKASteeringEV):
SAFETY_PARAM = HyundaiSafetyFlags.CANFD_LKA_STEER_MSG | HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.EV_GAS
@@ -334,5 +310,34 @@ class TestHyundaiCanfdLFASteeringCCNCLong(TestHyundaiCanfdLFASteeringLongBase, T
self.assertTrue(self._tx(self._button_msg(btn, main_button=main_btn, bus=self.BUTTONS_TX_BUS)))
@parameterized_class(CAMERA_SCC_COMBOS)
class TestHyundaiCanfdLFASteeringCCNCLongAltButtons(TestHyundaiCanfdLFASteeringCCNCLong, TestHyundaiCanfdLFASteeringAltButtonsBase):
TX_MSGS = [[0x12A, 0], [0x1E0, 0], [0x1AA, 2], [0x1A0, 0], [0x161, 0], [0x162, 0], [0xEA, 2]]
RELAY_MALFUNCTION_ADDRS = {0: (0x12A, 0x1E0, 0x1A0, 0x161, 0x162), 2: (0x1AA, 0xEA)}
FWD_BLACKLISTED_ADDRS = {0: [0x1AA, 0xEA], 2: [0x12A, 0x1E0, 0x1A0, 0x161, 0x162]}
@classmethod
def setUpClass(cls):
super().setUpClass()
if cls.__name__ == "TestHyundaiCanfdLFASteeringCCNCLongAltButtons":
cls.packer = None
raise unittest.SkipTest
@property
def SAFETY_PARAM(self):
return HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.CANFD_ALT_BUTTONS | self.EXTRA_SAFETY_PARAM
def _button_msg(self, buttons, main_button=0, bus=None):
values = {
"CRUISE_BUTTONS": buttons,
"ADAPTIVE_CRUISE_MAIN_BTN": main_button,
}
return self.packer.make_can_msg_safety("CRUISE_BUTTONS_ALT", self.PT_BUS if bus is None else bus, values)
def test_acc_cancel(self):
pass
if __name__ == "__main__":
unittest.main()
+110 -25
View File
@@ -1657,6 +1657,16 @@
],
"package": "Highway Driving Assist"
},
"Hyundai Ioniq 5 N (with HDA II) 2024": {
"platform": "HYUNDAI_IONIQ_5_N",
"make": "Hyundai",
"brand": "hyundai",
"model": "Ioniq 5 N (with HDA II)",
"year": [
"2024"
],
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Ioniq 6 (with HDA II) 2023-24": {
"platform": "HYUNDAI_IONIQ_6",
"make": "Hyundai",
@@ -1811,6 +1821,16 @@
],
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Kona Electric (without HDA II) 2024": {
"platform": "HYUNDAI_KONA_EV_2ND_GEN",
"make": "Hyundai",
"brand": "hyundai",
"model": "Kona Electric (without HDA II)",
"year": [
"2024"
],
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Kona Electric Non-SCC 2019": {
"platform": "HYUNDAI_KONA_EV_NON_SCC",
"make": "Hyundai",
@@ -1831,6 +1851,18 @@
],
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Kona Hybrid (without HDA II) 2024-26": {
"platform": "HYUNDAI_KONA_HEV_2ND_GEN",
"make": "Hyundai",
"brand": "hyundai",
"model": "Kona Hybrid (without HDA II)",
"year": [
"2024",
"2025",
"2026"
],
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Kona Non-SCC 2019": {
"platform": "HYUNDAI_KONA_NON_SCC",
"make": "Hyundai",
@@ -1875,6 +1907,16 @@
],
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Santa Cruz (without HDA II) 2025": {
"platform": "HYUNDAI_SANTA_CRUZ_2025",
"make": "Hyundai",
"brand": "hyundai",
"model": "Santa Cruz (without HDA II)",
"year": [
"2025"
],
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Santa Fe 2019-20": {
"platform": "HYUNDAI_SANTA_FE",
"make": "Hyundai",
@@ -1954,7 +1996,7 @@
"2025",
"2026"
],
"package": "All"
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Sonata Hybrid 2020-23": {
"platform": "HYUNDAI_SONATA_HYBRID",
@@ -1970,7 +2012,7 @@
"package": "All"
},
"Hyundai Sonata Hybrid (without HDA II) 2024-26": {
"platform": "HYUNDAI_SONATA_2024",
"platform": "HYUNDAI_SONATA_HEV_2024",
"make": "Hyundai",
"brand": "hyundai",
"model": "Sonata Hybrid (without HDA II)",
@@ -1979,7 +2021,7 @@
"2025",
"2026"
],
"package": "All"
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Staria 2023": {
"platform": "HYUNDAI_STARIA_4TH_GEN",
@@ -2022,6 +2064,17 @@
],
"package": "All"
},
"Hyundai Tucson (without HDA II) 2025-26": {
"platform": "HYUNDAI_TUCSON_2025",
"make": "Hyundai",
"brand": "hyundai",
"model": "Tucson (without HDA II)",
"year": [
"2025",
"2026"
],
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Tucson Diesel 2019": {
"platform": "HYUNDAI_TUCSON",
"make": "Hyundai",
@@ -2045,7 +2098,7 @@
"package": "All"
},
"Hyundai Tucson Hybrid (without HDA II) 2025-26": {
"platform": "HYUNDAI_TUCSON_4TH_GEN",
"platform": "HYUNDAI_TUCSON_HEV_2025",
"make": "Hyundai",
"brand": "hyundai",
"model": "Tucson Hybrid (without HDA II)",
@@ -2065,6 +2118,16 @@
],
"package": "All"
},
"Hyundai Tucson Plug-in Hybrid (without HDA II) 2025": {
"platform": "HYUNDAI_TUCSON_PHEV_2025",
"make": "Hyundai",
"brand": "hyundai",
"model": "Tucson Plug-in Hybrid (without HDA II)",
"year": [
"2025"
],
"package": "Smart Cruise Control (SCC)"
},
"Hyundai Veloster 2019-20": {
"platform": "HYUNDAI_VELOSTER",
"make": "Hyundai",
@@ -2132,17 +2195,6 @@
],
"package": "Smart Cruise Control (SCC)"
},
"Kia Carnival Hybrid (with HDA II) 2025-26": {
"platform": "KIA_CARNIVAL_4TH_GEN",
"make": "Kia",
"brand": "hyundai",
"model": "Carnival Hybrid (with HDA II)",
"year": [
"2025",
"2026"
],
"package": "Highway Driving Assist II"
},
"Kia Ceed 2019-21": {
"platform": "KIA_CEED",
"make": "Kia",
@@ -2244,6 +2296,27 @@
],
"package": "No Smart Cruise Control (Non-SCC)"
},
"Kia K4 (with HDA II) 2025": {
"platform": "KIA_K4_2025",
"make": "Kia",
"brand": "hyundai",
"model": "K4 (with HDA II)",
"year": [
"2025"
],
"package": "Smart Cruise Control (SCC)"
},
"Kia K4 (without HDA II) 2025-26": {
"platform": "KIA_K4_2025",
"make": "Kia",
"brand": "hyundai",
"model": "K4 (without HDA II)",
"year": [
"2025",
"2026"
],
"package": "Smart Cruise Control (SCC)"
},
"Kia K5 2021-24": {
"platform": "KIA_K5_2021",
"make": "Kia",
@@ -2257,6 +2330,17 @@
],
"package": "Smart Cruise Control (SCC)"
},
"Kia K5 (without HDA II) 2025-26": {
"platform": "KIA_K5_2025",
"make": "Kia",
"brand": "hyundai",
"model": "K5 (without HDA II)",
"year": [
"2025",
"2026"
],
"package": "Smart Cruise Control (SCC)"
},
"Kia K5 Hybrid 2020-22": {
"platform": "KIA_K5_HEV_2020",
"make": "Kia",
@@ -2434,16 +2518,6 @@
],
"package": "Smart Cruise Control (SCC)"
},
"Kia Niro Plus EV 2024": {
"platform": "KIA_NIRO_EV",
"make": "Kia",
"brand": "hyundai",
"model": "Niro Plus EV",
"year": [
"2024"
],
"package": "Smart Cruise Control (SCC)"
},
"Kia Optima 2017": {
"platform": "KIA_OPTIMA_G4",
"make": "Kia",
@@ -2517,6 +2591,17 @@
],
"package": "Smart Cruise Control (SCC)"
},
"Kia Sorento (without HDA II) 2024-25": {
"platform": "KIA_SORENTO_2024",
"make": "Kia",
"brand": "hyundai",
"model": "Sorento (without HDA II)",
"year": [
"2024",
"2025"
],
"package": "Smart Cruise Control (SCC)"
},
"Kia Sorento Hybrid 2021-23": {
"platform": "KIA_SORENTO_HEV_4TH_GEN",
"make": "Kia",
@@ -95,9 +95,6 @@ class CarStateExt:
self.msg_162 = copy.copy(cp_cam.vl["CCNC_0x162"])
self.mdps = copy.copy(cp.vl["MDPS"])
self.cruise_info = copy.copy(cp_cam.vl["SCC_CONTROL"])
self.cruise_buttons_msg = copy.copy(cp.vl["CRUISE_BUTTONS"])
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS and self.CP.flags & HyundaiFlags.CANFD_LKA_STEER_MSG:
self.cruise_buttons_msg = copy.copy(cp.vl[self.cruise_btns_msg_canfd])
ret_sp.speedLimit = self.update_speed_limit(cp, cp_cam) * speed_factor
@@ -10,12 +10,11 @@ from opendbc.car import DT_CTRL
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.common.filter_simple import FirstOrderFilter
from opendbc.car.crc import CRC8J1850, mk_crc8_fun
from opendbc.car.hyundai.values import HyundaiFlags, Buttons
from opendbc.car.hyundai.values import HyundaiFlags
from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
cruise_buttons_checksum = mk_crc8_fun(CRC8J1850, init_crc=0x97, xor_out=0x97) # mk_crc8_fun xors init with xor_out: register starts at 0
CANCEL_BUTTON_DELAY_FRAMES = 10 # 100 ms
MAIN_PRESS_FRAMES = 12 # 120 ms
OVERRIDE_BLINK_FRAMES = 100
OVERRIDE_BLINK_ON_FRAMES = 60
@@ -39,7 +38,7 @@ def create_ccnc_mdps(packer, CAN, mdps):
def create_ccnc_0x161(packer, CAN, frame, msg_161, enabled, lat_active, paused, long_enabled, main_cruise_enabled, gas_override,
hud_control, set_speed, v_ego, lead_visible, show_distance_bars):
values = msg_161.copy()
values = {k: v for k, v in msg_161.items() if k != "COUNTER"}
values.update({
"LKA_ICON": 4 if lat_active else 3,
@@ -91,7 +90,7 @@ def create_ccnc_0x161(packer, CAN, frame, msg_161, enabled, lat_active, paused,
def create_ccnc_0x162(packer, CAN, msg_162, enabled, long_enabled, main_cruise_enabled, gas_override, lead_visible, lead_distance):
values = msg_162.copy()
values = {k: v for k, v in msg_162.items() if k != "COUNTER"}
if long_enabled:
values.update({
@@ -103,7 +102,7 @@ def create_ccnc_0x162(packer, CAN, msg_162, enabled, long_enabled, main_cruise_e
return packer.make_can_msg("CCNC_0x162", CAN.ECAN, values)
def create_ccnc_buttons(packer, CAN, cruise_buttons_msg, main_btn):
def create_ccnc_buttons(packer, CAN, cruise_buttons_msg, main_btn, alt_buttons, counter):
values = cruise_buttons_msg.copy()
values.update({
@@ -111,49 +110,23 @@ def create_ccnc_buttons(packer, CAN, cruise_buttons_msg, main_btn):
"NORMAL_CRUISE_MAIN_BTN": 0,
})
if alt_buttons:
return packer.make_can_msg("CRUISE_BUTTONS_ALT", CAN.CAM, values)
values["COUNTER"] = counter
dat = packer.make_can_msg("CRUISE_BUTTONS", CAN.CAM, values)[1]
values["_CHECKSUM"] = cruise_buttons_checksum(dat[1:])
return packer.make_can_msg("CRUISE_BUTTONS", CAN.CAM, values)
def create_ccnc_alt_buttons(packer, CAN, cruise_buttons_msg, cnt, btn):
values = cruise_buttons_msg.copy()
values.update({
"COUNTER": cnt,
"CRUISE_BUTTONS": btn,
})
return packer.make_can_msg("CRUISE_BUTTONS_ALT", CAN.ECAN, values)
class CcncCarController:
def __init__(self, CP, CP_SP):
self.ccnc_lfa_steering = bool(CP_SP.flags & HyundaiFlagsSP.CCNC and not (CP.flags & HyundaiFlags.CANFD_LKA_STEER_MSG))
self.ccnc_lka_alt_buttons = bool(CP_SP.flags & HyundaiFlagsSP.CCNC and CP.flags & HyundaiFlags.CANFD_LKA_STEER_MSG and
CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS)
self.lead_distance_filter = FirstOrderFilter(TARGET_DISTANCE_MAX, LEAD_FILTER_RC, 5 * DT_CTRL, initialized=False)
self.lead_distance_bars_last = None
self.distance_bar_frame = 0
def create_alt_button_msgs(self, CS, CC):
can_sends = []
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
btn = None
if CC.cruiseControl.cancel:
if self.cancel_counter > CANCEL_BUTTON_DELAY_FRAMES:
btn = Buttons.CANCEL
elif CC.cruiseControl.resume:
btn = Buttons.RES_ACCEL
if btn is not None:
for _ in range(10):
can_sends.append(create_ccnc_alt_buttons(self.packer, self.CAN, CS.cruise_buttons_msg, CS.buttons_counter + 1, btn))
self.last_button_frame = self.frame
return can_sends
self.buttons_counter = 0
@staticmethod
def _get_set_speed(v_cruise_cluster, is_metric):
@@ -166,9 +139,6 @@ class CcncCarController:
def update(self, CS, CC):
can_sends = []
if self.ccnc_lka_alt_buttons:
return self.create_alt_button_msgs(CS, CC)
if not self.ccnc_lfa_steering:
return can_sends
@@ -181,7 +151,9 @@ class CcncCarController:
if self.frame % 2 == 0 and self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC:
press_main = CS.cruise_info["MainMode_ACC"] and self.frame % (2 * MAIN_PRESS_FRAMES) < MAIN_PRESS_FRAMES
can_sends.append(create_ccnc_buttons(self.packer, self.CAN, CS.cruise_buttons_msg, press_main))
can_sends.append(create_ccnc_buttons(self.packer, self.CAN, CS.cruise_buttons_msg, press_main,
self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS, self.buttons_counter))
self.buttons_counter = (self.buttons_counter + 1) % 15 # stock counts 0-14
if self.frame % 5 == 0:
if not self.lead_visible:
@@ -131,14 +131,11 @@ FW_VERSIONS_EXT = {
b'\xf1\x00QX MFC AT USA LHD 1.00 1.01 99211-K2000 191014',
],
},
CAR.HYUNDAI_SONATA_2024: {
CAR.HYUNDAI_SONATA_HEV_2024: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DN8HMFC AT KOR LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8HMFC AT USA LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8HMFC AT USA LHD 1.00 1.02 99211-L1800 250613',
b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.02 99211-L1800 250613',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DN8_ RDR ----- 1.00 1.00 99110-L1800 ',
@@ -146,7 +143,6 @@ FW_VERSIONS_EXT = {
},
CAR.HYUNDAI_KONA_2ND_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00SX2 MFC AT AUS RHD 1.00 1.03 99211-BE000 230517',
b'\xf1\x00SX2 MFC AT USA LHD 1.00 1.03 99211-BE000 230517',
b'\xf1\x00SX2 MFC AT USA LHD 1.00 1.07 99211-BE000 240611',
],
@@ -155,16 +151,51 @@ FW_VERSIONS_EXT = {
b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE500 ',
],
},
CAR.KIA_CARNIVAL_4TH_GEN: {
CAR.HYUNDAI_KONA_HEV_2ND_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00KA4HMFC AT USA LHD 1.00 1.00 99210-R0700 250324',
b'\xf1\x00KA4HMFC AT USA LHD 1.00 1.05 99210-R0500 240305',
b'\xf1\x00SX2HMFC AT AUS RHD 1.00 1.00 99211-BE001 241015',
b'\xf1\x00SX2HMFC AT AUS RHD 1.00 1.01 99211-BE001 250117',
b'\xf1\x00SX2HMFC AT EUR LHD 1.00 1.01 99211-BE001 250117',
b'\xf1\x00SX2HMFC AT EUR RHD 1.00 1.04 99211-BE000 231010',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00KAhe RDR ----- 1.00 1.01 99110-ES500 ',
b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE000 ',
b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE500 ',
],
},
CAR.HYUNDAI_TUCSON_4TH_GEN: {
CAR.HYUNDAI_SONATA_2024: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.02 99211-L1800 250613',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DN8_ RDR ----- 1.00 1.00 99110-L1800 ',
],
},
CAR.HYUNDAI_IONIQ_5_N: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NE1N RDR ----- 1.00 1.00 99110-NI000 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NE1NMFC AT KOR LHD 1.00 1.04 99211-NI000 231219',
b'\xf1\x00NE1NMFC AT KOR LHD 1.00 1.00 99211-NI010 240712',
b'\xf1\x00NE1NMFC AT USA LHD 1.00 1.04 99211-NI000 231219',
b'\xf1\x00NE1NMFC AT USA LHD 1.00 1.00 99211-NI110 250404',
],
},
CAR.HYUNDAI_TUCSON_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT GEN LHD 1.00 1.00 99211-N7030 C55',
b'\xf1\x00NX4 FR_CMR AT GEN LHD 1.00 1.00 99211-N7035 C5C',
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N7050 C5A',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NX4__ 1.00 1.02 99110N7000 ',
b'\xf1\x00NX4__ 1.00 1.03 99110N7100 ',
],
},
CAR.HYUNDAI_TUCSON_HEV_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N7030 C55',
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N7030 C55',
@@ -177,31 +208,54 @@ FW_VERSIONS_EXT = {
b'\xf1\x00NX4__ 1.00 1.03 99110N7100 ',
],
},
CAR.KIA_SELTOS: {
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00SP2 MDPS C 1.00 1.04 56310Q5840 4SPSC104',
],
CAR.HYUNDAI_TUCSON_PHEV_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00SP2 MFC AT AUS RHD 1.00 1.03 99210-Q5500 230208',
b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.00 99211-N7030 C55',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00SP2_ SCC F-CUP 1.00 1.01 99110-Q5500 ',
b'\xf1\x00NX4__ 1.00 1.02 99110N7100 ',
],
},
CAR.KIA_NIRO_EV: {
CAR.HYUNDAI_SANTA_CRUZ_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N7030 C55',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DEev SCC FHCUP 1.00 1.00 99110-Q4510 ',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00DE MDPS C 1.00 1.06 56310Q4200\x00 4DEEC106',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DEE MFC AT KOR LHD 1.00 1.00 99211-DB100 211206',
b'\xf1\x00NX4__ 1.00 1.00 99110K5500 ',
],
},
CAR.HYUNDAI_KONA_EV: {
CAR.KIA_K4_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00OE2 LKAS AT EUR RHD 1.00 1.00 95740-K4200 200',
b'\xf1\x00CL4 MFC AT CAN LHD 1.00 1.02 99210-GG000 240708',
b'\xf1\x00CL4 MFC AT USA LHD 1.00 1.02 99210-GG000 240708',
b'\xf1\x00CL4 MFC AT USA LHD 1.00 1.04 99210-GG100 251205',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00CL4_ RDR ----- 1.00 1.01 99110-GG000 ',
b'\xf1\x00CL4_ RDR ----- 1.00 1.01 99110-GG100 ',
],
},
CAR.KIA_K5_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DL3 MFC AT USA LHD 1.00 1.04 99210-L2500 240117',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DL3_ RDR ----- 1.00 1.01 99110-L2500 ',
],
},
CAR.KIA_SORENTO_2024: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00MQ4 MFC AT AUS RHD 1.01 1.04 99210-P2550 231127',
b'\xf1\x00MQ4 MFC AT USA LHD 1.01 1.04 99210-R5500 231127',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00MQ4_ RDR ----- 1.00 1.01 99110-P2500 ',
b'\xf1\x00MQ4_ RDR ----- 1.00 1.01 99110-R5500 ',
],
},
CAR.HYUNDAI_KONA_EV_2ND_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00SX2EMFC AT USA LHD 1.00 1.02 99211-BF000 230823',
],
},
}
Binary file not shown.
+2
View File
@@ -162,6 +162,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CarParamsSPCache", {CLEAR_ON_MANAGER_START, BYTES}},
{"CarParamsSPPersistent", {PERSISTENT, BYTES}},
{"CarPlatformBundle", {PERSISTENT | BACKUP, JSON}},
{"CcncPortEolAck", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"ChevronInfo", {PERSISTENT | BACKUP, INT, "4"}},
{"CompletedSunnylinkConsentVersion", {PERSISTENT, STRING, "0"}},
{"CustomAccIncrementsEnabled", {PERSISTENT | BACKUP, BOOL, "0"}},
@@ -184,6 +185,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"MaxTimeOffroad", {PERSISTENT | BACKUP, INT, "1800"}},
{"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}},
{"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}},
{"Offroad_CcncPortEol", {CLEAR_ON_MANAGER_START, JSON}},
{"Offroad_TiciSupport", {CLEAR_ON_MANAGER_START, JSON}},
{"OnroadScreenOffBrightness", {PERSISTENT | BACKUP, INT, "0"}},
{"OnroadScreenOffBrightnessMigrated", {PERSISTENT | BACKUP, STRING, "0.0"}},
Binary file not shown.
@@ -1,4 +1,8 @@
{
"Offroad_CcncPortEol": {
"text": "This branch will not receive any more functional updates. ccNC support is moving to master. See the ccNC Port topic on community.sunnypilot.ai for what you need to do.",
"severity": 1
},
"Offroad_TemperatureTooHigh": {
"text": "Device temperature too high. System cooling down before starting. Current internal component temperature: %1",
"severity": 0
+3
View File
@@ -10,6 +10,7 @@ from openpilot.selfdrive.ui.onroad.augmented_road_view import AugmentedRoadView
from openpilot.selfdrive.ui.ui_state import device, ui_state
from openpilot.selfdrive.ui.layouts.onboarding import OnboardingWindow
from openpilot.selfdrive.ui.body.layouts.onroad import BodyLayout
from openpilot.selfdrive.ui.sunnypilot.layouts.ccnc_port_eol import CcncPortEolGate, CcncPortEolNotice
if gui_app.sunnypilot_ui():
from openpilot.selfdrive.ui.sunnypilot.layouts.settings.settings import SettingsLayoutSP as SettingsLayout
@@ -54,6 +55,8 @@ class MainLayout(Widget):
if not self._onboarding_window.completed:
gui_app.push_widget(self._onboarding_window)
self._ccnc_port_eol = CcncPortEolGate(self, CcncPortEolNotice)
def _render(self, _):
self._handle_onroad_transition()
self._render_main_content()
@@ -7,6 +7,8 @@ from openpilot.selfdrive.ui.mici.onroad.augmented_road_view import AugmentedRoad
from openpilot.selfdrive.ui.ui_state import device, ui_state
from openpilot.selfdrive.ui.mici.layouts.onboarding import OnboardingWindow
from openpilot.selfdrive.ui.body.layouts.onroad import BodyLayout
from openpilot.selfdrive.ui.sunnypilot.layouts.ccnc_port_eol import CcncPortEolGate
from openpilot.selfdrive.ui.sunnypilot.mici.layouts.ccnc_port_eol import MiciCcncPortEolNotice
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.scroller import Scroller
from openpilot.system.ui.lib.application import gui_app
@@ -64,6 +66,8 @@ class MiciMainLayout(Scroller):
if not self._onboarding_window.completed:
gui_app.push_widget(self._onboarding_window)
self._ccnc_port_eol = CcncPortEolGate(self, MiciCcncPortEolNotice)
# initialize correct onroad layout
self._on_body_changed()
@@ -0,0 +1,146 @@
"""
Copyright (c) 2021-, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
import subprocess
from collections.abc import Callable
import pyray as rl
from openpilot.common.qrcode import make_texture
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.application import FontWeight, TextAlignment, TextAlignmentVertical, gui_app
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.button import Button, ButtonStyle
from openpilot.system.ui.widgets.label import Label
CCNC_PORT_EOL_URL = "https://community.sunnypilot.ai/t/ccnc-port-non-hda2-hda2-supported-vehicles-features/1064/337?u=sunnyhaibin"
SWITCH_BRANCH = "staging"
# Merged into master and built into staging. Keyed on ccnc-port platform names, which never change; the FW is the
# camera and radar FW master also lists, so a car whose FW master lacks is not sent to a branch that won't recognize it.
CCNC_PORT_SUPPORTED: dict[str, tuple[str, set[bytes]]] = {
"HYUNDAI_SONATA_HEV_2024": ("Hyundai Sonata Hybrid 2024-26", {
b'\xf1\x00DN8HMFC AT KOR LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8HMFC AT USA LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8HMFC AT USA LHD 1.00 1.02 99211-L1800 250613',
b'\xf1\x00DN8_ RDR ----- 1.00 1.00 99110-L1800 ',
}),
"HYUNDAI_SONATA_2024": ("Hyundai Sonata 2024-26", {
b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.02 99211-L1800 250613',
b'\xf1\x00DN8_ RDR ----- 1.00 1.00 99110-L1800 ',
}),
"HYUNDAI_TUCSON_HEV_2025": ("Hyundai Tucson Hybrid 2025-26", {
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N7030 C55',
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N7030 C55',
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N7035 C5C',
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N7060 C5B',
b'\xf1\x00NX4__ 1.00 1.02 99110N7000 ',
b'\xf1\x00NX4__ 1.00 1.02 99110N7100 ',
b'\xf1\x00NX4__ 1.00 1.03 99110N7100 ',
}),
"HYUNDAI_KONA_2ND_GEN": ("Hyundai Kona 2024-25", {
b'\xf1\x00SX2 MFC AT USA LHD 1.00 1.03 99211-BE000 230517',
b'\xf1\x00SX2 MFC AT USA LHD 1.00 1.07 99211-BE000 240611',
b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE000 ',
b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE500 ',
}),
}
def supported_car_name() -> str | None:
CP = ui_state.CP
if CP is None or CP.carFingerprint not in CCNC_PORT_SUPPORTED:
return None
name, fw_versions = CCNC_PORT_SUPPORTED[CP.carFingerprint]
seen = {(str(fw.ecu), fw.fwVersion) for fw in CP.carFw if str(fw.ecu) in ("fwdCamera", "fwdRadar") and not fw.logging}
if {ecu for ecu, _ in seen} != {"fwdCamera", "fwdRadar"} or any(v not in fw_versions for _, v in seen):
return None
return name
class CcncPortEolGate:
# The ack param clears on boot and on every offroad transition, so the notice is shown again after each drive.
def __init__(self, main: Widget, notice_cls: Callable[[Callable[[], None], Callable[[], None], str | None], Widget]):
self._main = main
self._notice_cls = notice_cls
self._notice: Widget | None = None
self._acked = False
gui_app.add_nav_stack_tick(self._tick)
def _tick(self):
if ui_state.started:
self._acked = False
elif not self._acked and gui_app.get_active_widget() is self._main:
# built per drive: CarParamsPersistent first appears after the device's first drive
self._notice = self._notice_cls(self._on_ack, self._on_switch, supported_car_name())
gui_app.push_widget(self._notice)
def _on_ack(self):
self._acked = True
ui_state.params.put_bool("CcncPortEolAck", True, block=True)
gui_app.pop_widgets_to(self._main, instant=True)
def _on_switch(self):
ui_state.params.put("UpdaterTargetBranch", SWITCH_BRANCH, block=True)
subprocess.run(["pkill", "-SIGUSR1", "-f", "openpilot.system.updated.updated"], check=False)
self._on_ack()
class CcncPortEolNotice(Widget):
def __init__(self, on_ack: Callable[[], None], on_switch: Callable[[], None], car_name: str | None):
super().__init__()
self._car_name = car_name
if car_name:
title = tr("Your car is now officially supported")
desc = tr("ccnc-port will not receive any more functional updates. Your car is supported on sunnypilot master.\n\n" +
"Switch to staging to keep getting updates. Scan the QR code for details.")
else:
title = tr("This branch is no longer updated")
desc = tr("ccnc-port will not receive any more functional updates. ccNC support is moving to master.\n\n" +
"Scan the QR code to see what you need to do.")
self._title = Label(title, font_size=75, font_weight=FontWeight.BOLD,
text_alignment=TextAlignment.LEFT, text_alignment_vertical=TextAlignmentVertical.TOP)
self._car = Label(car_name or "", font_size=55, font_weight=FontWeight.MEDIUM, text_color=rl.Color(150, 150, 150, 255),
text_alignment=TextAlignment.LEFT, text_alignment_vertical=TextAlignmentVertical.TOP)
self._desc = Label(desc, font_size=55, font_weight=FontWeight.MEDIUM,
text_alignment=TextAlignment.LEFT, text_alignment_vertical=TextAlignmentVertical.TOP)
self._ack_btn = Button(tr("Not now") if car_name else tr("I understand"),
button_style=ButtonStyle.NORMAL if car_name else ButtonStyle.PRIMARY, click_callback=on_ack)
self._switch_btn = Button(tr("Switch to staging"), button_style=ButtonStyle.PRIMARY, click_callback=on_switch)
self._qr_texture = make_texture(CCNC_PORT_EOL_URL)
def _render(self, rect: rl.Rectangle):
rl.draw_rectangle_rec(rect, rl.BLACK)
qr_size = 560
qr_x = rect.x + rect.width - qr_size - 90
text_x = rect.x + 90
text_w = qr_x - text_x - 60
if self._car_name:
self._title.render(rl.Rectangle(text_x, rect.y + 90, text_w, 100))
self._car.render(rl.Rectangle(text_x, rect.y + 190, text_w, 80))
self._desc.render(rl.Rectangle(text_x, rect.y + 330, text_w, 450))
else:
self._title.render(rl.Rectangle(text_x, rect.y + 90, text_w, 200))
self._desc.render(rl.Rectangle(text_x, rect.y + 300, text_w, 450))
if self._qr_texture:
src = rl.Rectangle(0, 0, self._qr_texture.width, self._qr_texture.height)
rl.draw_texture_pro(self._qr_texture, src, rl.Rectangle(qr_x, rect.y + 90, qr_size, qr_size), rl.Vector2(0, 0), 0, rl.WHITE)
btn_y = rect.y + rect.height - 160 - 45
if self._car_name:
btn_w = (rect.width - 90 - 30) / 2
self._ack_btn.render(rl.Rectangle(rect.x + 45, btn_y, btn_w, 160))
self._switch_btn.render(rl.Rectangle(rect.x + 45 + btn_w + 30, btn_y, btn_w, 160))
else:
self._ack_btn.render(rl.Rectangle(rect.x + 45, btn_y, rect.width - 90, 160))
def __del__(self):
if self._qr_texture and self._qr_texture.id != 0:
rl.unload_texture(self._qr_texture)
@@ -0,0 +1,46 @@
"""
Copyright (c) 2021-, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
from collections.abc import Callable
import pyray as rl
from openpilot.selfdrive.ui.mici.layouts.onboarding import QRCodeWidget
from openpilot.selfdrive.ui.mici.widgets.dialog import BigConfirmationCircleButton
from openpilot.selfdrive.ui.sunnypilot.layouts.ccnc_port_eol import CCNC_PORT_EOL_URL
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.mici_setup import GreyBigButton
from openpilot.system.ui.widgets.scroller import Scroller
class MiciCcncPortEolNotice(Scroller):
def __init__(self, on_ack: Callable[[], None], on_switch: Callable[[], None], car_name: str | None):
super().__init__()
check = gui_app.texture("icons_mici/setup/driver_monitoring/dm_check.png", 64, 64)
if car_name:
self._scroller.add_widgets([
GreyBigButton("officially\nsupported", "scroll to continue",
gui_app.texture("icons_mici/setup/green_info.png", 64, 64)),
GreyBigButton(car_name.lower(), "is supported on master"),
GreyBigButton("", "ccnc-port is no longer updated."),
GreyBigButton("switch to staging", "to keep getting updates"),
BigConfirmationCircleButton("switch to\nstaging", gui_app.texture("icons_mici/settings/device/update.png", 64, 64), on_switch),
GreyBigButton("scan the QR code", "for details"),
QRCodeWidget(CCNC_PORT_EOL_URL),
BigConfirmationCircleButton("not\nnow", check, on_ack),
])
else:
self._scroller.add_widgets([
GreyBigButton("no longer\nupdated", "scroll to continue",
gui_app.texture("icons_mici/setup/green_info.png", 64, 64)),
GreyBigButton("", "ccnc-port will not receive any more functional updates. ccNC support is moving to master."),
GreyBigButton("scan the QR code", "to see what to do"),
QRCodeWidget(CCNC_PORT_EOL_URL),
BigConfirmationCircleButton("I\nunderstand", check, on_ack),
])
def _render(self, _):
rl.draw_rectangle_rec(self._rect, rl.BLACK)
super()._render(_)
+1 -1
View File
@@ -1 +1 @@
#define SUNNYPILOT_VERSION "2026.11.15-5034"
#define SUNNYPILOT_VERSION "2026.11.13-5031"
+4 -12
View File
@@ -17,25 +17,16 @@ def main():
parser.add_argument("--frame", required=True, help="width,height,stride,y_height,uv_height,buffer_size")
parser.add_argument("--warp-to", required=True, help="model input WxH")
parser.add_argument("--output", required=True)
parser.add_argument("--split-frames", action="store_true", help="one input per camera (frame, big_frame), bound to the camera buffers by pointer")
args = parser.parse_args()
from examples.openpilot.compile_warp import make_frame_prepare, parse_frame, parse_size
from tinygrad import Device, Tensor, TinyJit
frame = parse_frame(args.frame)
warp = make_frame_prepare(frame, *parse_size(args.warp_to))
run = TinyJit(lambda input_frame, M_inv: Tensor.stack(*(warp(input_frame[i], M_inv[i]) for i in range(2))), prune=True)
rng = np.random.default_rng(42)
frames = rng.integers(0, 256, (2, frame.size), dtype=np.uint8)
m_inv = Tensor((rng.standard_normal((2, 3, 3)) * 8).astype(np.float32), device=Device.DEFAULT).realize()
if args.split_frames:
run = TinyJit(lambda frame, big_frame, M_inv: Tensor.stack(warp(frame, M_inv[0]), warp(big_frame, M_inv[1])), prune=True)
inputs = {"frame": Tensor(frames[0], device=Device.DEFAULT).realize(), "big_frame": Tensor(frames[1], device=Device.DEFAULT).realize(), "M_inv": m_inv}
specs = {"frame": ((frame.size,), "|u1", Device.DEFAULT), "big_frame": ((frame.size,), "|u1", Device.DEFAULT),
"M_inv": ((2, 3, 3), "<f4", Device.DEFAULT)}
else:
run = TinyJit(lambda input_frame, M_inv: Tensor.stack(*(warp(input_frame[i], M_inv[i]) for i in range(2))), prune=True)
inputs = {"input_frame": Tensor(frames, device=Device.DEFAULT).realize(), "M_inv": m_inv}
specs = {"input_frame": ((2, frame.size), "|u1", Device.DEFAULT), "M_inv": ((2, 3, 3), "<f4", Device.DEFAULT)}
inputs = {"input_frame": Tensor(rng.integers(0, 256, (2, frame.size), dtype=np.uint8), device=Device.DEFAULT).realize(),
"M_inv": Tensor((rng.standard_normal((2, 3, 3)) * 8).astype(np.float32), device=Device.DEFAULT).realize()}
with record_kernel_linear() as recorded:
run(**inputs)
run(**inputs)
@@ -43,6 +34,7 @@ def main():
assert len(recorded) == 1, f"expected one captured kernel list, got {len(recorded)}"
part = serialize_jit(run, recorded[0], check)
PlainJit(*part)
specs = {"input_frame": ((2, frame.size), "|u1", Device.DEFAULT), "M_inv": ((2, 3, 3), "<f4", Device.DEFAULT)}
write_bundle(args.output, {"run": part}, {"input_specs": specs, "metadata": {}})
print(f"Saved warp to {args.output} ({len(part[0]['calls'])} kernels)")
@@ -12,8 +12,6 @@ from functools import partial
from openpilot.common.basedir import BASEDIR
from openpilot.sunnypilot.modeld_v2.helpers import _dtype, read_parts
SPLIT_FRAMES = ("big_frame", "frame")
def pack_layout(shapes: dict[str, tuple], frame_size: int) -> tuple[dict[str, int], int]:
offsets, offset = {}, 0
@@ -41,30 +39,29 @@ def frame_part(warp_path: str, parts: dict, extras: dict) -> dict:
(model, model_blob), (warp, warp_blob) = parts["run"], read_parts(warp_path)[0]["run"]
states = sorted(name for name in extras["input_specs"] if f"next_{name}" in extras["metadata"]["output_shapes"])
host = {name: shape for name, (shape, _, _) in extras["input_specs"].items() if name not in states and name != "new_img"}
frame_specs = {s["name"]: s for s in warp["inputs"] if s["name"] in SPLIT_FRAMES}
offsets, packed = pack_layout(host, 0 if frame_specs else next(s["numel"] for s in warp["inputs"] if s["name"] == "input_frame") // 2)
frame_size = next(s["numel"] for s in warp["inputs"] if s["name"] == "input_frame") // 2
offsets, packed = pack_layout(host, frame_size)
shift, upload, u8 = len(model_blob), len(model["buffers"]) + len(warp["buffers"]), repr(_dtype("dtypes.uint8"))
def view(name: str, nbytes: int, dtype: str) -> dict:
return {"buffer": upload, "offset": offsets[name], "nbytes": nbytes, "dtype": dtype}
outputs = sorted(s["slot"] for s in model["inputs"] if s["name"] is None)
names = sorted(["host", *states, *frame_specs])
names = sorted(["host", *states])
slots = {s["slot"]: names.index(s["name"]) for s in model["inputs"] if s["name"] in states} | \
{slot: len(names) + i for i, slot in enumerate(outputs)}
returned = warp["returns"]["tensors"][0]
model_inputs = {s["slot"]: {"input": slots[s["slot"]]} if s["slot"] in slots else
{k: v for k, v in returned.items() if k != "shape"} | {"buffer": returned["buffer"] + len(model["buffers"])} if s["name"] == "new_img" else
view(s["name"], s["numel"] * _dtype(s["dtype"]).itemsize, s["dtype"]) for s in model["inputs"]}
warp_inputs = {s["slot"]: {"input": names.index(s["name"])} if s["name"] in frame_specs else
view("frames" if s["name"] == "input_frame" else "tfm", s["numel"] * _dtype(s["dtype"]).itemsize, s["dtype"]) for s in warp["inputs"]}
warp_inputs = {s["slot"]: view("frames" if s["name"] == "input_frame" else "tfm", s["numel"] * _dtype(s["dtype"]).itemsize, s["dtype"])
for s in warp["inputs"]}
def remap(calls: list, inputs: dict, buffers: int, lib: int) -> list:
return [call | ({"lib": [call["lib"][0] + lib, call["lib"][1] + lib]} if "lib" in call else {}) |
{"args": [dict(inputs[a["input"]]) if "input" in a else a | {"buffer": a["buffer"] + buffers} for a in call["args"]]} for call in calls]
header = {"input_names": names, "returns": {"kind": "NoneType", "tensors": []}, "check": None,
"inputs": [{"slot": names.index("host"), "name": "host", "dtype": u8, "numel": packed, "device": "NPY"}] +
[s | {"slot": slots[s["slot"]]} for s in model["inputs"] if s["slot"] in slots] +
[s | {"slot": names.index(name)} for name, s in frame_specs.items()],
[s | {"slot": slots[s["slot"]]} for s in model["inputs"] if s["slot"] in slots],
"buffers": model["buffers"] + [b | ({"init": [b["init"][0] + shift, b["init"][1] + shift]} if "init" in b else {}) for b in warp["buffers"]] +
[{"nbytes": packed, "device": model["inputs"][0]["device"], "dtype": u8}],
"calls": [{"kind": "copy", "args": [{"buffer": upload, "offset": 0, "nbytes": packed, "dtype": u8}, {"input": names.index("host")}]}] +
+1 -18
View File
@@ -270,32 +270,15 @@ def _program_uop(call: dict, lib: bytes):
UOp(Ops.SOURCE, arg=""), UOp(Ops.BINARY, arg=lib)), arg=info)
def _input_tensors(kwargs: dict) -> list: # in _prepare_jit_inputs' order
from tinygrad import Tensor
tensors = [t for _, t in sorted(kwargs.items()) if t.__class__ is Tensor]
for value in kwargs.values():
tensors += [t for t in (value.values() if isinstance(value, dict) else value if isinstance(value, (tuple, list)) else ())
if t.__class__ is Tensor and not any(t is y for y in tensors)]
return tensors
class _Jit:
def __init__(self, captured, input_names: list, buffers: list):
self.captured, self.input_names, self.buffers = captured, input_names, buffers
def __call__(self, *args, **kwargs):
import tinygrad.engine.jit as jit
from tinygrad.uop.ops import Ops
# same names, no variables: the binding is the tensors' own uops, without _prepare_jit_inputs' graph rewrites
if not args and self.__dict__.get("_names") == sorted(kwargs):
tensors = _input_tensors(kwargs)
if all(t.uop.is_realized for t in tensors):
return self.captured([t.uop.src[0] if t.uop.op is Ops.UNSHARD else t.uop for t in tensors], {})
input_uops, var_vals, names, _ = jit._prepare_jit_inputs(args, kwargs)
if names != self.input_names:
raise ValueError(f"expected inputs {self.input_names}, got {names}")
if not args and not var_vals:
self._names = sorted(kwargs)
return self.captured(input_uops, var_vals)
@@ -328,7 +311,7 @@ class PlainJit(_Jit):
calls.append(_program_uop(call, bytes(blob[slice(*call["lib"])])).call(*arguments))
else:
calls.append(arguments[0].store_call(arguments[1]))
# allocate gpu buffers
# stand-ins for JIT inputs: copy staging to GPU is decided from the input buffers, the real ones bind per call
stand_ins = {slot: UOp.from_buffer(Buffer(_device(spec["device"], device_map), spec["numel"] * _dtype(spec["dtype"]).itemsize).ensure_allocated(),
_dtype(spec["dtype"])) for slot, spec in inputs.items()}
input_uops = tuple(stand_ins.get(slot, next(iter(stand_ins.values()), None)) for slot in range(max(stand_ins, default=-1) + 1))
@@ -11,7 +11,7 @@ import pickle
import numpy as np
from openpilot.common.basedir import BASEDIR
from openpilot.sunnypilot.modeld_v2.frame_fusion import pack_layout, SPLIT_FRAMES
from openpilot.sunnypilot.modeld_v2.frame_fusion import pack_layout
from openpilot.sunnypilot.modeld_v2.helpers import load_model
from openpilot.sunnypilot.modeld_v2.compile_modeld import (POLICY_INPUTS, derive_frame_skip,
make_split_input_queues, make_supercombo_input_queues)
@@ -169,18 +169,16 @@ class NativeTinygradAdapter(BaseModelAdapter):
self.warp_frame_size = self.frame_copy_size
self._init_common()
self.run_model = self.jits['run']
self.split = [name for name in SPLIT_FRAMES if name in self.run_model.input_names]
self.frame_inputs: dict[str, Tensor] = {}
self.input_queues = {name: Tensor(np.zeros(shape, dtype=dtype), device=self.model_device).realize()
for name, (shape, dtype) in self.input_shapes.items() if name in self.state_pairs}
shapes = {name: shape for name, (shape, _) in self.input_shapes.items() if name not in self.state_pairs and name != 'new_img'}
offsets, packed = pack_layout(shapes, 0 if self.split else self.warp_frame_size)
offsets, packed = pack_layout(shapes, self.warp_frame_size)
self.packed_input = np.zeros(packed, dtype=np.uint8)
self.host = Tensor(self.packed_input, device='NPY')
self.numpy_inputs = {name: np.ndarray(shape, dtype=np.float32, buffer=self.packed_input, offset=offsets[name])
for name, shape in ({'tfm': (2, 3, 3)} | shapes).items()}
self.frames = self.packed_input[offsets['frames']:].reshape(2, -1)
self.frames = self.packed_input[offsets['frames']:].reshape(2, self.warp_frame_size)
self.outputs = {name: Tensor(np.zeros(shape, dtype=dtype), device=device).realize() for name, (shape, dtype, device) in self.jits['output_specs'].items()}
for name, next_name in self.state_pairs.items():
@@ -189,29 +187,17 @@ class NativeTinygradAdapter(BaseModelAdapter):
def copy_frames(self, bufs):
for i, key in enumerate(self._vision_input_names):
if key not in bufs:
continue
if not self.split:
if key in bufs:
data = bufs[key].data if hasattr(bufs[key], 'data') else bufs[key]
np.copyto(self.frames[i], np.frombuffer(data, dtype=np.uint8, count=self.warp_frame_size))
elif (name := ('frame', 'big_frame')[i]) in self.split:
if isinstance(bufs[key], np.ndarray): # cached memory: the GPU would read stale lines in place
self.frame_inputs[name] = Tensor(np.ascontiguousarray(bufs[key][:self.warp_frame_size]), device=self.model_device).realize()
continue
ptr = np.frombuffer(bufs[key].data, dtype=np.uint8).ctypes.data # visionipc buffers are coherent
if (key, ptr) not in self._blob_cache:
self._blob_cache[(key, ptr)] = Tensor.from_blob(ptr, (self.warp_frame_size,), dtype='uint8', device=self.model_device)
self.frame_inputs[name] = self._blob_cache[(key, ptr)]
def reset_warmup_buffers(self) -> None:
self.packed_input[:] = 0
self.frame_inputs.clear()
self._blob_cache.clear()
for key in self.state_pairs:
self.input_queues[key].assign(0).realize()
def run(self):
self.run_model(host=self.host, **self.input_queues, **self.frame_inputs, output_buffers=self.outputs)
self.run_model(host=self.host, **self.input_queues, output_buffers=self.outputs)
return self.outputs['outputs']
@@ -144,21 +144,6 @@ class TestPlainArtifact(OpenpilotTestCase):
for name in ("outputs", "next_state_feat_q"):
assert np.array_equal(inputs["output_buffers"][name].numpy(), expected["output_buffers"][name].numpy()), name
split_path = os.path.join(self.tmp.name, "warp_split_tinygrad.pkl")
with mock.patch.object(sys, "argv", ["compile_warp", "--frame", FRAME, "--warp-to", f"{MODEL_W}x{MODEL_H}", "--output", split_path, "--split-frames"]):
compile_warp.main()
split = load_model(path, cache=False, extend=functools.partial(frame_part, split_path))
assert split["run"].input_names == ["big_frame", "frame", "host", "state_feat_q"]
offsets, packed = pack_layout(HOST, 0)
host = np.zeros(packed, np.uint8)
for name, shape in ({"tfm": (2, 3, 3)} | HOST).items():
np.ndarray(shape, np.float32, host, offsets[name])[...] = tfm.numpy() if name == "tfm" else inputs[name].numpy()
out = {"outputs": Tensor.zeros(OUT).contiguous().realize(), "next_state_feat_q": Tensor.zeros(STATE).contiguous().realize()}
split["run"](host=Tensor(host, device="NPY"), frame=Tensor(frames.numpy()[0]).realize(), big_frame=Tensor(frames.numpy()[1]).realize(),
state_feat_q=expected["state_feat_q"], output_buffers=out)
for name in ("outputs", "next_state_feat_q"):
assert np.array_equal(out[name].numpy(), expected["output_buffers"][name].numpy()), name
def test_tinygrad_api_the_loader_reads(self):
import tinygrad.engine.jit as jit
from tinygrad.device import Buffer, TinyELF
Binary file not shown.
+13 -16
View File
@@ -19,9 +19,10 @@ from openpilot.tools.lib.route import Route
REPO_ID = os.environ.get("SUNNYPILOT_CAR_SEGMENTS_REPO_ID", "sunnypilot/sunnypilotCarSegments")
def upload_route(route_name: str, dry_run: bool = False, local_dir: str | None = None) -> None:
log_paths = Route(route_name, data_dir=local_dir).log_paths()
valid_segments = [(i, path) for i, path in enumerate(log_paths) if path is not None]
def upload_route(route_name: str, dry_run: bool = False) -> None:
route = Route(route_name)
log_paths = route.log_paths()
valid_segments = [(i, url) for i, url in enumerate(log_paths) if url is not None]
print(f"Route: {route_name}")
print(f"Segments: {len(valid_segments)}/{len(log_paths)}")
@@ -33,17 +34,14 @@ def upload_route(route_name: str, dry_run: bool = False, local_dir: str | None =
api = HfApi()
with tempfile.TemporaryDirectory() as tmpdir:
for seg_idx, src in tqdm(valid_segments, desc="Uploading"):
filename = src.split("?")[0].rsplit("/", 1)[-1]
if local_dir is not None:
local_path = src
else:
local_path = os.path.join(tmpdir, f"{seg_idx}_{filename}")
resp = requests.get(src, stream=True)
resp.raise_for_status()
with open(local_path, "wb") as f:
for chunk in resp.iter_content(chunk_size=8192):
f.write(chunk)
for seg_idx, url in tqdm(valid_segments, desc="Uploading"):
filename = url.split("?")[0].rsplit("/", 1)[-1]
local_path = os.path.join(tmpdir, f"{seg_idx}_{filename}")
resp = requests.get(url, stream=True)
resp.raise_for_status()
with open(local_path, "wb") as f:
for chunk in resp.iter_content(chunk_size=8192):
f.write(chunk)
repo_path = f"segments/{route_name.replace('|', '/')}/{seg_idx}/{filename}"
@@ -65,7 +63,6 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Upload route rlogs to sunnypilot HuggingFace dataset")
parser.add_argument("route", help="Route ID (e.g. 5beb9b58bd12b691/0000010a--a51155e496)")
parser.add_argument("--dry-run", action="store_true", help="Download and show sizes without uploading")
parser.add_argument("--local", metavar="DIR", help="Upload rlogs from DIR (<dongle id>|<log id>--<segment>/) instead of the comma API")
args = parser.parse_args()
upload_route(args.route, dry_run=args.dry_run, local_dir=args.local)
upload_route(args.route, dry_run=args.dry_run)
Binary file not shown.
+2
View File
@@ -252,6 +252,7 @@ def hardware_thread(end_event, hw_queue) -> None:
chestnut = Chestnut()
chestnut_status = ChestnutStatus()
branch = get_short_branch()
set_offroad_alert("Offroad_CcncPortEol", True)
while not end_event.is_set():
sm.update(PANDA_STATES_TIMEOUT)
@@ -353,6 +354,7 @@ def hardware_thread(end_event, hw_queue) -> None:
startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get_bool("DisableUpdates") or params.get_bool("SnoozeUpdate")
startup_conditions["no_excessive_actuation"] = params.get("Offroad_ExcessiveActuation") is None
startup_conditions["ccnc_port_eol_ack"] = params.get_bool("CcncPortEolAck")
startup_conditions["not_uninstalling"] = not params.get_bool("DoUninstall")
startup_conditions["accepted_terms"] = params.get("HasAcceptedTerms") == terms_version
startup_conditions["accepted_terms_sp"] = params.get("HasAcceptedTermsSP") == terms_version_sp
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.