diff --git a/CHANGELOGS-DEV.md b/CHANGELOGS-DEV.md
new file mode 100644
index 000000000..c8ef6bee0
--- /dev/null
+++ b/CHANGELOGS-DEV.md
@@ -0,0 +1,366 @@
+2020-05-10 (dp 0.7.5 v2)
+========================
+* 基於最新 openpilot 0.7.5 devel-staging.
+* Based on latest openpilot 0.7.5 devel-staging.
+* 更新 dp 圖示 (特別感謝 @wabes 的設計與提供)。
+* Updated dp logo, special thanks to @wabes for the design.
+* 簡/繁中文版和 i18n 整合成為單一版本。
+* Merged zhs/zht/i18n versions into one.
+* 新增大陸版 CAMRY HYBRID 指紋v2。(感謝 @杜子腾)
+* Added China Camery Hybrid FPv2. (Thanks to @杜子腾)
+* 新增台灣版 Altis HYBRID 指紋v1。(感謝 @Fish)
+* Added Taiwan Altis Hybrid FPv1. (Thanks to @Fish)
+* 新增行駛時關閉畫面功能。
+* Added Screen off while driving feature.
+* 新增倒車時關閉畫面功能。
+* Added Screen off while reversing feature.
+* 新增駕駛介面加入「加速模式」切換鈕。
+* Added acceleration profile toggle onto driving UI.
+* 新增自定車型功能,取代指紋暫存功能。
+* Replaced fingerprint cache with custom car model selector.
+* 新增可調亮度。
+* Added Brightness changer.
+* 新增部分德語支持。(特別感謝 @arne182 提供)
+* Added partial de_DE language support (Thanks to @arne182)
+* 新增停車碰撞偵測記錄功能。
+* Added off road impact detection to dashcam.
+
+2020-05-06
+========================
+* 更新 dp 圖示 (特別感謝 @wabes 的設計與提供)。
+* 中文版整合進 i18n 版。
+* 刪除指紋暫存功能。
+* 新增 CAMERY HIBRID 指紋。(感謝 @杜子腾)
+* 新增行駛時關閉畫面功能。
+* 新增倒車時關閉畫面功能。
+* 新增駕駛介面加入「加速模式」切換鈕。
+* 新增自定義車型。
+
+2020-04-16
+========================
+* [DEVEL] 加入台灣版 2016 Lexus IS200t 指紋。(感謝 Philip / Cody Dai)
+* [DEVEL] 加入台灣版 2016 Toyota Prius 4.5 代指紋。(感謝 Philip)
+* [DEVEL] 加入台灣版 201x Toyota RAV4 4WD 指紋。(感謝 Philip)
+* [DEVEL] 加入台灣版 2020 Toyota Auris w/ LTA 指紋。(感謝 Philip)
+* [DEVEL] 修正 commIssue 錯誤。(感謝 Kent 協助)
+
+2020-04-13
+========================
+* [DEVEL] 加入可調整 Toyota Sng 起步反應值 (DragonToyotaSngResponse)。 (特別感謝 @Wei 提供 PR)
+* [DEVEL] 駕駛介面加入「動態調整車距」按鈕。(感謝 @cgw1968-5779 建議)
+* [DEVEL] 更新 update script。(感謝 深鯨希西 回報)
+
+2020-04-10
+========================
+* [DEVEL] 更新 panda 至最新的 comma:master 分支。
+* [DEVEL] 移除所有的第三方應用改為自動下載。
+* [DEVEL] 移除「啟用原廠 DSU 模式」、「安全帶檢查」、「車門檢查」開關。
+
+2020-03-31
+========================
+* [DEVEL] 更新至 2020-03-31 testing 分支。
+
+2020-03-27
+========================
+* [DEVEL] 更新至最新的 testing 分支:
+ * 加入波蘭版 2015 Lexus NX200T 支援。(感謝 wabes 提供)
+ * 調整「啟用原廠 DSU 模式」為不再需要 AHB 。(Enable Stock DSU Mode no longer requires "AHB" toggle)
+ * 加入「安全帶檢查」、「車門檢查」、「檔位檢查」、「溫度檢查」開關。
+ * 加入曲率學習功能 - Curvature Learner 。(感謝 zorrobyte 提供)
+ * 加入大陸版 2018 Toyota Highlander 支援。(感謝 toyboxZ 提供)
+ * 加入大陸版 2018 Toyota Camry 2.0 支援。(感謝 Rming 提供)
+ * 加入韓文支持。(感謝 crwusiz 提供)
+ * 調整 OFFROAD 主頁翻譯將 "dragonpilot" 改回 "openpilot"。
+
+2020-03-22
+========================
+* [DEVEL] 更新至最新的 testing 分支。
+
+2020-03-17
+========================
+* [DEVEL] 更新至最新的 testing 分支 (commaai:devel-staging 0.7.4)。
+* [DEVEL] 加入動態調整車距功能。(特別感謝 @ShaneSmiskol 提供 PR)
+
+2020-03-14
+========================
+* [DEVEL] 更新 pt-Br (葡萄牙語) 翻譯。(感謝 berno22 提供)
+* [DEVEL] 加入自動關機開關。(感謝 Rzxd 建議)
+* [DEVEL] 調高 Toyota 扭力容錯值。
+* [DEVEL] 優化讀取 dp 設定值。
+* [DEVEL] 加入 2019 手動 Civic 指紋。感謝 (AlexNoop 提供)
+* [DEVEL] dp 功能加入對 Subaru 車系的支援。
+
+2020-03-06
+========================
+* [DEVEL] 加入葡萄牙語支持。(感謝 berno22 提供)
+* [DEVEL] 加入大陸 2018 Camry、2020 RAV4 指紋。(感謝 笨木匠 提供)
+* [DEVEL] 建立 devel-i18n 取代 devel-en。
+* [DEVEL] devel-en is deprecated, please switch to devel-i18n instead.
+
+2020-03-04
+========================
+* [DEVEL] 加入顯示駕駛監控畫面。
+* [DEVEL] 加入加速模式選項。(特別感謝 @arne182, @cgw1968-5779 提供 PR)
+* [DEVEL] 修正 shutdownd 在 comma two 可能會不正常關機的錯誤。(感謝 @Wei, @Rzxd 回報)
+
+2020-02-25
+========================
+* [DEVEL] 更新至最新的 commaai:devel (0.7.3)。
+
+2020-02-21
+========================
+* [DEVEL] 更新至最新的 commaai:devel (0.7.3)。
+
+2020-02-14
+========================
+* [DEVEL] 更新至最新的 commaai:devel (0.7.2)。
+* [DEVEL] 修正錯誤。
+
+2020-02-08
+========================
+* [DEVEL] 更新至最新的 commaai:devel (0.7.2)。
+* [DEVEL] dp 功能加入對現代 (Hyundai) 車系的支援。
+* [DEVEL] 加入神盾測速照相自動啟動的開關。
+* [DEVEL] 更新高德地圖至 v4.5.0.600053。
+* [DEVEL] 使用 0.6.6 版的更新系統。
+* [DEVEL] 修正急剎問題。(感謝 kumar 提供)
+
+2020-01-31
+========================
+* [DEVEL] 移除行車介面電量、溫度顯示,(修正畫面當機、黑屏問題)
+
+2020-01-29
+========================
+* [DEVEL] 修正行車介面錯誤。(感謝 深鲸希西 測試;eisenheim、HeatNation 反應)
+
+2020-01-23
+========================
+* [DEVEL] 加入 Steer Ratio Learner 關閉。(感謝 eisenheim 建議)
+* [DEVEL] 行車介面加入電量、溫度。(感謝 eisenheim 建議)
+* [DEVEL] 優化 appd。
+
+2020-01-19
+========================
+* [DEVEL] 更新至最新的 commaai:devel (0.7.1)。
+* [DEVEL] 調整 appd 和 ALC 邏輯。
+
+2020-01-14
+========================
+* [DEVEL] 加入開機啟動個人熱點。(感謝 eisenheim 建議)
+
+2020-01-08
+========================
+* [DEVEL] 加入大陸版 2018 Lexus RX300 支援。(感謝 cafe 提供)
+* [DEVEL] 加入 DragonBTG 設定。(感謝 CloudJ、低調哥、歐姓Altis車主 提供)
+
+2019-12-31
+========================
+* [DEVEL-ZHS] 加回第三方應用。
+
+2019-12-29
+========================
+* [DEVEL] 更新至最新的 commaai:devel (0.7.0)。
+* [DEVEL] 輔助/自動變道改為可調整參數 (進階用戶)。(DragonAssistedLCMinMPH、DragonAutoLCMinMPH、DragonAutoLCDelay)
+* [DEVEL-ZHS] 修正無法運行第三方應用錯誤。(感謝 深鲸希西 反應)
+
+2019-12-18
+========================
+* [DEVEL] 修正自動換道邏輯。
+* [DEVEL] 更新 offroad 翻譯。
+* [DEVEL] 錯誤修正。
+* [DEVEL] 移除美版 2017 Civic Hatchback 指紋。(與其它車型衝突)
+
+2019-12-17
+========================
+* [DEVEL] 更新至最新的 commaai:devel (0.7.0)。
+* [DEVEL] 加入輔助換道開關。(24mph / 40kph 以上)
+* [DEVEL] 加入自動換道開關。(40mph / 65kph 以上)
+* [DEVEL] 加入大陸版 2019 雷凌汽油版指紋。 (感謝 Shell 提供)
+* [DEVEL] 加入大陸版 2019 卡羅拉汽油版指紋。 (感謝 Shell 提供)
+* [DEVEL] 加入美版 2017 Civic Hatchback 指紋。(感謝 CFranHonda 提供)
+
+2019-12-10
+========================
+* [DEVEL] 加入位智車機模式。 (Waze Mode)
+
+2019-11-21
+========================
+* [DEVEL] 修正 offroad 翻譯。(感謝 鄧育林 回報)
+* [DEVEL] 調整前車靜止移動偵測參數。
+* [DEVEL] 前車靜止移動偵測可在未啟用 dp 時運作。
+
+2019-11-18
+========================
+* [DEVEL] 修正 offroad 翻譯。(感謝 Cody、鄧育林 回報)
+
+2019-11-18
+========================
+* [DEVEL] 修正 frame 翻譯。
+
+2019-11-15
+========================
+* [DEVEL] 修正不會充電的錯誤。 (感謝 袁昊 反應)
+
+2019-11-15
+========================
+* [DEVEL] 修正充電控制。 (感謝 KT 反應)
+* [DEVEL] 更新 frame 翻譯,改為多語言版。 (感謝 深鲸希西、shaoching885、鄧育林 反應)
+* [DEVEL] 更新至最新的 commaai:devel (0.6.6)。
+
+2019-11-12
+========================
+* [DEVEL] 只顯示電量文字 (注意:有時不會更新,需要拔插 USB 線)
+* [DEVEL] 自動偵測並鎖定硬體 (EON / UNO)。
+
+2019-11-12
+========================
+* [DEVEL] 加入鎖定硬體 (EON / UNO) 的程式碼。
+
+2019-11-11
+========================
+* [DEVEL] 更新高德地圖至 v4.3.0.600310 R2098NSLAE
+* [DEVEL] 更新 MiXplorer 至 v6.40.3
+* [DEVEL] 更新至最新的 commaai:devel (0.6.6)。
+* [DEVEL] 前車靜止移動偵測加入偵測警示。
+
+2019-11-07
+========================
+* [DEVEL] 讓 Bosch 系統顯示三角。 (感謝 ching885 回報)
+* [DEVEL] 更新 offroad 多語言版簡體中文翻譯 (感謝 Rming 提供)
+
+2019-11-06
+========================
+* [DEVEL] 修正 0.6.6 appd 和 dashcamd 錯誤。 (感謝 鄧育林 回報)
+* [DEVEL] 更新至最新的 commaai:devel (0.6.6)。
+
+2019-11-05
+========================
+* [DEVEL] 加入台灣 Lexus 2017 GS450h 支援。 (感謝 簡銘佑 提供指紋)
+
+2019-11-01
+========================
+* [DEVEL] 新增神盾測速照相。 (感謝 Sky Chang 和 Wei Yi Chen)
+* [DEVEL] 修正 offroad 翻譯。 (感謝 Leo Hsieh)
+
+2019-11-01
+========================
+* [DEVEL] 移除 Miui 字型,縮小 dp 使用空間。
+* [DEVEL] 更新 offroad 為多語言版
+* [DEVEL] 更新至最新的 commaai:devel (0.6.5)。
+
+2019-10-29
+========================
+* [DEVEL] 加入 SnG 補丁。(感謝 楊雅智)
+
+2019-10-28
+========================
+* [DEVEL] 更新至最新的 commaai:devel (0.6.5)。
+* [DEVEL] 調整 dragon_allow_gas 邏輯 (請回報任何問題,需更新 Panda 韌體)
+
+2019-10-18
+========================
+* [DEVEL] 加入前車靜止移動偵測。(測試版,感謝 ucolchen)
+* [DEVEL] 移除強迫網路連線提示。(感謝 Shell)
+* [DEVEL] 修正 allow_gas 功能。
+
+2019-10-18
+========================
+* [DEVEL] 加入彎道減速功能開關。
+* [DEVEL] 強迫使用 dp 版 Panda 韌體。
+* [DEVEL] 更新至最新的 commaai:devel (0.6.5)。
+
+2019-10-17
+========================
+* [DEVEL] 加入「車型」顯示於 dp 設定畫面。
+* [DEVEL] 修正充電控制讀取預設值的錯誤。
+* [DEVEL] 修正無法顯示更新記錄的錯誤。
+
+2019-10-16
+========================
+* [DEVEL] 刷新 Panda 韌體按鈕將會自動重啟 EON。(感謝 鄧育林 建議)
+* [DEVEL] 下載更新記錄時使用 "no-cache" 標頭。
+* [DEVEL] 更新高德地圖至 v4.3.0
+* [DEVEL] 刪除 bs (Branch Switcher)
+
+2019-10-14
+========================
+* [DEVEL] 啟用自動更新功能。(感謝 鄧育林 提供)
+* [DEVEL] 清除不再使用的 dp params。
+* [DEVEL] 加入數字電量指示。(感謝 鄧育林 建議)
+* [DEVEL] 加入刷新 Panda 韌體按鈕。
+
+2019-10-11
+========================
+* [DEVEL] 更新至最新的 commaai:devel (0.6.5)。
+* [DEVEL] 加入台灣 2019 RAV4 汽油版指紋。 (感謝 Max Duan / CloudJ 提供)
+
+2019-10-09
+========================
+* [DEVEL] 加入當 LatCtrl 關閉時,畫面顯示提示訊息。
+
+2019-10-08
+========================
+* [DEVEL] 加回駕駛監控開關。
+* [DEVEL] 加入 bs (branch switcher) 程式。
+
+2019-10-07
+========================
+* [DEVEL] 加入台灣版 2019 RAV4H 油電版指紋。(感謝 Max Duan 提供)
+
+2019-10-05
+========================
+* [DEVEL] 移除 curvature learner: 轉角明顯比原廠小。
+* [DEVEL] 更新至最新的 commaai:devel (0.6.4)。
+
+2019-09-30
+========================
+* [DEVEL] 更新 curvature learner 版本至 v4。
+* [DEVEL] Lexus ISH 使用更精確的 EPS Steering Angle Sensor
+
+2019-09-27
+========================
+* [DEVEL] 加入 Zorrobyte 的 curvature learner (https://github.com/zorrobyte/openpilot)
+* [DEVEL] 加入可開關駕駛監控的程式碼。
+* [DEVEL] 取消當 steering 出現錯誤時,自動切斷方向控制 2 秒的機制。
+* [DEVEL] 讓行車介面的「方向盤」/「轉彎」圖示半透明化。
+
+2019-09-26
+========================
+* [DEVEL] 修正當「啟用記錄服務」關閉時,make 會有問題的錯誤。 (感謝 shaoching885 和 afa 回報)
+
+2019-09-24
+========================
+* [DEVEL] 行車介面加入可開關的「前車」、「路線」、「車道」設定。
+* [DEVEL] 行車介面加入可開關的「方向燈號」提示。 (感謝 CloudJ 建議,程式碼來源: https://github.com/kegman/openpilot)
+
+2019-09-23
+========================
+* [DEVEL] 優化讀取 params 的次數。
+* [DEVEL] 加入可開關的車道偏移警示。
+* [DEVEL] 修正充電控制邏輯。
+* [DEVEL] 加入台灣 Prius 4.5 指紋。 (感謝 Lin Hsin Hung 提供)
+
+2019-09-20
+========================
+* [DEVEL] 加入充電控制功能。 (感謝 loveloveses 和 KT 建議)
+
+2019-09-16
+========================
+* [DEVEL] 加入台灣 CT200h 指紋。 (感謝 CloudJ 提供)
+* [DEVEL] 加入美版 CT200h 移植。 (感謝 thomaspich 提供)
+
+2019-09-13
+========================
+* [DEVEL] 行車介面加入可開關的「速度顯示」設定。
+
+2019-09-09
+========================
+* [DEVEL] 加入 GreyPanda 模式。
+
+2019-08-28
+========================
+* [DEVEL] 加入可調警示音量。
+
+2019-08-27
+========================
+* [DEVEL] 自動關機改為可調時長。
diff --git a/CHANGELOGS-REL.md b/CHANGELOGS-REL.md
new file mode 100644
index 000000000..523855b06
--- /dev/null
+++ b/CHANGELOGS-REL.md
@@ -0,0 +1,144 @@
+dragonpilot 0.7.4
+========================
+* [2020-04-10] 移除所有的第三方應用改為自動下載。
+* [2020-04-10] 移除「啟用原廠 DSU 模式」、「安全帶檢查」、「車門檢查」開關。
+* [2020-03-31] 還原部分修改代碼以達到 comma ai 安全準則。 (Reverted changes to panda safety code to comply with comma ai safety guideline.)
+* [2020-03-31] 調整「啟用原廠 DSU 模式」為踩剎車時會暫時斷開控制 。(Enable Stock DSU Mode will temporary disable controls when brake is pressed.)
+* [2020-03-27] 加入波蘭版 2015 Lexus NX200T 支援。(感謝 wabes 提供)
+* [2020-03-27] 調整「啟用原廠 DSU 模式」為不再需要 AHB 。(Enable Stock DSU Mode no longer requires "AHB" toggle)
+* [2020-03-27] 加入「安全帶檢查」、「車門檢查」、「檔位檢查」、「溫度檢查」開關。
+* [2020-03-27] 加入曲率學習功能 - Curvature Learner 。(感謝 zorrobyte 提供)
+* [2020-03-27] 加入大陸版 2018 Toyota Highlander 支援。(感謝 toyboxZ 提供)
+* [2020-03-27] 加入大陸版 2018 Toyota Camry 2.0 支援。(感謝 Rming 提供)
+* [2020-03-27] 加入韓文支持。(感謝 crwusiz 提供)
+* [2020-03-27] 調整 OFFROAD 主頁翻譯將 "dragonpilot" 改回 "openpilot"。
+
+dragonpilot 0.7.3
+========================
+* [2020-03-17] 加入動態調整車距功能。(特別感謝 @ShaneSmiskol 提供 PR)
+* [2020-03-14] 更新 pt-Br (葡萄牙語) 翻譯。(感謝 berno22 提供)
+* [2020-03-14] 加入自動關機開關。(感謝 Rzxd 建議)
+* [2020-03-14] 調高 Toyota 扭力容錯值。
+* [2020-03-14] 優化讀取 dp 設定值。
+* [2020-03-14] 加入 2019 手動 Civic 指紋。感謝 (AlexNoop 提供)
+* [2020-03-14] dp 功能加入對 Subaru 車系的支援。
+* [2020-03-06] 加入葡萄牙語支持。(感謝 berno22 提供)
+* [2020-03-06] 加入大陸 2018 Camry、2020 RAV4 指紋。(感謝 笨木匠 提供)
+* [2020-03-04] 加入顯示駕駛監控畫面。
+* [2020-03-04] 加入加速模式選項。(特別感謝 @arne182, @cgw1968-5779 提供 PR)
+* [2020-03-04] 修正 shutdownd 在 comma two 可能會不正常關機的錯誤。(感謝 @Wei, @Rzxd 回報)
+
+dragonpilot 0.7.2
+========================
+* [2020-02-08] dp 功能加入對現代 (Hyundai) 車系的支援。
+* [2020-02-08] 加入神盾測速照相自動啟動的開關。
+* [2020-02-08] 更新高德地圖至 v4.5.0.600053。
+* [2020-02-08] 使用 0.6.6 版的更新系統。
+* [2020-02-08] 修正急剎問題。(感謝 kumar 提供)
+* [2020-01-31] 移除行車介面電量、溫度顯示,(修正畫面當機、黑屏問題)
+* [2020-01-29] 修正行車介面錯誤。(感謝 深鲸希西 測試;eisenheim、HeatNation 反應)
+* [2020-01-23] 加入 Steer Ratio Learner 關閉。(感謝 eisenheim 建議)
+* [2020-01-23] 行車介面加入電量、溫度。(感謝 eisenheim 建議)
+* [2020-01-23] 優化 appd。
+
+dragonpilot 0.7.1
+========================
+* [2020-01-19] 調整 appd 和 ALC 邏輯。
+* [2020-01-14] 加入開機啟動個人熱點。(感謝 eisenheim 建議)
+* [2020-01-18] 加入大陸版 2018 Lexus RX300 支援。(感謝 cafe 提供)
+* [2020-01-18] 加入 DragonBTG 設定。(感謝 CloudJ、低調哥、歐姓Altis車主 提供)
+
+dragonpilot 0.7.0
+========================
+* [DEVEL] 更新至最新的 commaai:devel (0.7.0)。
+* [2019-12-29] 輔助/自動變道改為可調整參數 (進階用戶)。(DragonAssistedLCMinMPH、DragonAutoLCMinMPH、DragonAutoLCDelay)
+* [2019-12-29] 修正無法運行第三方應用錯誤。(感謝 深鲸希西 反應)
+* [2019-12-18] 修正自動換道邏輯。
+* [2019-12-18] 更新 offroad 翻譯。
+* [2019-12-18] 錯誤修正。
+* [2019-12-18] 移除美版 2017 Civic Hatchback 指紋。(與其它車型衝突)
+* [2019-12-17] 加入輔助換道開關。(24mph / 40kph 以上)
+* [2019-12-17] 加入自動換道開關。(40mph / 65kph 以上)
+* [2019-12-17] 加入大陸版 2019 雷凌汽油版指紋。 (感謝 Shell 提供)
+* [2019-12-17] 加入大陸版 2019 卡羅拉汽油版指紋。 (感謝 Shell 提供)
+* [2019-12-17] 加入美版 2017 Civic Hatchback 指紋。(感謝 CFranHonda 提供)
+* [2019-12-10] 加入位智車機模式。 (Waze Mode)
+* [2019-11-21] 修正 offroad 翻譯。(感謝 鄧育林 回報)
+* [2019-11-21] 調整前車靜止移動偵測參數。
+* [2019-11-21] 前車靜止移動偵測可在未啟用 dp 時運作。
+* [2019-11-18] 修正 offroad 翻譯。(感謝 Cody、鄧育林 回報)
+* [2019-11-18] 修正 frame 翻譯。
+
+dragonpilot 0.6.6
+========================
+* [2019-11-15] 修正不會充電的錯誤。 (感謝 袁昊 反應)
+* [2019-11-15] 修正充電控制。 (感謝 KT 反應)
+* [2019-11-15] 更新 frame 翻譯,改為多語言版。 (感謝 深鲸希西、shaoching885、鄧育林 反應)
+* [2019-11-12] 只顯示電量文字 (注意:有時不會更新,需要拔插 USB 線)
+* [2019-11-12] 自動偵測並鎖定硬體 (EON / UNO)。
+* [2019-11-12] 加入鎖定硬體 (EON / UNO) 的程式碼。
+* [2019-11-11] 更新高德地圖至 v4.3.0.600310 R2098NSLAE
+* [2019-11-11] 更新 MiXplorer 至 v6.40.3
+* [2019-11-11] 前車靜止移動偵測加入偵測警示。
+* [2019-11-07] 讓 Bosch 系統顯示三角。 (感謝 ching885 回報)
+* [2019-11-07] 更新 offroad 多語言版簡體中文翻譯 (感謝 Rming 提供)
+* [2019-11-06] 修正 0.6.6 appd 和 dashcamd 錯誤。 (感謝 鄧育林 回報)
+
+dragonpilot 0.6.5
+========================
+* [2019-11-05] 加入台灣 Lexus 2017 GS450h 支援。 (感謝 簡銘佑 提供指紋)
+* [2019-11-01] 新增神盾測速照相。 (感謝 Sky Chang 和 Wei Yi Chen)
+* [2019-11-01] 修正 offroad 翻譯。 (感謝 Leo Hsieh)
+* [2019-11-01] 移除 Miui 字型,縮小 dp 使用空間。
+* [2019-11-01] 更新 offroad 為多語言版
+* [2019-10-29] 加入 SnG 補丁。(感謝 楊雅智)
+* [2019-10-28] 調整 dragon_allow_gas 邏輯 (請回報任何問題,需更新 Panda 韌體)
+* [2019-10-22] 移除強迫網路連線提示。(感謝 Shell)
+* [2019-10-18] 加入前車靜止移動偵測。(測試版,感謝 ucolchen)
+* [2019-10-18] 移除強迫網路連線提示。(感謝 Shell)
+* [2019-10-18] 修正 allow_gas 功能。
+* [2019-10-18] 加入彎道減速功能開關。
+* [2019-10-18] 強迫使用 dp 版 Panda 韌體。
+* [2019-10-17] 加入「車型」顯示於 dp 設定畫面。
+* [2019-10-17] 修正充電控制讀取預設值的錯誤。
+* [2019-10-17] 修正無法顯示更新記錄的錯誤。
+* [2019-10-17] 刷新 Panda 韌體按鈕將會自動重啟 EON。(感謝 鄧育林 建議)
+* [2019-10-17] 下載更新記錄時使用 "no-cache" 標頭。
+* [2019-10-17] 更新高德地圖至 v4.3.0
+* [2019-10-14] 啟用自動更新功能。(感謝 鄧育林 提供)
+* [2019-10-14] 清除不再使用的 dp params。
+* [2019-10-14] 加入數字電量指示。(感謝 鄧育林 建議)
+* [2019-10-14] 加入刷新 Panda 韌體按鈕。
+* [2019-10-11] 加入台灣 2019 RAV4 汽油版指紋。 (感謝 Max Duan / CloudJ 提供)
+* [2019-10-11] 加入當 LatCtrl 關閉時,畫面顯示提示訊息。
+
+dragonpilot 0.6.4
+========================
+* [2019-10-11] 加入台灣版 2019 RAV4H 油電版指紋。
+* [2019-10-08] 加回駕駛監控開關。
+* [2019-10-07] 加入台灣版 2019 RAV4H 油電版指紋。(感謝 Max Duan 提供)
+* [2019-10-05] 移除 curvature learner: 轉角明顯比原廠小。
+* [2019-09-30] 更新 curvature learner 版本至 v4。
+* [2019-09-30] Lexus ISH 使用更精確的 EPS Steering Angle Sensor
+* [2019-09-27] 加入 Zorrobyte 的 curvature learner (https://github.com/zorrobyte/openpilot)
+* [2019-09-27] 加入可開關駕駛監控的程式碼。
+* [2019-09-27] 取消當 steering 出現錯誤時,自動切斷方向控制 2 秒的機制。
+* [2019-09-27] 讓行車介面的「方向盤」/「轉彎」圖示半透明化。
+* [2019-09-26] 修正當「啟用記錄服務」關閉時,make 會有問題的錯誤。 (感謝 shaoching885 和 afa 回報)
+* [2019-09-24] 行車介面加入可開關的「前車」、「路線」、「車道」設定。
+* [2019-09-24] 行車介面加入可開關的「方向燈號」提示。 (感謝 CloudJ 建議,程式碼來源: https://github.com/kegman/openpilot)
+* [2019-09-23] 優化讀取 params 的次數。
+* [2019-09-23] 加入可開關的車道偏移警示。
+* [2019-09-23] 修正充電控制邏輯。
+* [2019-09-23] 加入台灣 Prius 4.5 指紋。 (感謝 Lin Hsin Hung 提供)
+* [2019-09-20] 加入充電控制功能。 (感謝 loveloveses 和 KT 建議)
+* [2019-09-16] 加入台灣 CT200h 指紋。 (感謝 CloudJ 提供)
+* [2019-09-16] 加入美版 CT200h 移植。 (感謝 thomaspich 提供)
+* [2019-09-13] 行車介面加入可開關的「速度顯示」設定。
+* [2019-09-09] 加入 GreyPanda 模式。
+* [2019-08-28] 加入可調警示音量。
+* [2019-08-27] 自動關機改為可調時長。
+
+dragonpilot 0.6.3
+========================
+* [2019-10-11] 加入台灣版 2019 RAV4H 油電版指紋。
\ No newline at end of file
diff --git a/CHANGELOGS.md b/CHANGELOGS.md
new file mode 100644
index 000000000..2018d5424
--- /dev/null
+++ b/CHANGELOGS.md
@@ -0,0 +1,26 @@
+2020-05-10 (dp 0.7.5 v2)
+========================
+* 基於最新 openpilot 0.7.5 devel-staging.
+* Based on latest openpilot 0.7.5 devel-staging.
+* 更新 dp 圖示 (特別感謝 @wabes 的設計與提供)。
+* Updated dp logo, special thanks to @wabes for the design.
+* 簡/繁中文版和 i18n 整合成為單一版本。
+* Merged zhs/zht/i18n versions into one.
+* 新增大陸版 CAMRY HYBRID 指紋v2。(感謝 @杜子腾)
+* Added China Camery Hybrid FPv2. (Thanks to @杜子腾)
+* 新增台灣版 Altis HYBRID 指紋v1。(感謝 @Fish)
+* Added Taiwan Altis Hybrid FPv1. (Thanks to @Fish)
+* 新增行駛時關閉畫面功能。
+* Added Screen off while driving feature.
+* 新增倒車時關閉畫面功能。
+* Added Screen off while reversing feature.
+* 新增駕駛介面加入「加速模式」切換鈕。
+* Added acceleration profile toggle onto driving UI.
+* 新增自定車型功能,取代指紋暫存功能。
+* Replaced fingerprint cache with custom car model selector.
+* 新增可調亮度。
+* Added Brightness changer.
+* 新增部分德語支持。(特別感謝 @arne182 提供)
+* Added partial de_DE language support (Thanks to @arne182)
+* 新增停車碰撞偵測記錄功能。
+* Added off road impact detection to dashcam.
\ No newline at end of file
diff --git a/apk/ai.comma.plus.offroad.apk b/apk/ai.comma.plus.offroad.apk
index c6a6af110..7ffe96553 100644
Binary files a/apk/ai.comma.plus.offroad.apk and b/apk/ai.comma.plus.offroad.apk differ
diff --git a/cereal/car.capnp b/cereal/car.capnp
index 3ef711738..cb2039c44 100644
--- a/cereal/car.capnp
+++ b/cereal/car.capnp
@@ -97,6 +97,14 @@ struct CarEvent @0x9b1657f34caf3ad3 {
relayMalfunction @72;
gasPressed @73;
stockFcw @74;
+ # dp
+ preLaneChangeLeftALC @75;
+ preLaneChangeRightALC @76;
+ laneChangeALC @77;
+ manualSteeringRequired @78;
+ manualSteeringRequiredBlinkersOn @79;
+ leadCarMoving @80;
+ leadCarDetected @81;
}
}
@@ -157,6 +165,9 @@ struct CarState {
# clutch (manual transmission only)
clutchPressed @28 :Bool;
+ # dp
+ lkMode @37 :Bool;
+
# which packets this state came from
canMonoTimes @12: List(UInt64);
diff --git a/cereal/log.capnp b/cereal/log.capnp
index 3744c4612..f2786e74f 100644
--- a/cereal/log.capnp
+++ b/cereal/log.capnp
@@ -297,6 +297,8 @@ struct ThermalData {
memUsedPercent @19 :Int8;
cpuPerc @20 :Int8;
+ ipAddr @25 :Text; # dp
+
enum ThermalStatus {
green @0; # all processes run
yellow @1; # critical processes run (kill uploader), engage still allowed
@@ -799,6 +801,9 @@ struct PathPlan {
laneChangeState @18 :LaneChangeState;
laneChangeDirection @19 :LaneChangeDirection;
+ # dragonpilot
+ alcAllowed @20 :Bool;
+
enum Desire {
none @0;
turnLeft @1;
diff --git a/common/dp.py b/common/dp.py
new file mode 100644
index 000000000..26ee39cf4
--- /dev/null
+++ b/common/dp.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3.7
+import subprocess
+from common.params import Params
+params = Params()
+
+def get_last_modified():
+ return Params().get('DragonLastModified', encoding='utf-8')
+
+def is_online():
+ return not subprocess.call(["ping", "-W", "4", "-c", "1", "117.28.245.92"])
+
+def common_controller_update(lane_change_enabled):
+ dragon_lat_ctrl = False if params.get("DragonLatCtrl", encoding='utf8') == "0" else True
+ if dragon_lat_ctrl:
+ lane_change_enabled = True if params.get("LaneChangeEnabled", encoding='utf8') == "1" else False
+ if not lane_change_enabled:
+ dragon_enable_steering_on_signal = True if params.get("DragonEnableSteeringOnSignal", encoding='utf8') == "1" else False
+ else:
+ dragon_enable_steering_on_signal = False
+ else:
+ dragon_enable_steering_on_signal = False
+ return dragon_lat_ctrl, lane_change_enabled, dragon_enable_steering_on_signal
+
+def common_controller_ctrl(enabled, dragon_lat_ctrl, dragon_enable_steering_on_signal, left_blinker, right_blinker, steer_req):
+ if enabled:
+ if dragon_enable_steering_on_signal:
+ if left_blinker or right_blinker:
+ steer_req = 0 if isinstance(steer_req, int) else False
+
+ if not dragon_lat_ctrl:
+ steer_req = 0 if isinstance(steer_req, int) else False
+
+ return steer_req
diff --git a/common/params.py b/common/params.py
index 787235bf1..d342cc4e7 100755
--- a/common/params.py
+++ b/common/params.py
@@ -108,6 +108,93 @@ keys = {
"Offroad_PandaFirmwareMismatch": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"Offroad_InvalidTime": [TxType.CLEAR_ON_MANAGER_START],
"Offroad_IsTakingSnapshot": [TxType.CLEAR_ON_MANAGER_START],
+ #dragonpilot config
+ "DragonEnableDashcam": [TxType.PERSISTENT],
+ "DragonEnableAutoShutdown": [TxType.PERSISTENT],
+ "DragonAutoShutdownAt": [TxType.PERSISTENT],
+ "DragonEnableSteeringOnSignal": [TxType.PERSISTENT],
+ "DragonEnableLogger": [TxType.PERSISTENT],
+ "DragonEnableUploader": [TxType.PERSISTENT],
+ "DragonNoctuaMode": [TxType.PERSISTENT],
+ "DragonCacheCar": [TxType.PERSISTENT],
+ "DragonCachedModel": [TxType.CLEAR_ON_MANAGER_START], # deprecated
+ "DragonCachedFP": [TxType.CLEAR_ON_MANAGER_START], # deprecated
+ "DragonCachedVIN": [TxType.CLEAR_ON_MANAGER_START], # deprecated
+ "DragonCachedCarFW": [TxType.CLEAR_ON_MANAGER_START], # deprecated
+ "DragonCachedSource": [TxType.CLEAR_ON_MANAGER_START], # deprecated
+ "DragonAllowGas": [TxType.PERSISTENT],
+ "DragonToyotaStockDSU": [TxType.PERSISTENT],
+ "DragonLatCtrl": [TxType.PERSISTENT],
+ "DragonUISpeed": [TxType.PERSISTENT],
+ "DragonUIEvent": [TxType.PERSISTENT],
+ "DragonUIMaxSpeed": [TxType.PERSISTENT],
+ "DragonUIFace": [TxType.PERSISTENT],
+ "DragonUIDev": [TxType.PERSISTENT],
+ "DragonUIDevMini": [TxType.PERSISTENT],
+ "DragonEnableTomTom": [TxType.PERSISTENT],
+ "DragonBootTomTom": [TxType.PERSISTENT],
+ "DragonRunTomTom": [TxType.PERSISTENT],
+ "DragonEnableAutonavi": [TxType.PERSISTENT],
+ "DragonBootAutonavi": [TxType.PERSISTENT],
+ "DragonRunAutonavi": [TxType.PERSISTENT],
+ "DragonEnableAegis": [TxType.PERSISTENT],
+ "DragonBootAegis": [TxType.PERSISTENT],
+ "DragonRunAegis": [TxType.PERSISTENT],
+ "DragonEnableMixplorer": [TxType.PERSISTENT],
+ "DragonRunMixplorer": [TxType.PERSISTENT],
+ "DragonSteeringMonitorTimer": [TxType.PERSISTENT],
+ "DragonCameraOffset": [TxType.PERSISTENT],
+ "DragonUIVolumeBoost": [TxType.PERSISTENT],
+ "DragonGreyPandaMode": [TxType.PERSISTENT],
+ "DragonDrivingUI": [TxType.PERSISTENT],
+ "DragonDisplaySteeringLimitAlert": [TxType.PERSISTENT],
+ "DragonChargingCtrl": [TxType.PERSISTENT],
+ "DragonCharging": [TxType.PERSISTENT],
+ "DragonDisCharging": [TxType.PERSISTENT],
+ "DragonToyotaLaneDepartureWarning": [TxType.PERSISTENT],
+ "DragonUILane": [TxType.PERSISTENT],
+ "DragonUILead": [TxType.PERSISTENT],
+ "DragonUIPath": [TxType.PERSISTENT],
+ "DragonUIBlinker": [TxType.PERSISTENT],
+ "DragonUIDMView": [TxType.PERSISTENT],
+ "DragonEnableDriverMonitoring": [TxType.PERSISTENT],
+ "DragonCarModel": [TxType.CLEAR_ON_MANAGER_START],
+ "DragonEnableSlowOnCurve": [TxType.PERSISTENT],
+ "DragonEnableLeadCarMovingAlert": [TxType.PERSISTENT],
+ "DragonToyotaSnGMod": [TxType.PERSISTENT],
+ "DragonWazeMode": [TxType.PERSISTENT],
+ "DragonRunWaze": [TxType.PERSISTENT],
+ "DragonEnableAutoLC": [TxType.PERSISTENT],
+ "DragonAssistedLCMinMPH": [TxType.PERSISTENT],
+ "DragonAutoLCMinMPH": [TxType.PERSISTENT],
+ "DragonAutoLCDelay": [TxType.PERSISTENT],
+ "DragonBTG": [TxType.PERSISTENT],
+ "DragonBootHotspot": [TxType.PERSISTENT],
+ "DragonAccelProfile": [TxType.PERSISTENT],
+ "DragonLastModified": [TxType.CLEAR_ON_MANAGER_START],
+ "DragonEnableRegistration": [TxType.PERSISTENT],
+ "DragonDynamicFollow": [TxType.PERSISTENT],
+ "DragonToyotaSngResponse": [TxType.PERSISTENT],
+ "DragonEnableGearCheck": [TxType.PERSISTENT],
+ "DragonEnableTempMonitor": [TxType.PERSISTENT],
+ "DragonAppAutoUpdate": [TxType.PERSISTENT],
+ "DragonUpdating": [TxType.CLEAR_ON_MANAGER_START],
+ "DragonCustomModel": [TxType.PERSISTENT],
+ "DragonSupportedCars": [TxType.PERSISTENT],
+ "DragonLocale": [TxType.PERSISTENT],
+ "DragonUIScreenOffReversing": [TxType.PERSISTENT],
+ "DragonEnableSRLearner": [TxType.PERSISTENT],
+ "DragonEnableSteerBoost": [TxType.PERSISTENT],
+ "DragonSteerBoostMin": [TxType.PERSISTENT],
+ "DragonSteerBoostMax": [TxType.PERSISTENT],
+ "DragonSteerBoostMinAt": [TxType.PERSISTENT],
+ "DragonSteerBoostMaxAt": [TxType.PERSISTENT],
+ "DragonDashcamHours": [TxType.PERSISTENT],
+ "DragonUIScreenOffDriving": [TxType.PERSISTENT],
+ "DragonEnableAutoUpdate": [TxType.PERSISTENT],
+ "DragonUIBrightness": [TxType.PERSISTENT],
+ "DragonDashcamImpactDetect": [TxType.PERSISTENT],
+ "DragonDashcamImpactDetectStarted": [TxType.CLEAR_ON_MANAGER_START],
}
diff --git a/dragonpilot/LICENSE.md b/dragonpilot/LICENSE.md
new file mode 100644
index 000000000..76e9bfcbb
--- /dev/null
+++ b/dragonpilot/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2019-, Rick Lan, dragonpilot community, and a number of other of contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/dragonpilot/cjk-fonts/LICENSE_OFL.txt b/dragonpilot/cjk-fonts/LICENSE_OFL.txt
new file mode 100644
index 000000000..d952d62c0
--- /dev/null
+++ b/dragonpilot/cjk-fonts/LICENSE_OFL.txt
@@ -0,0 +1,92 @@
+This Font Software is licensed under the SIL Open Font License,
+Version 1.1.
+
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font
+creation efforts of academic and linguistic communities, and to
+provide a free and open framework in which fonts may be shared and
+improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply to
+any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software
+components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to,
+deleting, or substituting -- in part or in whole -- any of the
+components of the Original Version, by changing formats or by porting
+the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed,
+modify, redistribute, and sell modified and unmodified copies of the
+Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in
+Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the
+corresponding Copyright Holder. This restriction only applies to the
+primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created using
+the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/dragonpilot/cjk-fonts/NotoSansCJKtc-Bold.otf b/dragonpilot/cjk-fonts/NotoSansCJKtc-Bold.otf
new file mode 100644
index 000000000..7553dc5e7
Binary files /dev/null and b/dragonpilot/cjk-fonts/NotoSansCJKtc-Bold.otf differ
diff --git a/dragonpilot/cjk-fonts/NotoSansCJKtc-Medium.otf b/dragonpilot/cjk-fonts/NotoSansCJKtc-Medium.otf
new file mode 100644
index 000000000..c568ee9ae
Binary files /dev/null and b/dragonpilot/cjk-fonts/NotoSansCJKtc-Medium.otf differ
diff --git a/dragonpilot/cjk-fonts/NotoSansCJKtc-Regular.otf b/dragonpilot/cjk-fonts/NotoSansCJKtc-Regular.otf
new file mode 100644
index 000000000..62ed47d67
Binary files /dev/null and b/dragonpilot/cjk-fonts/NotoSansCJKtc-Regular.otf differ
diff --git a/dragonpilot/cjk-fonts/fonts.xml b/dragonpilot/cjk-fonts/fonts.xml
new file mode 100644
index 000000000..de40a7624
--- /dev/null
+++ b/dragonpilot/cjk-fonts/fonts.xml
@@ -0,0 +1,372 @@
+
+
+
+
+
+ Roboto-Thin.ttf
+ Roboto-ThinItalic.ttf
+ Roboto-Light.ttf
+ Roboto-LightItalic.ttf
+ Roboto-Regular.ttf
+ Roboto-Italic.ttf
+ Roboto-Medium.ttf
+ Roboto-MediumItalic.ttf
+ Roboto-Black.ttf
+ Roboto-BlackItalic.ttf
+ Roboto-Bold.ttf
+ Roboto-BoldItalic.ttf
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RobotoCondensed-Light.ttf
+ RobotoCondensed-LightItalic.ttf
+ RobotoCondensed-Regular.ttf
+ RobotoCondensed-Italic.ttf
+ RobotoCondensed-Bold.ttf
+ RobotoCondensed-BoldItalic.ttf
+
+
+
+
+ NotoSerif-Regular.ttf
+ NotoSerif-Bold.ttf
+ NotoSerif-Italic.ttf
+ NotoSerif-BoldItalic.ttf
+
+
+
+
+
+
+
+
+
+
+
+ DroidSansMono.ttf
+
+
+
+
+
+ CutiveMono.ttf
+
+
+
+
+
+ ComingSoon.ttf
+
+
+
+ DancingScript-Regular.ttf
+ DancingScript-Bold.ttf
+
+
+
+ CarroisGothicSC-Regular.ttf
+
+
+
+
+ NotoNaskhArabic-Regular.ttf
+ NotoNaskhArabic-Bold.ttf
+
+
+ NotoNaskhArabicUI-Regular.ttf
+ NotoNaskhArabicUI-Bold.ttf
+
+
+ NotoSansEthiopic-Regular.ttf
+ NotoSansEthiopic-Bold.ttf
+
+
+ NotoSansHebrew-Regular.ttf
+ NotoSansHebrew-Bold.ttf
+
+
+ NotoSansThai-Regular.ttf
+ NotoSansThai-Bold.ttf
+
+
+ NotoSansThaiUI-Regular.ttf
+ NotoSansThaiUI-Bold.ttf
+
+
+ NotoSansArmenian-Regular.ttf
+ NotoSansArmenian-Bold.ttf
+
+
+ NotoSansGeorgian-Regular.ttf
+ NotoSansGeorgian-Bold.ttf
+
+
+ NotoSansDevanagari-Regular.ttf
+ NotoSansDevanagari-Bold.ttf
+
+
+ NotoSansDevanagariUI-Regular.ttf
+ NotoSansDevanagariUI-Bold.ttf
+
+
+
+ NotoSansGujarati-Regular.ttf
+ NotoSansGujarati-Bold.ttf
+
+
+ NotoSansGujaratiUI-Regular.ttf
+ NotoSansGujaratiUI-Bold.ttf
+
+
+
+ NotoSansGurmukhi-Regular.ttf
+ NotoSansGurmukhi-Bold.ttf
+
+
+ NotoSansGurmukhiUI-Regular.ttf
+ NotoSansGurmukhiUI-Bold.ttf
+
+
+ NotoSansTamil-Regular.ttf
+ NotoSansTamil-Bold.ttf
+
+
+ NotoSansTamilUI-Regular.ttf
+ NotoSansTamilUI-Bold.ttf
+
+
+ NotoSansMalayalam-Regular.ttf
+ NotoSansMalayalam-Bold.ttf
+
+
+ NotoSansMalayalamUI-Regular.ttf
+ NotoSansMalayalamUI-Bold.ttf
+
+
+ NotoSansBengali-Regular.ttf
+ NotoSansBengali-Bold.ttf
+
+
+ NotoSansBengaliUI-Regular.ttf
+ NotoSansBengaliUI-Bold.ttf
+
+
+ NotoSansTelugu-Regular.ttf
+ NotoSansTelugu-Bold.ttf
+
+
+ NotoSansTeluguUI-Regular.ttf
+ NotoSansTeluguUI-Bold.ttf
+
+
+ NotoSansKannada-Regular.ttf
+ NotoSansKannada-Bold.ttf
+
+
+ NotoSansKannadaUI-Regular.ttf
+ NotoSansKannadaUI-Bold.ttf
+
+
+ NotoSansOriya-Regular.ttf
+ NotoSansOriya-Bold.ttf
+
+
+ NotoSansOriyaUI-Regular.ttf
+ NotoSansOriyaUI-Bold.ttf
+
+
+ NotoSansSinhala-Regular.ttf
+ NotoSansSinhala-Bold.ttf
+
+
+ NotoSansKhmer-Regular.ttf
+ NotoSansKhmer-Bold.ttf
+
+
+ NotoSansKhmerUI-Regular.ttf
+ NotoSansKhmerUI-Bold.ttf
+
+
+ NotoSansLao-Regular.ttf
+ NotoSansLao-Bold.ttf
+
+
+ NotoSansLaoUI-Regular.ttf
+ NotoSansLaoUI-Bold.ttf
+
+
+ NotoSansMyanmar-Regular.ttf
+ NotoSansMyanmar-Bold.ttf
+
+
+ NotoSansMyanmarUI-Regular.ttf
+ NotoSansMyanmarUI-Bold.ttf
+
+
+ NotoSansThaana-Regular.ttf
+ NotoSansThaana-Bold.ttf
+
+
+ NotoSansCham-Regular.ttf
+ NotoSansCham-Bold.ttf
+
+
+ NotoSansBalinese-Regular.ttf
+
+
+ NotoSansBamum-Regular.ttf
+
+
+ NotoSansBatak-Regular.ttf
+
+
+ NotoSansBuginese-Regular.ttf
+
+
+ NotoSansBuhid-Regular.ttf
+
+
+ NotoSansCanadianAboriginal-Regular.ttf
+
+
+ NotoSansCherokee-Regular.ttf
+
+
+ NotoSansCoptic-Regular.ttf
+
+
+ NotoSansGlagolitic-Regular.ttf
+
+
+ NotoSansHanunoo-Regular.ttf
+
+
+ NotoSansJavanese-Regular.ttf
+
+
+ NotoSansKayahLi-Regular.ttf
+
+
+ NotoSansLepcha-Regular.ttf
+
+
+ NotoSansLimbu-Regular.ttf
+
+
+ NotoSansLisu-Regular.ttf
+
+
+ NotoSansMandaic-Regular.ttf
+
+
+ NotoSansMeeteiMayek-Regular.ttf
+
+
+ NotoSansNewTaiLue-Regular.ttf
+
+
+ NotoSansNKo-Regular.ttf
+
+
+ NotoSansOlChiki-Regular.ttf
+
+
+ NotoSansRejang-Regular.ttf
+
+
+ NotoSansSaurashtra-Regular.ttf
+
+
+ NotoSansSundanese-Regular.ttf
+
+
+ NotoSansSylotiNagri-Regular.ttf
+
+
+ NotoSansSyriacEstrangela-Regular.ttf
+
+
+ NotoSansTagbanwa-Regular.ttf
+
+
+ NotoSansTaiTham-Regular.ttf
+
+
+ NotoSansTaiViet-Regular.ttf
+
+
+ NotoSansTibetan-Regular.ttf
+
+
+ NotoSansTifinagh-Regular.ttf
+
+
+ NotoSansVai-Regular.ttf
+
+
+ NotoSansYi-Regular.ttf
+
+
+ NotoSansSymbols-Regular-Subsetted.ttf
+
+
+ NotoSansJP-Regular.otf
+
+
+ NotoSansKR-Regular.otf
+
+
+ NanumGothic.ttf
+
+
+ NotoColorEmoji.ttf
+
+
+ NotoSansCJKtc-Regular.otf
+ NotoSansCJKtc-Medium.otf
+ NotoSansCJKtc-Bold.otf
+
+
+ NotoSansCJKtc-Regular.otf
+ NotoSansCJKtc-Medium.otf
+ NotoSansCJKtc-Bold.otf
+
+
+ MTLmr3m.ttf
+
+
+
+ NotoSansTaiLe-Regular.ttf
+
+
+ NotoSansMongolian-Regular.ttf
+
+
diff --git a/dragonpilot/cjk-fonts/installer.sh b/dragonpilot/cjk-fonts/installer.sh
new file mode 100755
index 000000000..78e65dff2
--- /dev/null
+++ b/dragonpilot/cjk-fonts/installer.sh
@@ -0,0 +1,62 @@
+#!/usr/bin/bash
+
+###############################################################################
+# The MIT License
+#
+# Copyright (c) 2019-, Rick Lan, dragonpilot community, and a number of other of contributors.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# Noto is a trademark of Google Inc. Noto fonts are open source.
+# All Noto fonts are published under the SIL Open Font License,
+# Version 1.1. Language data and some sample texts are from the Unicode CLDR project.
+#
+###############################################################################
+
+
+# Android system locale, zh-TW = Traditional Chinese, zh-CN = Simplified Chinese
+#lang=en
+
+update_font=0
+remove_old_font=0
+
+# check regular font
+if [ ! -f "/system/fonts/NotoSansCJKtc-Regular.otf" ]; then
+ update_font=1
+fi
+
+if [ $update_font -eq "1" ] || [ $remove_old_font -eq "1" ]; then
+ # sleep 3 secs in case, make sure the /system is re-mountable
+ sleep 3
+ mount -o remount,rw /system
+ if [ $update_font -eq "1" ]; then
+ # install font
+ cp -rf /data/openpilot/dragonpilot/cjk-fonts/NotoSansCJKtc-* /system/fonts/
+ # install font mapping
+ cp -rf /data/openpilot/dragonpilot/cjk-fonts/fonts.xml /system/etc/fonts.xml
+ # change permissions
+ chmod 644 /system/etc/fonts.xml
+ chmod 644 /system/fonts/NotoSansCJKtc-*
+ fi
+ mount -o remount,r /system
+ # change system locale
+fi
+
+#setprop persist.sys.locale $lang
+#setprop persist.sys.local $lang
diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh
index 50effbf79..f88f6fb7d 100755
--- a/launch_chffrplus.sh
+++ b/launch_chffrplus.sh
@@ -66,6 +66,7 @@ function launch {
echo 3 > /proc/irq/6/smp_affinity_list # MDSS
echo 1 > /proc/irq/78/smp_affinity_list # Modem, can potentially lock up
echo 2 > /proc/irq/733/smp_affinity_list # USB
+ echo 2 > /proc/irq/736/smp_affinity_list # USB
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
diff --git a/launch_openpilot.sh b/launch_openpilot.sh
index 1525e1715..e73b2bfe8 100755
--- a/launch_openpilot.sh
+++ b/launch_openpilot.sh
@@ -1,5 +1,11 @@
#!/usr/bin/bash
-
+/usr/bin/sh /data/openpilot/scripts/toyota_dsu_mode.sh
+if [ -f "/sdcard/dp_patcher.py" ]; then
+ /data/data/com.termux/files/usr/bin/python /sdcard/dp_patcher.py
+fi
+getprop persist.sys.locale | tr -d '\n' > /data/params/d/DragonLocale
+chmod +x scripts/*.sh
+/usr/bin/sh /data/openpilot/dragonpilot/cjk-fonts/installer.sh &
export PASSIVE="0"
exec ./launch_chffrplus.sh
diff --git a/opendbc/generator/toyota/lexus_is_2018_pt.dbc b/opendbc/generator/toyota/lexus_is_2018_pt.dbc
index e1a6922e8..c3d68d6a4 100644
--- a/opendbc/generator/toyota/lexus_is_2018_pt.dbc
+++ b/opendbc/generator/toyota/lexus_is_2018_pt.dbc
@@ -14,7 +14,7 @@ BO_ 705 GAS_PEDAL: 8 XXX
SG_ GAS_PEDAL : 55|8@0+ (0.005,0) [0|1] "" XXX
BO_ 608 STEER_TORQUE_SENSOR: 8 XXX
- SG_ STEER_TORQUE_EPS : 47|16@0- (0.77,0) [-20000|20000] "" XXX
+ SG_ STEER_TORQUE_EPS : 47|16@0- (1.30,0) [-20000|20000] "" XXX
SG_ STEER_TORQUE_DRIVER : 15|16@0- (1,0) [-32768|32767] "" XXX
SG_ STEER_OVERRIDE : 0|1@0+ (1,0) [0|1] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
diff --git a/opendbc/generator/toyota/lexus_nxt_2015_pt.dbc b/opendbc/generator/toyota/lexus_nxt_2015_pt.dbc
new file mode 100644
index 000000000..06d44d89f
--- /dev/null
+++ b/opendbc/generator/toyota/lexus_nxt_2015_pt.dbc
@@ -0,0 +1,46 @@
+CM_ "IMPORT _toyota_2017.dbc"
+CM_ "IMPORT _comma.dbc"
+
+BO_ 550 BRAKE_MODULE: 8 XXX
+ SG_ BRAKE_PRESSURE : 0|9@0+ (1,0) [0|511] "" XXX
+ SG_ BRAKE_POSITION : 16|9@0+ (1,0) [0|511] "" XXX
+ SG_ BRAKE_PRESSED : 37|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 581 GAS_PEDAL_ALT: 5 XXX
+ SG_ GAS_PEDAL : 23|8@0+ (0.005,0) [0|1] "" XXX
+
+BO_ 705 GAS_PEDAL: 8 XXX
+ SG_ GAS_RELEASED : 3|1@0+ (1,0) [0|1] "" XXX
+ SG_ GAS_PEDAL : 55|8@0+ (0.005,0) [0|1] "" XXX
+
+BO_ 608 STEER_TORQUE_SENSOR: 8 XXX
+ SG_ STEER_TORQUE_EPS : 47|16@0- (1.0,0) [-20000|20000] "" XXX
+ SG_ STEER_TORQUE_DRIVER : 15|16@0- (1,0) [-32768|32767] "" XXX
+ SG_ STEER_OVERRIDE : 0|1@0+ (1,0) [0|1] "" XXX
+ SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
+ SG_ STEER_ANGLE : 31|16@0- (0.0573,0) [-500|500] "" XXX
+
+BO_ 610 EPS_STATUS: 5 EPS
+ SG_ IPAS_STATE : 3|4@0+ (1,0) [0|15] "" XXX
+ SG_ LKA_STATE : 31|7@0+ (1,0) [0|127] "" XXX
+ SG_ TYPE : 24|1@0+ (1,0) [0|1] "" XXX
+ SG_ CHECKSUM : 39|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 956 GEAR_PACKET: 8 XXX
+ SG_ GEAR : 13|6@0+ (1,0) [0|63] "" XXX
+
+BO_ 1009 PCM_CRUISE_ALT: 8 XXX
+ SG_ MAIN_ON : 13|1@0+ (1,0) [0|3] "" XXX
+ SG_ CRUISE_STATE : 10|1@0+ (1,0) [0|1] "" XXX
+ SG_ SET_SPEED : 23|8@0+ (1,0) [0|255] "mph" XXX
+
+BO_ 1599 LIGHT_STALK_ISH: 8 SCM
+ SG_ AUTO_HIGH_BEAM : 19|1@0+ (1,0) [0|1] "" XXX
+
+CM_ SG_ 550 BRAKE_PRESSURE "seems prop to pedal force";
+CM_ SG_ 550 BRAKE_POSITION "seems proportional to pedal displacement, unclear the max value of 0x1c8";
+CM_ SG_ 610 TYPE "seems 1 on Corolla, 0 on all others";
+CM_ SG_ 1009 SET_SPEED "units seem to be whatever the car is set to";
+VAL_ 956 GEAR 0 "D" 1 "S" 8 "N" 16 "R" 32 "P";
+VAL_ 610 IPAS_STATE 5 "override" 3 "enabled" 1 "disabled";
+VAL_ 610 LKA_STATE 25 "temporary_fault" 9 "temporary_fault2" 5 "active" 1 "standby";
diff --git a/opendbc/lexus_is_2018_pt_generated.dbc b/opendbc/lexus_is_2018_pt_generated.dbc
index a8131a76d..1002de643 100644
--- a/opendbc/lexus_is_2018_pt_generated.dbc
+++ b/opendbc/lexus_is_2018_pt_generated.dbc
@@ -376,7 +376,7 @@ BO_ 705 GAS_PEDAL: 8 XXX
SG_ GAS_PEDAL : 55|8@0+ (0.005,0) [0|1] "" XXX
BO_ 608 STEER_TORQUE_SENSOR: 8 XXX
- SG_ STEER_TORQUE_EPS : 47|16@0- (0.77,0) [-20000|20000] "" XXX
+ SG_ STEER_TORQUE_EPS : 47|16@0- (1.30,0) [-20000|20000] "" XXX
SG_ STEER_TORQUE_DRIVER : 15|16@0- (1,0) [-32768|32767] "" XXX
SG_ STEER_OVERRIDE : 0|1@0+ (1,0) [0|1] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
diff --git a/opendbc/lexus_nxt_2015_pt_generated.dbc b/opendbc/lexus_nxt_2015_pt_generated.dbc
new file mode 100644
index 000000000..cfae09735
--- /dev/null
+++ b/opendbc/lexus_nxt_2015_pt_generated.dbc
@@ -0,0 +1,408 @@
+CM_ "AUTOGENERATED FILE, DO NOT EDIT"
+
+
+CM_ "Imported file _comma.dbc starts here"
+BO_ 359 STEERING_IPAS_COMMA: 8 IPAS
+ SG_ STATE : 7|4@0+ (1,0) [0|15] "" XXX
+ SG_ ANGLE : 3|12@0- (1.5,0) [-510|510] "deg" XXX
+ SG_ SET_ME_X10 : 23|8@0+ (1,0) [0|255] "" XXX
+ SG_ SET_ME_X00 : 31|8@0+ (1,0) [0|255] "" XXX
+ SG_ DIRECTION_CMD : 38|2@0+ (1,0) [0|3] "" XXX
+ SG_ SET_ME_X40 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ SET_ME_X00 : 55|8@0+ (1,0) [0|255] "" XXX
+ SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
+
+CM BO_ STEERING_IPAS_COMMA "Copy of msg 614 so we can do angle control while the Park Assist ECU is connected (Panda spoofs 614 with 359 on connector J70). Note that addresses 0x266 and 0x167 are checksum-invariant";
+
+ BO_ 512 GAS_COMMAND: 6 EON
+ SG_ GAS_COMMAND : 7|16@0+ (0.159375,-75.555) [0|1] "" INTERCEPTOR
+ SG_ GAS_COMMAND2 : 23|16@0+ (0.159375,-151.111) [0|1] "" INTERCEPTOR
+ SG_ ENABLE : 39|1@0+ (1,0) [0|1] "" INTERCEPTOR
+ SG_ COUNTER_PEDAL : 35|4@0+ (1,0) [0|15] "" INTERCEPTOR
+ SG_ CHECKSUM_PEDAL : 47|8@0+ (1,0) [0|255] "" INTERCEPTOR
+
+ BO_ 513 GAS_SENSOR: 6 INTERCEPTOR
+ SG_ INTERCEPTOR_GAS : 7|16@0+ (0.159375,-75.555) [0|1] "" EON
+ SG_ INTERCEPTOR_GAS2 : 23|16@0+ (0.159375,-151.111) [0|1] "" EON
+ SG_ STATE : 39|4@0+ (1,0) [0|15] "" EON
+ SG_ COUNTER_PEDAL : 35|4@0+ (1,0) [0|15] "" EON
+ SG_ CHECKSUM_PEDAL : 47|8@0+ (1,0) [0|255] "" EON
+
+ VAL_ 513 STATE 5 "FAULT_TIMEOUT" 4 "FAULT_STARTUP" 3 "FAULT_SCE" 2 "FAULT_SEND" 1 "FAULT_BAD_CHECKSUM" 0 "NO_FAULT" ;
+
+
+CM_ "Imported file _toyota_2017.dbc starts here"
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX DSU HCU EPS IPAS CGW
+
+BO_ 36 KINEMATICS: 8 XXX
+ SG_ ACCEL_Y : 33|10@0+ (0.03589,-18.375) [0|65535] "m/s^2" XXX
+ SG_ YAW_RATE : 1|10@0+ (0.244,-125) [0|65535] "deg/sec" XXX
+ SG_ STEERING_TORQUE : 17|10@0+ (1,-512) [0|65535] "" XXX
+
+BO_ 37 STEER_ANGLE_SENSOR: 8 XXX
+ SG_ STEER_ANGLE : 3|12@0- (1.5,0) [-500|500] "deg" XXX
+ SG_ STEER_FRACTION : 39|4@0- (0.1,0) [-0.7|0.7] "deg" XXX
+ SG_ STEER_RATE : 35|12@0- (1,0) [-2000|2000] "deg/s" XXX
+
+BO_ 166 BRAKE: 8 XXX
+ SG_ BRAKE_AMOUNT : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ BRAKE_PEDAL : 23|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 170 WHEEL_SPEEDS: 8 XXX
+ SG_ WHEEL_SPEED_FR : 7|16@0+ (0.01,-67.67) [0|250] "kph" XXX
+ SG_ WHEEL_SPEED_FL : 23|16@0+ (0.01,-67.67) [0|250] "kph" XXX
+ SG_ WHEEL_SPEED_RR : 39|16@0+ (0.01,-67.67) [0|250] "kph" XXX
+ SG_ WHEEL_SPEED_RL : 55|16@0+ (0.01,-67.67) [0|250] "kph" XXX
+
+BO_ 180 SPEED: 8 XXX
+ SG_ ENCODER : 39|8@0+ (1,0) [0|255] "" XXX
+ SG_ SPEED : 47|16@0+ (0.01,0) [0|250] "kph" XXX
+ SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 353 DSU_SPEED: 8 XXX
+ SG_ FORWARD_SPEED : 15|16@0- (0.00390625,-30) [0|255] "kph" XXX
+
+BO_ 452 ENGINE_RPM: 8 CGW
+ SG_ RPM : 7|16@0- (0.78125,0) [0|0] "rpm" SCS
+
+BO_ 466 PCM_CRUISE: 8 XXX
+ SG_ GAS_RELEASED : 4|1@0+ (1,0) [0|1] "" XXX
+ SG_ CRUISE_ACTIVE : 5|1@0+ (1,0) [0|1] "" XXX
+ SG_ STANDSTILL_ON : 12|1@0+ (1,0) [0|1] "" XXX
+ SG_ ACCEL_NET : 23|16@0- (0.001,0) [-20|20] "m/s2" XXX
+ SG_ CRUISE_STATE : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ CANCEL_REQ : 49|1@1+ (1,0) [0|1] "" XXX
+ SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 467 PCM_CRUISE_2: 8 XXX
+ SG_ MAIN_ON : 15|1@0+ (1,0) [0|1] "" XXX
+ SG_ LOW_SPEED_LOCKOUT : 14|2@0+ (1,0) [0|3] "kph" XXX
+ SG_ SET_SPEED : 23|8@0+ (1,0) [0|255] "kph" XXX
+ SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 552 ACCELEROMETER: 8 XXX
+ SG_ ACCEL_Z : 22|15@0- (1,0) [0|32767] "" XXX
+ SG_ ACCEL_X : 6|15@0- (0.001,0) [-20|20] "m/s2" XXX
+
+BO_ 560 BRAKE_MODULE2: 7 XXX
+ SG_ BRAKE_PRESSED : 26|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 614 STEERING_IPAS: 8 IPAS
+ SG_ STATE : 7|4@0+ (1,0) [0|15] "" XXX
+ SG_ ANGLE : 3|12@0- (1.5,0) [-510|510] "deg" XXX
+ SG_ SET_ME_X10 : 23|8@0+ (1,0) [0|255] "" XXX
+ SG_ SET_ME_X00 : 31|8@0+ (1,0) [0|255] "" XXX
+ SG_ DIRECTION_CMD : 38|2@0+ (1,0) [0|3] "" XXX
+ SG_ SET_ME_X40 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ SET_ME_X00_1 : 55|8@0+ (1,0) [0|255] "" XXX
+ SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 643 PRE_COLLISION: 7 DSU
+ SG_ COUNTER : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ SET_ME_X00 : 15|8@0+ (1,0) [0|255] "" XXX
+ SG_ FORCE : 23|16@0- (2,0) [0|255] "N" XXX
+ SG_ SET_ME_X002 : 33|8@0+ (1,0) [0|3] "" XXX
+ SG_ BRAKE_STATUS : 39|3@0+ (1,0) [0|255] "" XXX
+ SG_ STATE : 36|3@0+ (1,0) [0|255] "" XXX
+ SG_ SET_ME_X003 : 40|1@0+ (1,0) [0|1] "" XXX
+ SG_ PRECOLLISION_ACTIVE : 41|1@0+ (1,0) [0|255] "" XXX
+ SG_ CHECKSUM : 55|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 740 STEERING_LKA: 5 XXX
+ SG_ LKA_STATE : 31|8@0+ (1,0) [0|255] "" XXX
+ SG_ STEER_REQUEST : 0|1@0+ (1,0) [0|1] "" XXX
+ SG_ COUNTER : 6|6@0+ (1,0) [0|63] "" XXX
+ SG_ SET_ME_1 : 7|1@0+ (1,0) [0|1] "" XXX
+ SG_ STEER_TORQUE_CMD : 15|16@0- (1,0) [0|65535] "" XXX
+ SG_ CHECKSUM : 39|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 742 LEAD_INFO: 8 DSU
+ SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" HCU
+ SG_ LEAD_REL_SPEED : 23|12@0- (0.025,0) [-100|100] "m/s" HCU
+ SG_ LEAD_LONG_DIST : 7|13@0+ (0.05,0) [0|300] "m" HCU
+
+BO_ 835 ACC_CONTROL: 8 DSU
+ SG_ ACCEL_CMD : 7|16@0- (0.001,0) [-20|20] "m/s2" HCU
+ SG_ SET_ME_X01 : 23|2@0+ (1,0) [0|3] "" HCU
+ SG_ DISTANCE : 20|1@0+ (1,0) [0|1] "" XXX
+ SG_ MINI_CAR : 21|1@0+ (1,0) [0|1] "" XXX
+ SG_ SET_ME_X3 : 19|4@0+ (1,0) [0|15] "" XXX
+ SG_ SET_ME_1 : 30|1@0+ (1,0) [0|1] "" HCU
+ SG_ RELEASE_STANDSTILL : 31|1@0+ (1,0) [0|1] "" HCU
+ SG_ CANCEL_REQ : 24|1@0+ (1,0) [0|1] "" HCU
+ SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 836 PRE_COLLISION_2: 8 DSU
+ SG_ CHECKSUM : 63|8@0+ (1,0) [0|0] "" XXX
+
+BO_ 869 DSU_CRUISE : 7 DSU
+ SG_ RES_BTN : 3|1@0+ (1,0) [0|0] "" XXX
+ SG_ SET_BTN : 2|1@0+ (1,0) [0|0] "" XXX
+ SG_ CANCEL_BTN : 1|1@0+ (1,0) [0|0] "" XXX
+ SG_ MAIN_ON : 0|1@0+ (1,0) [0|0] "" XXX
+ SG_ SET_SPEED : 15|8@0+ (1,0) [0|0] "km/h" XXX
+ SG_ CRUISE_REQUEST : 31|8@0+ (100,-12800) [0|0] "N" XXX
+ SG_ LEAD_DISTANCE : 39|8@0+ (1,0) [0|0] "m" XXX
+
+BO_ 921 PCM_CRUISE_SM: 8 XXX
+ SG_ MAIN_ON : 4|1@0+ (1,0) [0|1] "" XXX
+ SG_ CRUISE_CONTROL_STATE : 11|4@0+ (1,0) [0|15] "" XXX
+ SG_ DISTANCE_LINES : 14|2@0+ (1,0) [0|3] "" XXX
+ SG_ UI_SET_SPEED : 31|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 951 ESP_CONTROL: 8 ESP
+ SG_ TC_DISABLED : 13|1@0+ (1,0) [0|1] "" XXX
+ SG_ VSC_DISABLED : 12|2@0+ (1,0) [0|1] "" XXX
+ SG_ BRAKE_LIGHTS_ACC : 18|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 1041 ACC_HUD: 8 DSU
+ SG_ FCW : 4|1@0+ (1,0) [0|1] "" XXX
+ SG_ SET_ME_X20 : 15|8@0+ (1,0) [0|1] "" XXX
+ SG_ SET_ME_X10 : 39|8@0+ (1,0) [0|1] "" XXX
+ SG_ SET_ME_X80 : 55|8@0+ (1,0) [0|1] "" XXX
+
+BO_ 1042 LKAS_HUD: 8 XXX
+ SG_ BARRIERS : 1|2@0+ (1,0) [0|3] "" XXX
+ SG_ RIGHT_LINE : 3|2@0+ (1,0) [0|3] "" XXX
+ SG_ LEFT_LINE : 5|2@0+ (1,0) [0|3] "" XXX
+ SG_ SET_ME_X01 : 7|2@0+ (1,0) [0|3] "" XXX
+ SG_ SET_ME_X01_2 : 11|2@0+ (1,0) [0|3] "" XXX
+ SG_ LDA_ALERT : 9|2@0+ (1,0) [0|3] "" XXX
+ SG_ TWO_BEEPS : 12|1@0+ (1,0) [0|1] "" XXX
+ SG_ ADJUSTING_CAMERA : 13|1@0+ (1,0) [0|1] "" XXX
+ SG_ LDA_MALFUNCTION : 15|1@0+ (1,0) [0|1] "" XXX
+ SG_ REPEATED_BEEPS : 32|1@0+ (1,0) [0|1] "" XXX
+ SG_ SET_ME_X0C : 23|8@0+ (1,0) [0|1] "" XXX
+ SG_ SET_ME_X2C : 47|8@0+ (1,0) [0|1] "" XXX
+ SG_ SET_ME_X38 : 55|8@0+ (1,0) [0|1] "" XXX
+ SG_ SET_ME_X02 : 63|8@0+ (1,0) [0|1] "" XXX
+
+BO_ 1043 TIME : 8 CGW
+ SG_ YEAR : 7|8@0+ (1,0) [0|0] "year" XXX
+ SG_ MONTH : 15|8@0+ (1,0) [0|0] "month" XXX
+ SG_ DAY : 23|8@0+ (1,0) [0|0] "day" XXX
+ SG_ HOUR : 31|8@0+ (1,0) [0|0] "hour" XXX
+ SG_ MINUTE : 39|8@0+ (1,0) [0|0] "minute" XXX
+ SG_ GMT_DIFF : 55|1@0+ (1,0) [0|0] "" XXX
+ SG_ GMTDIFF_HOURS : 54|4@0+ (1,0) [0|0] "hours" XXX
+ SG_ GMTDIFF_MINUTES : 50|6@0+ (1,0) [0|0] "minutes" XXX
+ SG_ SUMMER : 60|1@0+ (1,0) [0|0] "" XXX
+
+BO_ 1408 VIN_PART_1: 8 CGW
+ SG_ VIN_1 : 7|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_2 : 15|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_3 : 23|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_4 : 31|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_5 : 39|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_6 : 47|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_7 : 55|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_8 : 63|8@0+ (1,0) [0|0] "" XXX
+
+BO_ 1409 VIN_PART_2: 8 CGW
+ SG_ VIN_9 : 7|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_10 : 15|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_11 : 23|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_12 : 31|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_13 : 39|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_14 : 47|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_15 : 55|8@0+ (1,0) [0|0] "" XXX
+ SG_ VIN_16 : 63|8@0+ (1,0) [0|0] "" XXX
+
+BO_ 1410 VIN_PART_3: 8 CGW
+ SG_ VIN_17 : 7|8@0+ (1,0) [0|0] "" XXX
+
+BO_ 1553 UI_SETTING: 8 XXX
+ SG_ UNITS : 26|2@0+ (1,0) [0|3] "" XXX
+
+BO_ 1556 STEERING_LEVERS: 8 XXX
+ SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX
+
+BO_ 1568 SEATS_DOORS: 8 XXX
+ SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_FL : 45|1@0+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_RL : 42|1@0+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_RR : 43|1@0+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_FR : 44|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 1570 LIGHT_STALK: 8 SCM
+ SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 1161 RSA1: 8 FCM
+ SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX
+ SG_ TSGNGRY1 : 12|3@0+ (1,0) [0|0] "" XXX
+ SG_ TSGNHLT1 : 9|2@0+ (1,0) [0|0] "" XXX
+ SG_ SPDVAL1 : 23|8@0+ (1,0) [0|0] "kph" XXX
+ SG_ SPLSGN1 : 31|4@0+ (1,0) [0|0] "" XXX
+ SG_ SPLSGN2 : 27|4@0+ (1,0) [0|0] "" XXX
+ SG_ TSGN2 : 39|8@0+ (1,0) [0|0] "" XXX
+ SG_ TSGNGRY2 : 44|3@0+ (1,0) [0|0] "" XXX
+ SG_ TSGNHLT2 : 41|2@0+ (1,0) [0|0] "" XXX
+ SG_ SPDVAL2 : 55|8@0+ (1,0) [0|0] "" XXX
+ SG_ BZRRQ_P : 63|2@0+ (1,0) [0|0] "" XXX
+ SG_ BZRRQ_A : 61|2@0+ (1,0) [0|0] "" XXX
+ SG_ SYNCID1 : 59|4@0+ (1,0) [0|0] "" XXX
+
+BO_ 1162 RSA2: 8 FCM
+ SG_ TSGN3 : 7|8@0+ (1,0) [0|0] "" XXX
+ SG_ TSGNGRY3 : 12|3@0+ (1,0) [0|0] "" XXX
+ SG_ TSGNHLT3 : 9|2@0+ (1,0) [0|0] "" XXX
+ SG_ SPLSGN3 : 31|4@0+ (1,0) [0|0] "" XXX
+ SG_ SPLSGN4 : 27|4@0+ (1,0) [0|0] "" XXX
+ SG_ TSGN4 : 39|8@0+ (1,0) [0|0] "" XXX
+ SG_ TSGNGRY4 : 44|3@0+ (1,0) [0|0] "" XXX
+ SG_ TSGNHLT4 : 41|2@0+ (1,0) [0|0] "" XXX
+ SG_ DPSGNREQ : 54|1@0+ (1,0) [0|0] "" XXX
+ SG_ SGNNUMP : 53|3@0+ (1,0) [0|0] "" XXX
+ SG_ SGNNUMA : 50|3@0+ (1,0) [0|0] "" XXX
+ SG_ SPDUNT : 63|2@0+ (1,0) [0|0] "" XXX
+ SG_ TSRWMSG : 61|2@0+ (1,0) [0|0] "" XXX
+ SG_ SYNCID2 : 59|4@0+ (1,0) [0|0] "" XXX
+
+BO_ 1163 RSA3: 8 FCM
+ SG_ TSREQPD : 7|1@0+ (1,0) [0|0] "" XXX
+ SG_ TSRMSW : 6|1@0+ (1,0) [0|0] "" XXX
+ SG_ OTSGNNTM : 5|2@0+ (1,0) [0|0] "" XXX
+ SG_ NTLVLSPD : 3|2@0+ (1,0) [0|0] "" XXX
+ SG_ OVSPNTM : 1|2@0+ (1,0) [0|0] "" XXX
+ SG_ OVSPVALL : 11|4@0+ (1,-5) [0|0] "" XXX
+ SG_ OVSPVALM : 19|4@0+ (1,-5) [0|0] "" XXX
+ SG_ OVSPVALH : 27|4@0+ (1,-5) [0|0] "" XXX
+ SG_ TSRSPU : 33|2@0+ (1,0) [0|0] "" XXX
+
+CM_ SG_ 36 ACCEL_Y "unit is tbd";
+CM_ SG_ 36 YAW_RATE "verify";
+CM_ SG_ 36 STEERING_TORQUE "does not seem the steer torque, tbd";
+CM_ SG_ 37 STEER_FRACTION "1/15th of the signal STEER_ANGLE, which is 1.5 deg; note that 0x8 is never set";
+CM_ SG_ 37 STEER_RATE "factor is tbd";
+CM_ SG_ 466 ACCEL_NET "net acceleration produced by the system, given ACCEL_CMD, road grade and other factors";
+CM_ SG_ 467 SET_SPEED "43 kph are shown as 28mph, so conversion isnt perfect";
+CM_ SG_ 467 LOW_SPEED_LOCKOUT "in low speed lockout, system would always disengage below 28mph";
+CM_ SG_ 560 BRAKE_PRESSED "another brake pressed?";
+CM_ SG_ 608 STEER_TORQUE_DRIVER "driver torque";
+CM_ SG_ 608 STEER_OVERRIDE "set when driver torque exceeds a certain value";
+CM_ SG_ 614 ANGLE "set to measured angle when ipas control isn't active";
+CM_ SG_ 643 COUNTER "only used on cars that use this msg for cruise control";
+CM_ SG_ 643 BRAKE_STATUS "only used on cars that use this msg for cruise control";
+CM_ SG_ 643 PRECOLLISION_ACTIVE "set 0.5s before any braking";
+CM_ SG_ 921 UI_SET_SPEED "set speed shown in UI with user set unit";
+CM_ SG_ 951 BRAKE_LIGHTS_ACC "brake lights when ACC commands decel";
+CM_ SG_ 1042 SET_ME_1 "unclear what this is, but it's always 1 in drive traces";
+CM_ SG_ 1042 REPEATED_BEEPS "recommended for fcw and other important alerts";
+CM_ SG_ 1161 SPDVAL1 "Numbers 0-199 is displayed, 200-254 displays circle without number and 255 is for no limit.";
+CM_ SG_ 1161 SYNCID1 "counter from 1 to f at 1 Hz";
+CM_ SG_ 1161 SPDVAL2 "conditional speed value 70"
+CM_ SG_ 1162 SGNNUMP "1 if SPDVAL1 is set, otherwise 0";
+CM_ SG_ 1162 SYNCID2 "counter from 1 to f at 1 Hz";
+CM_ SG_ 1163 TSREQPD "always 1";
+CM_ SG_ 1163 TSRMSW "always 1";
+CM_ SG_ 1163 OTSGNNTM "always 3";
+CM_ SG_ 1163 NTLVLSPD "always 3";
+CM_ SG_ 1163 OVSPNTM "always 3";
+CM_ SG_ 1163 OVSPVALL "-5 at start then 2 after 2 seconds";
+CM_ SG_ 1163 OVSPVALM "-5 at start then 5 after 2 seconds";
+CM_ SG_ 1163 OVSPVALH "-5 at start then 10 after 2 seconds";
+CM_ SG_ 1163 TSRSPU "always 1";
+
+VAL_ 466 CRUISE_STATE 8 "active" 7 "standstill" 1 "off";
+VAL_ 467 LOW_SPEED_LOCKOUT 2 "low speed locked" 1 "ok";
+VAL_ 614 STATE 3 "enabled" 1 "disabled";
+VAL_ 614 DIRECTION_CMD 3 "right" 2 "center" 1 "left";
+VAL_ 643 STATE 0 "normal" 1 "adaptive_cruise_control" 3 "emergency_braking";
+VAL_ 921 CRUISE_CONTROL_STATE 2 "disabled" 11 "hold" 10 "hold_waiting_user_cmd" 6 "enabled" 5 "faulted";
+VAL_ 1042 LDA_ALERT 3 "hold with continuous beep" 2 "LDA unavailable" 1 "hold" 0 "none";
+VAL_ 1042 BARRIERS 3 "both" 2 "right" 1 "left" 0 "none";
+VAL_ 1042 RIGHT_LINE 3 "orange" 2 "faded" 1 "solid" 0 "none";
+VAL_ 1042 LEFT_LINE 3 "orange" 2 "faded" 1 "solid" 0 "none";
+VAL_ 1553 UNITS 1 "km" 2 "miles";
+VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left";
+VAL_ 1161 TSGN1 1 "speed sign" 0 "none";
+VAL_ 1161 TSGN2 1 "speed sign" 0 "none";
+VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none";
+VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry";
+VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none";
+
+
+CM_ "CHFFR_METRIC 37 STEER_ANGLE STEER_ANGLE 0.36 180";
+
+CM_ "lexus_nxt_2015_pt.dbc starts here"
+
+
+
+BO_ 550 BRAKE_MODULE: 8 XXX
+ SG_ BRAKE_PRESSURE : 0|9@0+ (1,0) [0|511] "" XXX
+ SG_ BRAKE_POSITION : 16|9@0+ (1,0) [0|511] "" XXX
+ SG_ BRAKE_PRESSED : 37|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 581 GAS_PEDAL_ALT: 5 XXX
+ SG_ GAS_PEDAL : 23|8@0+ (0.005,0) [0|1] "" XXX
+
+BO_ 705 GAS_PEDAL: 8 XXX
+ SG_ GAS_RELEASED : 3|1@0+ (1,0) [0|1] "" XXX
+ SG_ GAS_PEDAL : 55|8@0+ (0.005,0) [0|1] "" XXX
+
+BO_ 608 STEER_TORQUE_SENSOR: 8 XXX
+ SG_ STEER_TORQUE_EPS : 47|16@0- (1.0,0) [-20000|20000] "" XXX
+ SG_ STEER_TORQUE_DRIVER : 15|16@0- (1,0) [-32768|32767] "" XXX
+ SG_ STEER_OVERRIDE : 0|1@0+ (1,0) [0|1] "" XXX
+ SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
+ SG_ STEER_ANGLE : 31|16@0- (0.0573,0) [-500|500] "" XXX
+
+BO_ 610 EPS_STATUS: 5 EPS
+ SG_ IPAS_STATE : 3|4@0+ (1,0) [0|15] "" XXX
+ SG_ LKA_STATE : 31|7@0+ (1,0) [0|127] "" XXX
+ SG_ TYPE : 24|1@0+ (1,0) [0|1] "" XXX
+ SG_ CHECKSUM : 39|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 956 GEAR_PACKET: 8 XXX
+ SG_ GEAR : 13|6@0+ (1,0) [0|63] "" XXX
+
+BO_ 1009 PCM_CRUISE_ALT: 8 XXX
+ SG_ MAIN_ON : 13|1@0+ (1,0) [0|3] "" XXX
+ SG_ CRUISE_STATE : 10|1@0+ (1,0) [0|1] "" XXX
+ SG_ SET_SPEED : 23|8@0+ (1,0) [0|255] "mph" XXX
+
+BO_ 1599 LIGHT_STALK_ISH: 8 SCM
+ SG_ AUTO_HIGH_BEAM : 19|1@0+ (1,0) [0|1] "" XXX
+
+CM_ SG_ 550 BRAKE_PRESSURE "seems prop to pedal force";
+CM_ SG_ 550 BRAKE_POSITION "seems proportional to pedal displacement, unclear the max value of 0x1c8";
+CM_ SG_ 610 TYPE "seems 1 on Corolla, 0 on all others";
+CM_ SG_ 1009 SET_SPEED "units seem to be whatever the car is set to";
+VAL_ 956 GEAR 0 "D" 1 "S" 8 "N" 16 "R" 32 "P";
+VAL_ 610 IPAS_STATE 5 "override" 3 "enabled" 1 "disabled";
+VAL_ 610 LKA_STATE 25 "temporary_fault" 9 "temporary_fault2" 5 "active" 1 "standby";
diff --git a/scripts/btg_mode.sh b/scripts/btg_mode.sh
new file mode 100755
index 000000000..b1e96d21d
--- /dev/null
+++ b/scripts/btg_mode.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/bash
+
+if [ $1 -eq 1 ]; then
+ printf %s "1" > /data/params/d/DragonBTG
+fi
+if [ $1 -eq 0 ]; then
+ printf %s "0" > /data/params/d/DragonBTG
+fi
+
+rm -rf /data/openpilot/selfdrive/boardd/boardd && reboot
\ No newline at end of file
diff --git a/scripts/rebuild.sh b/scripts/rebuild.sh
new file mode 100755
index 000000000..b35318891
--- /dev/null
+++ b/scripts/rebuild.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/bash
+
+export LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib
+export HOME=/data/data/com.termux/files/home
+export PATH=/usr/local/bin:/data/data/com.termux/files/usr/bin:/data/data/com.termux/files/usr/sbin:/data/data/com.termux/files/usr/bin/applets:/bin:/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin:/data/data/com.termux/files/usr/bin/git
+printf %s "1" > /data/params/d/DragonUpdating
+cd /data/openpilot || exit
+git reset --hard @{u}
+git clean -xdf
+rm -fr /tmp/scons_cache/
+find . -type f -name '*.py[co]' -delete -o -type d -name __pycache__ -delete
+scons --clean
+reboot
\ No newline at end of file
diff --git a/scripts/reset_update.sh b/scripts/reset_update.sh
new file mode 100755
index 000000000..2b2bbffbb
--- /dev/null
+++ b/scripts/reset_update.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/bash
+
+export LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib
+export HOME=/data/data/com.termux/files/home
+export PATH=/usr/local/bin:/data/data/com.termux/files/usr/bin:/data/data/com.termux/files/usr/sbin:/data/data/com.termux/files/usr/bin/applets:/bin:/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin:/data/data/com.termux/files/usr/bin/git
+export PYTHONPATH=/data/openpilot
+printf %s "1" > /data/params/d/DragonUpdating
+rm /data/openpilot/panda/board/obj/panda.bin
+cd /data/openpilot && git fetch --all && git reset --hard @{u} && git clean -xdf && scons --clean && reboot
\ No newline at end of file
diff --git a/scripts/toyota_dsu_mode.sh b/scripts/toyota_dsu_mode.sh
new file mode 100755
index 000000000..dec14c793
--- /dev/null
+++ b/scripts/toyota_dsu_mode.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/bash
+
+export LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib
+export HOME=/data/data/com.termux/files/home
+export PATH=/usr/local/bin:/data/data/com.termux/files/usr/bin:/data/data/com.termux/files/usr/sbin:/data/data/com.termux/files/usr/bin/applets:/bin:/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin:/data/data/com.termux/files/usr/bin/python
+export PYTHONPATH=/data/openpilot
+value=`cat /data/params/d/DragonToyotaStockDSU`
+if [ $value -eq "1" ]; then
+ printf %s "0" > /data/params/d/DragonEnableLogger
+ printf %s "0" > /data/params/d/DragonEnableUploader
+fi
\ No newline at end of file
diff --git a/scripts/update_panda_firmware.sh b/scripts/update_panda_firmware.sh
new file mode 100755
index 000000000..e61b4a3c6
--- /dev/null
+++ b/scripts/update_panda_firmware.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/bash
+
+export LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib
+export HOME=/data/data/com.termux/files/home
+export PATH=/usr/local/bin:/data/data/com.termux/files/usr/bin:/data/data/com.termux/files/usr/sbin:/data/data/com.termux/files/usr/bin/applets:/bin:/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin:/data/data/com.termux/files/usr/bin/python
+export PYTHONPATH=/data/openpilot
+printf %s "1" > /data/params/d/DragonUpdating
+rm /data/openpilot/panda/board/obj/panda.bin
+cd /data/openpilot/panda ; pkill -f boardd ; python -c "from panda import Panda; Panda().flash()" && reboot
\ No newline at end of file
diff --git a/selfdrive/assets/images/button_home.png b/selfdrive/assets/images/button_home.png
index 9f52faf9e..aa90a78c4 100644
Binary files a/selfdrive/assets/images/button_home.png and b/selfdrive/assets/images/button_home.png differ
diff --git a/selfdrive/assets/img_spinner_comma.png b/selfdrive/assets/img_spinner_comma.png
index 16109557f..aa90a78c4 100644
Binary files a/selfdrive/assets/img_spinner_comma.png and b/selfdrive/assets/img_spinner_comma.png differ
diff --git a/selfdrive/assets/locales/alerts.pot b/selfdrive/assets/locales/alerts.pot
new file mode 100644
index 000000000..0580c29d9
--- /dev/null
+++ b/selfdrive/assets/locales/alerts.pot
@@ -0,0 +1,486 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR , YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-04-23 17:17+1000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: controls/lib/alerts.py:82 controls/lib/alerts.py:89
+msgid "BRAKE!"
+msgstr ""
+
+#: controls/lib/alerts.py:83 controls/lib/alerts.py:90
+msgid "Risk of Collision"
+msgstr ""
+
+#: controls/lib/alerts.py:96 controls/lib/alerts.py:103
+#: controls/lib/alerts.py:110 controls/lib/alerts.py:215
+#: controls/lib/alerts.py:229 controls/lib/alerts.py:263
+#: controls/lib/alerts.py:824
+msgid "TAKE CONTROL"
+msgstr ""
+
+#: controls/lib/alerts.py:97
+msgid "Turn Exceeds Steering Limit"
+msgstr ""
+
+#: controls/lib/alerts.py:104 controls/lib/alerts.py:111
+#: controls/lib/alerts.py:209
+msgid "Steering Temporarily Unavailable"
+msgstr ""
+
+#: controls/lib/alerts.py:117
+msgid "KEEP EYES ON ROAD: Driver Distracted"
+msgstr ""
+
+#: controls/lib/alerts.py:124
+msgid "KEEP EYES ON ROAD"
+msgstr ""
+
+#: controls/lib/alerts.py:125
+msgid "Driver Appears Distracted"
+msgstr ""
+
+#: controls/lib/alerts.py:131 controls/lib/alerts.py:152
+msgid "DISENGAGE IMMEDIATELY"
+msgstr ""
+
+#: controls/lib/alerts.py:132
+msgid "Driver Was Distracted"
+msgstr ""
+
+#: controls/lib/alerts.py:138
+msgid "TOUCH STEERING WHEEL: No Face Detected"
+msgstr ""
+
+#: controls/lib/alerts.py:145
+msgid "TOUCH STEERING WHEEL"
+msgstr ""
+
+#: controls/lib/alerts.py:146
+msgid "Driver Is Unresponsive"
+msgstr ""
+
+#: controls/lib/alerts.py:153
+msgid "Driver Was Unresponsive"
+msgstr ""
+
+#: controls/lib/alerts.py:159
+msgid "CHECK DRIVER FACE VISIBILITY"
+msgstr ""
+
+#: controls/lib/alerts.py:160
+msgid "Driver Monitor Model Output Uncertain"
+msgstr ""
+
+#: controls/lib/alerts.py:166
+msgid "DISENGAGEMENT REQUIRED"
+msgstr ""
+
+#: controls/lib/alerts.py:167 controls/lib/alerts.py:593
+msgid "Not in Geofenced Area"
+msgstr ""
+
+#: controls/lib/alerts.py:173
+msgid "Be ready to take over at any time"
+msgstr ""
+
+#: controls/lib/alerts.py:174 controls/lib/alerts.py:181
+#: controls/lib/alerts.py:188 controls/lib/alerts.py:195
+msgid "Always keep hands on wheel and eyes on road"
+msgstr ""
+
+#: controls/lib/alerts.py:180
+msgid "WARNING: This branch is not tested"
+msgstr ""
+
+#: controls/lib/alerts.py:187
+msgid "Dashcam mode"
+msgstr ""
+
+#: controls/lib/alerts.py:194
+msgid "Dashcam mode for unsupported car"
+msgstr ""
+
+#: controls/lib/alerts.py:201 controls/lib/alerts.py:356
+#: controls/lib/alerts.py:363 controls/lib/alerts.py:370
+#: controls/lib/alerts.py:377 controls/lib/alerts.py:384
+#: controls/lib/alerts.py:391 controls/lib/alerts.py:398
+#: controls/lib/alerts.py:405 controls/lib/alerts.py:412
+#: controls/lib/alerts.py:419 controls/lib/alerts.py:426
+#: controls/lib/alerts.py:433 controls/lib/alerts.py:441
+#: controls/lib/alerts.py:449 controls/lib/alerts.py:456
+#: controls/lib/alerts.py:463 controls/lib/alerts.py:470
+#: controls/lib/alerts.py:477 controls/lib/alerts.py:484
+#: controls/lib/alerts.py:491 controls/lib/alerts.py:498
+#: controls/lib/alerts.py:505 controls/lib/alerts.py:512
+msgid "TAKE CONTROL IMMEDIATELY"
+msgstr ""
+
+#: controls/lib/alerts.py:202
+msgid "Ethical Dilemma Detected"
+msgstr ""
+
+#: controls/lib/alerts.py:208 controls/lib/alerts.py:271
+#: controls/lib/alerts.py:278 controls/lib/alerts.py:285
+#: controls/lib/alerts.py:292 controls/lib/alerts.py:299
+#: controls/lib/alerts.py:306 controls/lib/alerts.py:313
+#: controls/lib/alerts.py:320 controls/lib/alerts.py:327
+#: controls/lib/alerts.py:334 controls/lib/alerts.py:341
+#: controls/lib/alerts.py:348 controls/lib/alerts.py:543
+#: controls/lib/alerts.py:550 controls/lib/alerts.py:557
+#: controls/lib/alerts.py:564 controls/lib/alerts.py:571
+#: controls/lib/alerts.py:578 controls/lib/alerts.py:585
+#: controls/lib/alerts.py:592 controls/lib/alerts.py:599
+#: controls/lib/alerts.py:606 controls/lib/alerts.py:613
+#: controls/lib/alerts.py:620 controls/lib/alerts.py:627
+#: controls/lib/alerts.py:634 controls/lib/alerts.py:641
+#: controls/lib/alerts.py:648 controls/lib/alerts.py:655
+#: controls/lib/alerts.py:662 controls/lib/alerts.py:669
+#: controls/lib/alerts.py:676 controls/lib/alerts.py:683
+#: controls/lib/alerts.py:690 controls/lib/alerts.py:697
+#: controls/lib/alerts.py:704 controls/lib/alerts.py:718
+msgid "openpilot Unavailable"
+msgstr ""
+
+#: controls/lib/alerts.py:216
+msgid "Resume Driving Manually"
+msgstr ""
+
+#: controls/lib/alerts.py:222
+msgid "STOPPED"
+msgstr ""
+
+#: controls/lib/alerts.py:223
+msgid "Press Resume to Move"
+msgstr ""
+
+#: controls/lib/alerts.py:230
+msgid "Steer Unavailable Below "
+msgstr ""
+
+#: controls/lib/alerts.py:236
+msgid "DEBUG ALERT"
+msgstr ""
+
+#: controls/lib/alerts.py:242
+msgid "Steer Left to Start Lane Change"
+msgstr ""
+
+#: controls/lib/alerts.py:243 controls/lib/alerts.py:250
+#: controls/lib/alerts.py:257 controls/lib/alerts.py:833
+#: controls/lib/alerts.py:840 controls/lib/alerts.py:847
+msgid "Monitor Other Vehicles"
+msgstr ""
+
+#: controls/lib/alerts.py:249
+msgid "Steer Right to Start Lane Change"
+msgstr ""
+
+#: controls/lib/alerts.py:256 controls/lib/alerts.py:846
+msgid "Changing Lane"
+msgstr ""
+
+#: controls/lib/alerts.py:264 controls/lib/alerts.py:614
+msgid "Vision Model Output Uncertain"
+msgstr ""
+
+#: controls/lib/alerts.py:272
+msgid "Main Switch Off"
+msgstr ""
+
+#: controls/lib/alerts.py:279
+msgid "Calibration Needs Data. Upload Drive, Try Again"
+msgstr ""
+
+#: controls/lib/alerts.py:286
+msgid "Out of Storage Space"
+msgstr ""
+
+#: controls/lib/alerts.py:293
+msgid "Pedal Pressed During Attempt"
+msgstr ""
+
+#: controls/lib/alerts.py:300
+msgid "Speed Too Low"
+msgstr ""
+
+#: controls/lib/alerts.py:307
+msgid "Brake Hold Active"
+msgstr ""
+
+#: controls/lib/alerts.py:314
+msgid "Park Brake Engaged"
+msgstr ""
+
+#: controls/lib/alerts.py:321 controls/lib/alerts.py:478
+#: controls/lib/alerts.py:642
+msgid "Cruise Fault: Restart the Car"
+msgstr ""
+
+#: controls/lib/alerts.py:328 controls/lib/alerts.py:406
+msgid "Low Battery"
+msgstr ""
+
+#: controls/lib/alerts.py:335 controls/lib/alerts.py:782
+msgid "No Data from Device Sensors"
+msgstr ""
+
+#: controls/lib/alerts.py:342 controls/lib/alerts.py:789
+msgid "Speaker not found"
+msgstr ""
+
+#: controls/lib/alerts.py:349
+msgid "Distraction Level Too High"
+msgstr ""
+
+#: controls/lib/alerts.py:357
+msgid "System Overheated"
+msgstr ""
+
+#: controls/lib/alerts.py:364 controls/lib/alerts.py:551
+msgid "Gear not D"
+msgstr ""
+
+#: controls/lib/alerts.py:371
+msgid "Calibration Invalid: Reposition Device and Recalibrate"
+msgstr ""
+
+#: controls/lib/alerts.py:378 controls/lib/alerts.py:565
+msgid "Calibration in Progress"
+msgstr ""
+
+#: controls/lib/alerts.py:385
+msgid "Door Open"
+msgstr ""
+
+#: controls/lib/alerts.py:392
+msgid "Seatbelt Unlatched"
+msgstr ""
+
+#: controls/lib/alerts.py:399 controls/lib/alerts.py:586
+msgid "ESP Off"
+msgstr ""
+
+#: controls/lib/alerts.py:413 controls/lib/alerts.py:684
+msgid "Communication Issue between Processes"
+msgstr ""
+
+#: controls/lib/alerts.py:420 controls/lib/alerts.py:691
+msgid "Radar Communication Issue"
+msgstr ""
+
+#: controls/lib/alerts.py:427 controls/lib/alerts.py:434
+#: controls/lib/alerts.py:600 controls/lib/alerts.py:607
+msgid "Radar Error: Restart the Car"
+msgstr ""
+
+#: controls/lib/alerts.py:442 controls/lib/alerts.py:705
+msgid "Low Memory: Reboot Your Device"
+msgstr ""
+
+#: controls/lib/alerts.py:450 controls/lib/alerts.py:621
+msgid "Controls Failed"
+msgstr ""
+
+#: controls/lib/alerts.py:457
+msgid "Controls Mismatch"
+msgstr ""
+
+#: controls/lib/alerts.py:464 controls/lib/alerts.py:628
+msgid "CAN Error: Check Connections"
+msgstr ""
+
+#: controls/lib/alerts.py:471 controls/lib/alerts.py:635
+msgid "LKAS Fault: Restart the Car"
+msgstr ""
+
+#: controls/lib/alerts.py:485
+msgid "Gas Fault: Restart the Car"
+msgstr ""
+
+#: controls/lib/alerts.py:492 controls/lib/alerts.py:656
+msgid "Reverse Gear"
+msgstr ""
+
+#: controls/lib/alerts.py:499
+msgid "Cruise Is Off"
+msgstr ""
+
+#: controls/lib/alerts.py:506 controls/lib/alerts.py:677
+msgid "Planner Solution Error"
+msgstr ""
+
+#: controls/lib/alerts.py:513 controls/lib/alerts.py:719
+#: controls/lib/alerts.py:810
+msgid "Harness Malfunction"
+msgstr ""
+
+#: controls/lib/alerts.py:521 controls/lib/alerts.py:528
+msgid "openpilot Canceled"
+msgstr ""
+
+#: controls/lib/alerts.py:522
+msgid "No close lead car"
+msgstr ""
+
+#: controls/lib/alerts.py:529
+msgid "Speed too low"
+msgstr ""
+
+#: controls/lib/alerts.py:535 controls/lib/alerts.py:711
+msgid "Speed Too High"
+msgstr ""
+
+#: controls/lib/alerts.py:536
+msgid "Slow down to resume operation"
+msgstr ""
+
+#: controls/lib/alerts.py:544
+msgid "System overheated"
+msgstr ""
+
+#: controls/lib/alerts.py:558
+msgid "Calibration Invalid: Reposition Device & Recalibrate"
+msgstr ""
+
+#: controls/lib/alerts.py:572
+msgid "Door open"
+msgstr ""
+
+#: controls/lib/alerts.py:579
+msgid "Seatbelt unlatched"
+msgstr ""
+
+#: controls/lib/alerts.py:649
+msgid "Gas Error: Restart the Car"
+msgstr ""
+
+#: controls/lib/alerts.py:663
+msgid "Cruise is Off"
+msgstr ""
+
+#: controls/lib/alerts.py:670
+msgid "No Close Lead Car"
+msgstr ""
+
+#: controls/lib/alerts.py:698
+msgid "Please Connect to Internet"
+msgstr ""
+
+#: controls/lib/alerts.py:712
+msgid "Slow down to engage"
+msgstr ""
+
+#: controls/lib/alerts.py:726
+msgid "LKAS Fault: Restart the car to engage"
+msgstr ""
+
+#: controls/lib/alerts.py:733 controls/lib/alerts.py:740
+msgid "Cruise Fault: Restart the car to engage"
+msgstr ""
+
+#: controls/lib/alerts.py:747
+msgid "Calibration in Progress: "
+msgstr ""
+
+#: controls/lib/alerts.py:748
+msgid "Drive Above "
+msgstr ""
+
+#: controls/lib/alerts.py:754
+msgid "Unsupported Giraffe Configuration"
+msgstr ""
+
+#: controls/lib/alerts.py:755
+msgid "Visit comma.ai/tg"
+msgstr ""
+
+#: controls/lib/alerts.py:761
+msgid "Stock LKAS is turned on"
+msgstr ""
+
+#: controls/lib/alerts.py:762
+msgid "Turn off stock LKAS to engage"
+msgstr ""
+
+#: controls/lib/alerts.py:768
+msgid "Please connect to Internet"
+msgstr ""
+
+#: controls/lib/alerts.py:769
+msgid "An Update Check Is Required to Engage"
+msgstr ""
+
+#: controls/lib/alerts.py:775
+msgid "Community Feature Detected"
+msgstr ""
+
+#: controls/lib/alerts.py:776
+msgid "Enable Community Features in Developer Settings"
+msgstr ""
+
+#: controls/lib/alerts.py:783 controls/lib/alerts.py:790
+#: controls/lib/alerts.py:797
+msgid "Reboot your Device"
+msgstr ""
+
+#: controls/lib/alerts.py:796
+msgid "RAM Critically Low"
+msgstr ""
+
+#: controls/lib/alerts.py:803
+msgid "Dashcam Mode"
+msgstr ""
+
+#: controls/lib/alerts.py:804
+msgid "Car Unrecognized"
+msgstr ""
+
+#: controls/lib/alerts.py:811
+msgid "Please Check Hardware"
+msgstr ""
+
+#: controls/lib/alerts.py:817
+msgid "Vehicle Parameter Identification Failed"
+msgstr ""
+
+#: controls/lib/alerts.py:825
+msgid "Lane Departure Detected"
+msgstr ""
+
+#: controls/lib/alerts.py:832
+msgid "Left ALC will engage in 3 seconds"
+msgstr ""
+
+#: controls/lib/alerts.py:839
+msgid "Right ALC will engage in 3 seconds"
+msgstr ""
+
+#: controls/lib/alerts.py:853
+msgid "STEERING REQUIRED: Lane Keeping OFF"
+msgstr ""
+
+#: controls/lib/alerts.py:860
+msgid "STEERING REQUIRED: Blinkers ON"
+msgstr ""
+
+#: controls/lib/alerts.py:866
+msgid "Lead Car Is Moving"
+msgstr ""
+
+#: controls/lib/alerts.py:872
+msgid "Lead Car Detected"
+msgstr ""
diff --git a/selfdrive/assets/locales/en-US/LC_MESSAGES/alerts.mo b/selfdrive/assets/locales/en-US/LC_MESSAGES/alerts.mo
new file mode 100644
index 000000000..69e36dbee
Binary files /dev/null and b/selfdrive/assets/locales/en-US/LC_MESSAGES/alerts.mo differ
diff --git a/selfdrive/assets/locales/en-US/LC_MESSAGES/alerts.po b/selfdrive/assets/locales/en-US/LC_MESSAGES/alerts.po
new file mode 100644
index 000000000..2f3b21386
--- /dev/null
+++ b/selfdrive/assets/locales/en-US/LC_MESSAGES/alerts.po
@@ -0,0 +1,486 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR , YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-04-23 17:17+1000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: controls/lib/alerts.py:82 controls/lib/alerts.py:89
+msgid "BRAKE!"
+msgstr ""
+
+#: controls/lib/alerts.py:83 controls/lib/alerts.py:90
+msgid "Risk of Collision"
+msgstr ""
+
+#: controls/lib/alerts.py:96 controls/lib/alerts.py:103
+#: controls/lib/alerts.py:110 controls/lib/alerts.py:215
+#: controls/lib/alerts.py:229 controls/lib/alerts.py:263
+#: controls/lib/alerts.py:824
+msgid "TAKE CONTROL"
+msgstr ""
+
+#: controls/lib/alerts.py:97
+msgid "Turn Exceeds Steering Limit"
+msgstr ""
+
+#: controls/lib/alerts.py:104 controls/lib/alerts.py:111
+#: controls/lib/alerts.py:209
+msgid "Steering Temporarily Unavailable"
+msgstr ""
+
+#: controls/lib/alerts.py:117
+msgid "KEEP EYES ON ROAD: Driver Distracted"
+msgstr ""
+
+#: controls/lib/alerts.py:124
+msgid "KEEP EYES ON ROAD"
+msgstr ""
+
+#: controls/lib/alerts.py:125
+msgid "Driver Appears Distracted"
+msgstr ""
+
+#: controls/lib/alerts.py:131 controls/lib/alerts.py:152
+msgid "DISENGAGE IMMEDIATELY"
+msgstr ""
+
+#: controls/lib/alerts.py:132
+msgid "Driver Was Distracted"
+msgstr ""
+
+#: controls/lib/alerts.py:138
+msgid "TOUCH STEERING WHEEL: No Face Detected"
+msgstr ""
+
+#: controls/lib/alerts.py:145
+msgid "TOUCH STEERING WHEEL"
+msgstr ""
+
+#: controls/lib/alerts.py:146
+msgid "Driver Is Unresponsive"
+msgstr ""
+
+#: controls/lib/alerts.py:153
+msgid "Driver Was Unresponsive"
+msgstr ""
+
+#: controls/lib/alerts.py:159
+msgid "CHECK DRIVER FACE VISIBILITY"
+msgstr ""
+
+#: controls/lib/alerts.py:160
+msgid "Driver Monitor Model Output Uncertain"
+msgstr ""
+
+#: controls/lib/alerts.py:166
+msgid "DISENGAGEMENT REQUIRED"
+msgstr ""
+
+#: controls/lib/alerts.py:167 controls/lib/alerts.py:593
+msgid "Not in Geofenced Area"
+msgstr ""
+
+#: controls/lib/alerts.py:173
+msgid "Be ready to take over at any time"
+msgstr ""
+
+#: controls/lib/alerts.py:174 controls/lib/alerts.py:181
+#: controls/lib/alerts.py:188 controls/lib/alerts.py:195
+msgid "Always keep hands on wheel and eyes on road"
+msgstr ""
+
+#: controls/lib/alerts.py:180
+msgid "WARNING: This branch is not tested"
+msgstr ""
+
+#: controls/lib/alerts.py:187
+msgid "Dashcam mode"
+msgstr ""
+
+#: controls/lib/alerts.py:194
+msgid "Dashcam mode for unsupported car"
+msgstr ""
+
+#: controls/lib/alerts.py:201 controls/lib/alerts.py:356
+#: controls/lib/alerts.py:363 controls/lib/alerts.py:370
+#: controls/lib/alerts.py:377 controls/lib/alerts.py:384
+#: controls/lib/alerts.py:391 controls/lib/alerts.py:398
+#: controls/lib/alerts.py:405 controls/lib/alerts.py:412
+#: controls/lib/alerts.py:419 controls/lib/alerts.py:426
+#: controls/lib/alerts.py:433 controls/lib/alerts.py:441
+#: controls/lib/alerts.py:449 controls/lib/alerts.py:456
+#: controls/lib/alerts.py:463 controls/lib/alerts.py:470
+#: controls/lib/alerts.py:477 controls/lib/alerts.py:484
+#: controls/lib/alerts.py:491 controls/lib/alerts.py:498
+#: controls/lib/alerts.py:505 controls/lib/alerts.py:512
+msgid "TAKE CONTROL IMMEDIATELY"
+msgstr ""
+
+#: controls/lib/alerts.py:202
+msgid "Ethical Dilemma Detected"
+msgstr ""
+
+#: controls/lib/alerts.py:208 controls/lib/alerts.py:271
+#: controls/lib/alerts.py:278 controls/lib/alerts.py:285
+#: controls/lib/alerts.py:292 controls/lib/alerts.py:299
+#: controls/lib/alerts.py:306 controls/lib/alerts.py:313
+#: controls/lib/alerts.py:320 controls/lib/alerts.py:327
+#: controls/lib/alerts.py:334 controls/lib/alerts.py:341
+#: controls/lib/alerts.py:348 controls/lib/alerts.py:543
+#: controls/lib/alerts.py:550 controls/lib/alerts.py:557
+#: controls/lib/alerts.py:564 controls/lib/alerts.py:571
+#: controls/lib/alerts.py:578 controls/lib/alerts.py:585
+#: controls/lib/alerts.py:592 controls/lib/alerts.py:599
+#: controls/lib/alerts.py:606 controls/lib/alerts.py:613
+#: controls/lib/alerts.py:620 controls/lib/alerts.py:627
+#: controls/lib/alerts.py:634 controls/lib/alerts.py:641
+#: controls/lib/alerts.py:648 controls/lib/alerts.py:655
+#: controls/lib/alerts.py:662 controls/lib/alerts.py:669
+#: controls/lib/alerts.py:676 controls/lib/alerts.py:683
+#: controls/lib/alerts.py:690 controls/lib/alerts.py:697
+#: controls/lib/alerts.py:704 controls/lib/alerts.py:718
+msgid "openpilot Unavailable"
+msgstr ""
+
+#: controls/lib/alerts.py:216
+msgid "Resume Driving Manually"
+msgstr ""
+
+#: controls/lib/alerts.py:222
+msgid "STOPPED"
+msgstr ""
+
+#: controls/lib/alerts.py:223
+msgid "Press Resume to Move"
+msgstr ""
+
+#: controls/lib/alerts.py:230
+msgid "Steer Unavailable Below "
+msgstr ""
+
+#: controls/lib/alerts.py:236
+msgid "DEBUG ALERT"
+msgstr ""
+
+#: controls/lib/alerts.py:242
+msgid "Steer Left to Start Lane Change"
+msgstr ""
+
+#: controls/lib/alerts.py:243 controls/lib/alerts.py:250
+#: controls/lib/alerts.py:257 controls/lib/alerts.py:833
+#: controls/lib/alerts.py:840 controls/lib/alerts.py:847
+msgid "Monitor Other Vehicles"
+msgstr ""
+
+#: controls/lib/alerts.py:249
+msgid "Steer Right to Start Lane Change"
+msgstr ""
+
+#: controls/lib/alerts.py:256 controls/lib/alerts.py:846
+msgid "Changing Lane"
+msgstr ""
+
+#: controls/lib/alerts.py:264 controls/lib/alerts.py:614
+msgid "Vision Model Output Uncertain"
+msgstr ""
+
+#: controls/lib/alerts.py:272
+msgid "Main Switch Off"
+msgstr ""
+
+#: controls/lib/alerts.py:279
+msgid "Calibration Needs Data. Upload Drive, Try Again"
+msgstr ""
+
+#: controls/lib/alerts.py:286
+msgid "Out of Storage Space"
+msgstr ""
+
+#: controls/lib/alerts.py:293
+msgid "Pedal Pressed During Attempt"
+msgstr ""
+
+#: controls/lib/alerts.py:300
+msgid "Speed Too Low"
+msgstr ""
+
+#: controls/lib/alerts.py:307
+msgid "Brake Hold Active"
+msgstr ""
+
+#: controls/lib/alerts.py:314
+msgid "Park Brake Engaged"
+msgstr ""
+
+#: controls/lib/alerts.py:321 controls/lib/alerts.py:478
+#: controls/lib/alerts.py:642
+msgid "Cruise Fault: Restart the Car"
+msgstr ""
+
+#: controls/lib/alerts.py:328 controls/lib/alerts.py:406
+msgid "Low Battery"
+msgstr ""
+
+#: controls/lib/alerts.py:335 controls/lib/alerts.py:782
+msgid "No Data from Device Sensors"
+msgstr ""
+
+#: controls/lib/alerts.py:342 controls/lib/alerts.py:789
+msgid "Speaker not found"
+msgstr ""
+
+#: controls/lib/alerts.py:349
+msgid "Distraction Level Too High"
+msgstr ""
+
+#: controls/lib/alerts.py:357
+msgid "System Overheated"
+msgstr ""
+
+#: controls/lib/alerts.py:364 controls/lib/alerts.py:551
+msgid "Gear not D"
+msgstr ""
+
+#: controls/lib/alerts.py:371
+msgid "Calibration Invalid: Reposition Device and Recalibrate"
+msgstr ""
+
+#: controls/lib/alerts.py:378 controls/lib/alerts.py:565
+msgid "Calibration in Progress"
+msgstr ""
+
+#: controls/lib/alerts.py:385
+msgid "Door Open"
+msgstr ""
+
+#: controls/lib/alerts.py:392
+msgid "Seatbelt Unlatched"
+msgstr ""
+
+#: controls/lib/alerts.py:399 controls/lib/alerts.py:586
+msgid "ESP Off"
+msgstr ""
+
+#: controls/lib/alerts.py:413 controls/lib/alerts.py:684
+msgid "Communication Issue between Processes"
+msgstr ""
+
+#: controls/lib/alerts.py:420 controls/lib/alerts.py:691
+msgid "Radar Communication Issue"
+msgstr ""
+
+#: controls/lib/alerts.py:427 controls/lib/alerts.py:434
+#: controls/lib/alerts.py:600 controls/lib/alerts.py:607
+msgid "Radar Error: Restart the Car"
+msgstr ""
+
+#: controls/lib/alerts.py:442 controls/lib/alerts.py:705
+msgid "Low Memory: Reboot Your Device"
+msgstr ""
+
+#: controls/lib/alerts.py:450 controls/lib/alerts.py:621
+msgid "Controls Failed"
+msgstr ""
+
+#: controls/lib/alerts.py:457
+msgid "Controls Mismatch"
+msgstr ""
+
+#: controls/lib/alerts.py:464 controls/lib/alerts.py:628
+msgid "CAN Error: Check Connections"
+msgstr ""
+
+#: controls/lib/alerts.py:471 controls/lib/alerts.py:635
+msgid "LKAS Fault: Restart the Car"
+msgstr ""
+
+#: controls/lib/alerts.py:485
+msgid "Gas Fault: Restart the Car"
+msgstr ""
+
+#: controls/lib/alerts.py:492 controls/lib/alerts.py:656
+msgid "Reverse Gear"
+msgstr ""
+
+#: controls/lib/alerts.py:499
+msgid "Cruise Is Off"
+msgstr ""
+
+#: controls/lib/alerts.py:506 controls/lib/alerts.py:677
+msgid "Planner Solution Error"
+msgstr ""
+
+#: controls/lib/alerts.py:513 controls/lib/alerts.py:719
+#: controls/lib/alerts.py:810
+msgid "Harness Malfunction"
+msgstr ""
+
+#: controls/lib/alerts.py:521 controls/lib/alerts.py:528
+msgid "openpilot Canceled"
+msgstr ""
+
+#: controls/lib/alerts.py:522
+msgid "No close lead car"
+msgstr ""
+
+#: controls/lib/alerts.py:529
+msgid "Speed too low"
+msgstr ""
+
+#: controls/lib/alerts.py:535 controls/lib/alerts.py:711
+msgid "Speed Too High"
+msgstr ""
+
+#: controls/lib/alerts.py:536
+msgid "Slow down to resume operation"
+msgstr ""
+
+#: controls/lib/alerts.py:544
+msgid "System overheated"
+msgstr ""
+
+#: controls/lib/alerts.py:558
+msgid "Calibration Invalid: Reposition Device & Recalibrate"
+msgstr ""
+
+#: controls/lib/alerts.py:572
+msgid "Door open"
+msgstr ""
+
+#: controls/lib/alerts.py:579
+msgid "Seatbelt unlatched"
+msgstr ""
+
+#: controls/lib/alerts.py:649
+msgid "Gas Error: Restart the Car"
+msgstr ""
+
+#: controls/lib/alerts.py:663
+msgid "Cruise is Off"
+msgstr ""
+
+#: controls/lib/alerts.py:670
+msgid "No Close Lead Car"
+msgstr ""
+
+#: controls/lib/alerts.py:698
+msgid "Please Connect to Internet"
+msgstr ""
+
+#: controls/lib/alerts.py:712
+msgid "Slow down to engage"
+msgstr ""
+
+#: controls/lib/alerts.py:726
+msgid "LKAS Fault: Restart the car to engage"
+msgstr ""
+
+#: controls/lib/alerts.py:733 controls/lib/alerts.py:740
+msgid "Cruise Fault: Restart the car to engage"
+msgstr ""
+
+#: controls/lib/alerts.py:747
+msgid "Calibration in Progress: "
+msgstr ""
+
+#: controls/lib/alerts.py:748
+msgid "Drive Above "
+msgstr ""
+
+#: controls/lib/alerts.py:754
+msgid "Unsupported Giraffe Configuration"
+msgstr ""
+
+#: controls/lib/alerts.py:755
+msgid "Visit comma.ai/tg"
+msgstr ""
+
+#: controls/lib/alerts.py:761
+msgid "Stock LKAS is turned on"
+msgstr ""
+
+#: controls/lib/alerts.py:762
+msgid "Turn off stock LKAS to engage"
+msgstr ""
+
+#: controls/lib/alerts.py:768
+msgid "Please connect to Internet"
+msgstr ""
+
+#: controls/lib/alerts.py:769
+msgid "An Update Check Is Required to Engage"
+msgstr ""
+
+#: controls/lib/alerts.py:775
+msgid "Community Feature Detected"
+msgstr ""
+
+#: controls/lib/alerts.py:776
+msgid "Enable Community Features in Developer Settings"
+msgstr ""
+
+#: controls/lib/alerts.py:783 controls/lib/alerts.py:790
+#: controls/lib/alerts.py:797
+msgid "Reboot your Device"
+msgstr ""
+
+#: controls/lib/alerts.py:796
+msgid "RAM Critically Low"
+msgstr ""
+
+#: controls/lib/alerts.py:803
+msgid "Dashcam Mode"
+msgstr ""
+
+#: controls/lib/alerts.py:804
+msgid "Car Unrecognized"
+msgstr ""
+
+#: controls/lib/alerts.py:811
+msgid "Please Check Hardware"
+msgstr ""
+
+#: controls/lib/alerts.py:817
+msgid "Vehicle Parameter Identification Failed"
+msgstr ""
+
+#: controls/lib/alerts.py:825
+msgid "Lane Departure Detected"
+msgstr ""
+
+#: controls/lib/alerts.py:832
+msgid "Left ALC will engage in 3 seconds"
+msgstr ""
+
+#: controls/lib/alerts.py:839
+msgid "Right ALC will engage in 3 seconds"
+msgstr ""
+
+#: controls/lib/alerts.py:853
+msgid "STEERING REQUIRED: Lane Keeping OFF"
+msgstr ""
+
+#: controls/lib/alerts.py:860
+msgid "STEERING REQUIRED: Blinkers ON"
+msgstr ""
+
+#: controls/lib/alerts.py:866
+msgid "Lead Car Is Moving"
+msgstr ""
+
+#: controls/lib/alerts.py:872
+msgid "Lead Car Detected"
+msgstr ""
diff --git a/selfdrive/assets/locales/zh-CN/LC_MESSAGES/alerts.mo b/selfdrive/assets/locales/zh-CN/LC_MESSAGES/alerts.mo
new file mode 100644
index 000000000..2e02a7bc1
Binary files /dev/null and b/selfdrive/assets/locales/zh-CN/LC_MESSAGES/alerts.mo differ
diff --git a/selfdrive/assets/locales/zh-CN/LC_MESSAGES/alerts.po b/selfdrive/assets/locales/zh-CN/LC_MESSAGES/alerts.po
new file mode 100644
index 000000000..65c8df739
--- /dev/null
+++ b/selfdrive/assets/locales/zh-CN/LC_MESSAGES/alerts.po
@@ -0,0 +1,486 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR , YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-04-23 17:17+1000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Rick Lan \n"
+"Language-Team: LANGUAGE \n"
+"Language: zh-CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: controls/lib/alerts.py:82 controls/lib/alerts.py:89
+msgid "BRAKE!"
+msgstr "刹车!"
+
+#: controls/lib/alerts.py:83 controls/lib/alerts.py:90
+msgid "Risk of Collision"
+msgstr "有碰撞的风险"
+
+#: controls/lib/alerts.py:96 controls/lib/alerts.py:103
+#: controls/lib/alerts.py:110 controls/lib/alerts.py:215
+#: controls/lib/alerts.py:229 controls/lib/alerts.py:263
+#: controls/lib/alerts.py:824
+msgid "TAKE CONTROL"
+msgstr "接管控制"
+
+#: controls/lib/alerts.py:97
+msgid "Turn Exceeds Steering Limit"
+msgstr "弯道超过横向操控限制"
+
+#: controls/lib/alerts.py:104 controls/lib/alerts.py:111
+#: controls/lib/alerts.py:209
+msgid "Steering Temporarily Unavailable"
+msgstr "横向控制暂时失效"
+
+#: controls/lib/alerts.py:117
+msgid "KEEP EYES ON ROAD: Driver Distracted"
+msgstr "注意路况:驾驶分心"
+
+#: controls/lib/alerts.py:124
+msgid "KEEP EYES ON ROAD"
+msgstr "注意路况"
+
+#: controls/lib/alerts.py:125
+msgid "Driver Appears Distracted"
+msgstr "驾驶分心"
+
+#: controls/lib/alerts.py:131 controls/lib/alerts.py:152
+msgid "DISENGAGE IMMEDIATELY"
+msgstr "立即解除"
+
+#: controls/lib/alerts.py:132
+msgid "Driver Was Distracted"
+msgstr "驾驶分心"
+
+#: controls/lib/alerts.py:138
+msgid "TOUCH STEERING WHEEL: No Face Detected"
+msgstr "请触碰方向盘:未侦测到驾驶面容"
+
+#: controls/lib/alerts.py:145
+msgid "TOUCH STEERING WHEEL"
+msgstr "请触碰方向盘"
+
+#: controls/lib/alerts.py:146
+msgid "Driver Is Unresponsive"
+msgstr "驾驶没有反应"
+
+#: controls/lib/alerts.py:153
+msgid "Driver Was Unresponsive"
+msgstr "驾驶没有反应"
+
+#: controls/lib/alerts.py:159
+msgid "CHECK DRIVER FACE VISIBILITY"
+msgstr "请检查驾驶面部的可见度"
+
+#: controls/lib/alerts.py:160
+msgid "Driver Monitor Model Output Uncertain"
+msgstr "驾驶监控模型判断不明确"
+
+#: controls/lib/alerts.py:166
+msgid "DISENGAGEMENT REQUIRED"
+msgstr "请马上解除"
+
+#: controls/lib/alerts.py:167 controls/lib/alerts.py:593
+msgid "Not in Geofenced Area"
+msgstr "不在地理围栏区域之内"
+
+#: controls/lib/alerts.py:173
+msgid "Be ready to take over at any time"
+msgstr "请准备好随时接管"
+
+#: controls/lib/alerts.py:174 controls/lib/alerts.py:181
+#: controls/lib/alerts.py:188 controls/lib/alerts.py:195
+msgid "Always keep hands on wheel and eyes on road"
+msgstr "将手放在方向盘上并持续监视路况"
+
+#: controls/lib/alerts.py:180
+msgid "WARNING: This branch is not tested"
+msgstr "注意:这个分支未经过测试"
+
+#: controls/lib/alerts.py:187
+msgid "Dashcam mode"
+msgstr "行车记录模式"
+
+#: controls/lib/alerts.py:194
+msgid "Dashcam mode for unsupported car"
+msgstr "行车记录模式 (尚未支援车种)"
+
+#: controls/lib/alerts.py:201 controls/lib/alerts.py:356
+#: controls/lib/alerts.py:363 controls/lib/alerts.py:370
+#: controls/lib/alerts.py:377 controls/lib/alerts.py:384
+#: controls/lib/alerts.py:391 controls/lib/alerts.py:398
+#: controls/lib/alerts.py:405 controls/lib/alerts.py:412
+#: controls/lib/alerts.py:419 controls/lib/alerts.py:426
+#: controls/lib/alerts.py:433 controls/lib/alerts.py:441
+#: controls/lib/alerts.py:449 controls/lib/alerts.py:456
+#: controls/lib/alerts.py:463 controls/lib/alerts.py:470
+#: controls/lib/alerts.py:477 controls/lib/alerts.py:484
+#: controls/lib/alerts.py:491 controls/lib/alerts.py:498
+#: controls/lib/alerts.py:505 controls/lib/alerts.py:512
+msgid "TAKE CONTROL IMMEDIATELY"
+msgstr "即刻接管控制"
+
+#: controls/lib/alerts.py:202
+msgid "Ethical Dilemma Detected"
+msgstr ""
+
+#: controls/lib/alerts.py:208 controls/lib/alerts.py:271
+#: controls/lib/alerts.py:278 controls/lib/alerts.py:285
+#: controls/lib/alerts.py:292 controls/lib/alerts.py:299
+#: controls/lib/alerts.py:306 controls/lib/alerts.py:313
+#: controls/lib/alerts.py:320 controls/lib/alerts.py:327
+#: controls/lib/alerts.py:334 controls/lib/alerts.py:341
+#: controls/lib/alerts.py:348 controls/lib/alerts.py:543
+#: controls/lib/alerts.py:550 controls/lib/alerts.py:557
+#: controls/lib/alerts.py:564 controls/lib/alerts.py:571
+#: controls/lib/alerts.py:578 controls/lib/alerts.py:585
+#: controls/lib/alerts.py:592 controls/lib/alerts.py:599
+#: controls/lib/alerts.py:606 controls/lib/alerts.py:613
+#: controls/lib/alerts.py:620 controls/lib/alerts.py:627
+#: controls/lib/alerts.py:634 controls/lib/alerts.py:641
+#: controls/lib/alerts.py:648 controls/lib/alerts.py:655
+#: controls/lib/alerts.py:662 controls/lib/alerts.py:669
+#: controls/lib/alerts.py:676 controls/lib/alerts.py:683
+#: controls/lib/alerts.py:690 controls/lib/alerts.py:697
+#: controls/lib/alerts.py:704 controls/lib/alerts.py:718
+msgid "openpilot Unavailable"
+msgstr "无法使用 openpilot"
+
+#: controls/lib/alerts.py:216
+msgid "Resume Driving Manually"
+msgstr "请自行恢復驾驶"
+
+#: controls/lib/alerts.py:222
+msgid "STOPPED"
+msgstr "已停止"
+
+#: controls/lib/alerts.py:223
+msgid "Press Resume to Move"
+msgstr "请按 RES 继续"
+
+#: controls/lib/alerts.py:230
+msgid "Steer Unavailable Below "
+msgstr "横向控制暂时失效,车速低于 "
+
+#: controls/lib/alerts.py:236
+msgid "DEBUG ALERT"
+msgstr "除错用警示讯息"
+
+#: controls/lib/alerts.py:242
+msgid "Steer Left to Start Lane Change"
+msgstr "请往左打方向盘切换至左车道"
+
+#: controls/lib/alerts.py:243 controls/lib/alerts.py:250
+#: controls/lib/alerts.py:257 controls/lib/alerts.py:833
+#: controls/lib/alerts.py:840 controls/lib/alerts.py:847
+msgid "Monitor Other Vehicles"
+msgstr "请注意其它车辆"
+
+#: controls/lib/alerts.py:249
+msgid "Steer Right to Start Lane Change"
+msgstr "请往右打方向盘切换至右车道"
+
+#: controls/lib/alerts.py:256 controls/lib/alerts.py:846
+msgid "Changing Lane"
+msgstr "切换车道中"
+
+#: controls/lib/alerts.py:264 controls/lib/alerts.py:614
+msgid "Vision Model Output Uncertain"
+msgstr "视觉模型判断不明确"
+
+#: controls/lib/alerts.py:272
+msgid "Main Switch Off"
+msgstr "主开关已关闭"
+
+#: controls/lib/alerts.py:279
+msgid "Calibration Needs Data. Upload Drive, Try Again"
+msgstr "校正需要数据,请上传您的行车数据后再重试一次"
+
+#: controls/lib/alerts.py:286
+msgid "Out of Storage Space"
+msgstr "存储空间不足"
+
+#: controls/lib/alerts.py:293
+msgid "Pedal Pressed During Attempt"
+msgstr "启用时侦测到驾驶踩踏油门/刹车"
+
+#: controls/lib/alerts.py:300
+msgid "Speed Too Low"
+msgstr "车速过慢"
+
+#: controls/lib/alerts.py:307
+msgid "Brake Hold Active"
+msgstr "驻车煞车已启用"
+
+#: controls/lib/alerts.py:314
+msgid "Park Brake Engaged"
+msgstr "电子驻车已启动"
+
+#: controls/lib/alerts.py:321 controls/lib/alerts.py:478
+#: controls/lib/alerts.py:642
+msgid "Cruise Fault: Restart the Car"
+msgstr "巡航系统错误:请重新发动车辆"
+
+#: controls/lib/alerts.py:328 controls/lib/alerts.py:406
+msgid "Low Battery"
+msgstr "电量过低"
+
+#: controls/lib/alerts.py:335 controls/lib/alerts.py:782
+msgid "No Data from Device Sensors"
+msgstr "未收到装置传感器数据"
+
+#: controls/lib/alerts.py:342 controls/lib/alerts.py:789
+msgid "Speaker not found"
+msgstr "找不到音效装置"
+
+#: controls/lib/alerts.py:349
+msgid "Distraction Level Too High"
+msgstr "驾驶分心太多次"
+
+#: controls/lib/alerts.py:357
+msgid "System Overheated"
+msgstr "系统过热"
+
+#: controls/lib/alerts.py:364 controls/lib/alerts.py:551
+msgid "Gear not D"
+msgstr "不在 D 档位"
+
+#: controls/lib/alerts.py:371
+msgid "Calibration Invalid: Reposition Device and Recalibrate"
+msgstr "校准无效:请将装置放于新的位置并重新校准"
+
+#: controls/lib/alerts.py:378 controls/lib/alerts.py:565
+msgid "Calibration in Progress"
+msgstr "正在校准中"
+
+#: controls/lib/alerts.py:385
+msgid "Door Open"
+msgstr "车门开启"
+
+#: controls/lib/alerts.py:392
+msgid "Seatbelt Unlatched"
+msgstr "安全带未繫"
+
+#: controls/lib/alerts.py:399 controls/lib/alerts.py:586
+msgid "ESP Off"
+msgstr "ESP 关闭"
+
+#: controls/lib/alerts.py:413 controls/lib/alerts.py:684
+msgid "Communication Issue between Processes"
+msgstr "行程间出现通讯问题"
+
+#: controls/lib/alerts.py:420 controls/lib/alerts.py:691
+msgid "Radar Communication Issue"
+msgstr "雷达通讯出现问题"
+
+#: controls/lib/alerts.py:427 controls/lib/alerts.py:434
+#: controls/lib/alerts.py:600 controls/lib/alerts.py:607
+msgid "Radar Error: Restart the Car"
+msgstr "雷达讯号错误:请重新发动车辆"
+
+#: controls/lib/alerts.py:442 controls/lib/alerts.py:705
+msgid "Low Memory: Reboot Your Device"
+msgstr "记忆体不足:请重启您的装置"
+
+#: controls/lib/alerts.py:450 controls/lib/alerts.py:621
+msgid "Controls Failed"
+msgstr "控制发生错误"
+
+#: controls/lib/alerts.py:457
+msgid "Controls Mismatch"
+msgstr "控制不匹配"
+
+#: controls/lib/alerts.py:464 controls/lib/alerts.py:628
+msgid "CAN Error: Check Connections"
+msgstr "CAN 讯号错误:请检查线路"
+
+#: controls/lib/alerts.py:471 controls/lib/alerts.py:635
+msgid "LKAS Fault: Restart the Car"
+msgstr "LKAS 错误:请重新发动车辆"
+
+#: controls/lib/alerts.py:485
+msgid "Gas Fault: Restart the Car"
+msgstr "油门错误:请重新发动车辆"
+
+#: controls/lib/alerts.py:492 controls/lib/alerts.py:656
+msgid "Reverse Gear"
+msgstr "切换至倒车档"
+
+#: controls/lib/alerts.py:499
+msgid "Cruise Is Off"
+msgstr "巡航系统关闭"
+
+#: controls/lib/alerts.py:506 controls/lib/alerts.py:677
+msgid "Planner Solution Error"
+msgstr "Planner Solution 错误"
+
+#: controls/lib/alerts.py:513 controls/lib/alerts.py:719
+#: controls/lib/alerts.py:810
+msgid "Harness Malfunction"
+msgstr "Harness 故障"
+
+#: controls/lib/alerts.py:521 controls/lib/alerts.py:528
+msgid "openpilot Canceled"
+msgstr "openpilot 已取消"
+
+#: controls/lib/alerts.py:522
+msgid "No close lead car"
+msgstr "前方没有车辆"
+
+#: controls/lib/alerts.py:529
+msgid "Speed too low"
+msgstr "车速过慢"
+
+#: controls/lib/alerts.py:535 controls/lib/alerts.py:711
+msgid "Speed Too High"
+msgstr "车速过快"
+
+#: controls/lib/alerts.py:536
+msgid "Slow down to resume operation"
+msgstr "请减速后再启用"
+
+#: controls/lib/alerts.py:544
+msgid "System overheated"
+msgstr "系统过热"
+
+#: controls/lib/alerts.py:558
+msgid "Calibration Invalid: Reposition Device & Recalibrate"
+msgstr "校准无效:请将装置放于新的位置并重新校准"
+
+#: controls/lib/alerts.py:572
+msgid "Door open"
+msgstr "车门未关"
+
+#: controls/lib/alerts.py:579
+msgid "Seatbelt unlatched"
+msgstr "安全带未繫"
+
+#: controls/lib/alerts.py:649
+msgid "Gas Error: Restart the Car"
+msgstr "油门错误:请重新发动车辆"
+
+#: controls/lib/alerts.py:663
+msgid "Cruise is Off"
+msgstr "巡航系统关闭"
+
+#: controls/lib/alerts.py:670
+msgid "No Close Lead Car"
+msgstr "前方没有车辆"
+
+#: controls/lib/alerts.py:698
+msgid "Please Connect to Internet"
+msgstr "请连接网路"
+
+#: controls/lib/alerts.py:712
+msgid "Slow down to engage"
+msgstr "请减速后再启用"
+
+#: controls/lib/alerts.py:726
+msgid "LKAS Fault: Restart the car to engage"
+msgstr "LKAS 错误:请重新发动车辆"
+
+#: controls/lib/alerts.py:733 controls/lib/alerts.py:740
+msgid "Cruise Fault: Restart the car to engage"
+msgstr "巡航系统错误:请重新发动车辆"
+
+#: controls/lib/alerts.py:747
+msgid "Calibration in Progress: "
+msgstr "正在校准相机中:"
+
+#: controls/lib/alerts.py:748
+msgid "Drive Above "
+msgstr "车速请高于"
+
+#: controls/lib/alerts.py:754
+msgid "Unsupported Giraffe Configuration"
+msgstr "未支援的 Giraffe 设置"
+
+#: controls/lib/alerts.py:755
+msgid "Visit comma.ai/tg"
+msgstr "请查阅 comma.ai/tg"
+
+#: controls/lib/alerts.py:761
+msgid "Stock LKAS is turned on"
+msgstr "原厂 LKAS 已开启"
+
+#: controls/lib/alerts.py:762
+msgid "Turn off stock LKAS to engage"
+msgstr "需关闭原厂 LKAS 才能启用"
+
+#: controls/lib/alerts.py:768
+msgid "Please connect to Internet"
+msgstr "请连接网路"
+
+#: controls/lib/alerts.py:769
+msgid "An Update Check Is Required to Engage"
+msgstr "需检查更新后才能启用"
+
+#: controls/lib/alerts.py:775
+msgid "Community Feature Detected"
+msgstr "检测到社群开发功能"
+
+#: controls/lib/alerts.py:776
+msgid "Enable Community Features in Developer Settings"
+msgstr "请至开发人员设定裡启用社群开发功能"
+
+#: controls/lib/alerts.py:783 controls/lib/alerts.py:790
+#: controls/lib/alerts.py:797
+msgid "Reboot your Device"
+msgstr "请重启装置"
+
+#: controls/lib/alerts.py:796
+msgid "RAM Critically Low"
+msgstr "记忆体严重不足"
+
+#: controls/lib/alerts.py:803
+msgid "Dashcam Mode"
+msgstr "行车记录模式"
+
+#: controls/lib/alerts.py:804
+msgid "Car Unrecognized"
+msgstr "无法辨识车款"
+
+#: controls/lib/alerts.py:811
+msgid "Please Check Hardware"
+msgstr "请检查硬体"
+
+#: controls/lib/alerts.py:817
+msgid "Vehicle Parameter Identification Failed"
+msgstr "车子参数识别失败"
+
+#: controls/lib/alerts.py:825
+msgid "Lane Departure Detected"
+msgstr "偏离车道"
+
+#: controls/lib/alerts.py:832
+msgid "Left ALC will engage in 3 seconds"
+msgstr "准备自动切至左车道"
+
+#: controls/lib/alerts.py:839
+msgid "Right ALC will engage in 3 seconds"
+msgstr "准备自动切至右车道"
+
+#: controls/lib/alerts.py:853
+msgid "STEERING REQUIRED: Lane Keeping OFF"
+msgstr "请接管方向盘:车道维持关闭"
+
+#: controls/lib/alerts.py:860
+msgid "STEERING REQUIRED: Blinkers ON"
+msgstr "请接管方向盘:方向灯开启"
+
+#: controls/lib/alerts.py:866
+msgid "Lead Car Is Moving"
+msgstr "前方车辆车移动中"
+
+#: controls/lib/alerts.py:872
+msgid "Lead Car Detected"
+msgstr "侦测到前方车辆"
diff --git a/selfdrive/assets/locales/zh-TW/LC_MESSAGES/alerts.mo b/selfdrive/assets/locales/zh-TW/LC_MESSAGES/alerts.mo
new file mode 100644
index 000000000..96b9bf3ec
Binary files /dev/null and b/selfdrive/assets/locales/zh-TW/LC_MESSAGES/alerts.mo differ
diff --git a/selfdrive/assets/locales/zh-TW/LC_MESSAGES/alerts.po b/selfdrive/assets/locales/zh-TW/LC_MESSAGES/alerts.po
new file mode 100644
index 000000000..760a14b5a
--- /dev/null
+++ b/selfdrive/assets/locales/zh-TW/LC_MESSAGES/alerts.po
@@ -0,0 +1,486 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR , YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-04-23 17:17+1000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Rick Lan \n"
+"Language-Team: LANGUAGE \n"
+"Language: zh-TW\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: controls/lib/alerts.py:82 controls/lib/alerts.py:89
+msgid "BRAKE!"
+msgstr "剎車!"
+
+#: controls/lib/alerts.py:83 controls/lib/alerts.py:90
+msgid "Risk of Collision"
+msgstr "有碰撞的風險"
+
+#: controls/lib/alerts.py:96 controls/lib/alerts.py:103
+#: controls/lib/alerts.py:110 controls/lib/alerts.py:215
+#: controls/lib/alerts.py:229 controls/lib/alerts.py:263
+#: controls/lib/alerts.py:824
+msgid "TAKE CONTROL"
+msgstr "接管控制"
+
+#: controls/lib/alerts.py:97
+msgid "Turn Exceeds Steering Limit"
+msgstr "彎道超過橫向操控限制"
+
+#: controls/lib/alerts.py:104 controls/lib/alerts.py:111
+#: controls/lib/alerts.py:209
+msgid "Steering Temporarily Unavailable"
+msgstr "橫向控制暫時失效"
+
+#: controls/lib/alerts.py:117
+msgid "KEEP EYES ON ROAD: Driver Distracted"
+msgstr "注意路況:駕駛分心"
+
+#: controls/lib/alerts.py:124
+msgid "KEEP EYES ON ROAD"
+msgstr "注意路況"
+
+#: controls/lib/alerts.py:125
+msgid "Driver Appears Distracted"
+msgstr "駕駛分心"
+
+#: controls/lib/alerts.py:131 controls/lib/alerts.py:152
+msgid "DISENGAGE IMMEDIATELY"
+msgstr "立即解除"
+
+#: controls/lib/alerts.py:132
+msgid "Driver Was Distracted"
+msgstr "駕駛分心"
+
+#: controls/lib/alerts.py:138
+msgid "TOUCH STEERING WHEEL: No Face Detected"
+msgstr "請觸碰方向盤:未偵測到駕駛面容"
+
+#: controls/lib/alerts.py:145
+msgid "TOUCH STEERING WHEEL"
+msgstr "請觸碰方向盤"
+
+#: controls/lib/alerts.py:146
+msgid "Driver Is Unresponsive"
+msgstr "駕駛沒有反應"
+
+#: controls/lib/alerts.py:153
+msgid "Driver Was Unresponsive"
+msgstr "駕駛沒有反應"
+
+#: controls/lib/alerts.py:159
+msgid "CHECK DRIVER FACE VISIBILITY"
+msgstr "請檢查駕駛面部的可見度"
+
+#: controls/lib/alerts.py:160
+msgid "Driver Monitor Model Output Uncertain"
+msgstr "駕駛監控模型判斷不明確"
+
+#: controls/lib/alerts.py:166
+msgid "DISENGAGEMENT REQUIRED"
+msgstr "請馬上解除"
+
+#: controls/lib/alerts.py:167 controls/lib/alerts.py:593
+msgid "Not in Geofenced Area"
+msgstr "不在地理圍欄區域之內"
+
+#: controls/lib/alerts.py:173
+msgid "Be ready to take over at any time"
+msgstr "請準備好隨時接管"
+
+#: controls/lib/alerts.py:174 controls/lib/alerts.py:181
+#: controls/lib/alerts.py:188 controls/lib/alerts.py:195
+msgid "Always keep hands on wheel and eyes on road"
+msgstr "將手放在方向盤上並持續監視路況"
+
+#: controls/lib/alerts.py:180
+msgid "WARNING: This branch is not tested"
+msgstr "注意:這個分支未經過測試"
+
+#: controls/lib/alerts.py:187
+msgid "Dashcam mode"
+msgstr "行車記錄模式"
+
+#: controls/lib/alerts.py:194
+msgid "Dashcam mode for unsupported car"
+msgstr "行車記錄模式 (尚未支援車種)"
+
+#: controls/lib/alerts.py:201 controls/lib/alerts.py:356
+#: controls/lib/alerts.py:363 controls/lib/alerts.py:370
+#: controls/lib/alerts.py:377 controls/lib/alerts.py:384
+#: controls/lib/alerts.py:391 controls/lib/alerts.py:398
+#: controls/lib/alerts.py:405 controls/lib/alerts.py:412
+#: controls/lib/alerts.py:419 controls/lib/alerts.py:426
+#: controls/lib/alerts.py:433 controls/lib/alerts.py:441
+#: controls/lib/alerts.py:449 controls/lib/alerts.py:456
+#: controls/lib/alerts.py:463 controls/lib/alerts.py:470
+#: controls/lib/alerts.py:477 controls/lib/alerts.py:484
+#: controls/lib/alerts.py:491 controls/lib/alerts.py:498
+#: controls/lib/alerts.py:505 controls/lib/alerts.py:512
+msgid "TAKE CONTROL IMMEDIATELY"
+msgstr "即刻接管控制"
+
+#: controls/lib/alerts.py:202
+msgid "Ethical Dilemma Detected"
+msgstr ""
+
+#: controls/lib/alerts.py:208 controls/lib/alerts.py:271
+#: controls/lib/alerts.py:278 controls/lib/alerts.py:285
+#: controls/lib/alerts.py:292 controls/lib/alerts.py:299
+#: controls/lib/alerts.py:306 controls/lib/alerts.py:313
+#: controls/lib/alerts.py:320 controls/lib/alerts.py:327
+#: controls/lib/alerts.py:334 controls/lib/alerts.py:341
+#: controls/lib/alerts.py:348 controls/lib/alerts.py:543
+#: controls/lib/alerts.py:550 controls/lib/alerts.py:557
+#: controls/lib/alerts.py:564 controls/lib/alerts.py:571
+#: controls/lib/alerts.py:578 controls/lib/alerts.py:585
+#: controls/lib/alerts.py:592 controls/lib/alerts.py:599
+#: controls/lib/alerts.py:606 controls/lib/alerts.py:613
+#: controls/lib/alerts.py:620 controls/lib/alerts.py:627
+#: controls/lib/alerts.py:634 controls/lib/alerts.py:641
+#: controls/lib/alerts.py:648 controls/lib/alerts.py:655
+#: controls/lib/alerts.py:662 controls/lib/alerts.py:669
+#: controls/lib/alerts.py:676 controls/lib/alerts.py:683
+#: controls/lib/alerts.py:690 controls/lib/alerts.py:697
+#: controls/lib/alerts.py:704 controls/lib/alerts.py:718
+msgid "openpilot Unavailable"
+msgstr "無法使用 openpilot"
+
+#: controls/lib/alerts.py:216
+msgid "Resume Driving Manually"
+msgstr "請自行恢復駕駛"
+
+#: controls/lib/alerts.py:222
+msgid "STOPPED"
+msgstr "已停止"
+
+#: controls/lib/alerts.py:223
+msgid "Press Resume to Move"
+msgstr "請按 RES 繼續"
+
+#: controls/lib/alerts.py:230
+msgid "Steer Unavailable Below "
+msgstr "橫向控制暫時失效,車速低於 "
+
+#: controls/lib/alerts.py:236
+msgid "DEBUG ALERT"
+msgstr "除錯用警示訊息"
+
+#: controls/lib/alerts.py:242
+msgid "Steer Left to Start Lane Change"
+msgstr "請往左打方向盤切換至左車道"
+
+#: controls/lib/alerts.py:243 controls/lib/alerts.py:250
+#: controls/lib/alerts.py:257 controls/lib/alerts.py:833
+#: controls/lib/alerts.py:840 controls/lib/alerts.py:847
+msgid "Monitor Other Vehicles"
+msgstr "請注意其它車輛"
+
+#: controls/lib/alerts.py:249
+msgid "Steer Right to Start Lane Change"
+msgstr "請往右打方向盤切換至右車道"
+
+#: controls/lib/alerts.py:256 controls/lib/alerts.py:846
+msgid "Changing Lane"
+msgstr "切換車道中"
+
+#: controls/lib/alerts.py:264 controls/lib/alerts.py:614
+msgid "Vision Model Output Uncertain"
+msgstr "視覺模型判斷不明確"
+
+#: controls/lib/alerts.py:272
+msgid "Main Switch Off"
+msgstr "主開關已關閉"
+
+#: controls/lib/alerts.py:279
+msgid "Calibration Needs Data. Upload Drive, Try Again"
+msgstr "校正需要數據,請上傳您的行車數據後再重試一次"
+
+#: controls/lib/alerts.py:286
+msgid "Out of Storage Space"
+msgstr "儲存空間不足"
+
+#: controls/lib/alerts.py:293
+msgid "Pedal Pressed During Attempt"
+msgstr "啟用時偵測到駕駛踩踏油門/剎車"
+
+#: controls/lib/alerts.py:300
+msgid "Speed Too Low"
+msgstr "車速過慢"
+
+#: controls/lib/alerts.py:307
+msgid "Brake Hold Active"
+msgstr "駐車煞車已啟用"
+
+#: controls/lib/alerts.py:314
+msgid "Park Brake Engaged"
+msgstr "電子駐車已啟動"
+
+#: controls/lib/alerts.py:321 controls/lib/alerts.py:478
+#: controls/lib/alerts.py:642
+msgid "Cruise Fault: Restart the Car"
+msgstr "巡航系統錯誤:請重新發動車輛"
+
+#: controls/lib/alerts.py:328 controls/lib/alerts.py:406
+msgid "Low Battery"
+msgstr "電量過低"
+
+#: controls/lib/alerts.py:335 controls/lib/alerts.py:782
+msgid "No Data from Device Sensors"
+msgstr "未收到裝置傳感器數據"
+
+#: controls/lib/alerts.py:342 controls/lib/alerts.py:789
+msgid "Speaker not found"
+msgstr "找不到音效裝置"
+
+#: controls/lib/alerts.py:349
+msgid "Distraction Level Too High"
+msgstr "駕駛分心太多次"
+
+#: controls/lib/alerts.py:357
+msgid "System Overheated"
+msgstr "系統過熱"
+
+#: controls/lib/alerts.py:364 controls/lib/alerts.py:551
+msgid "Gear not D"
+msgstr "不在 D 檔位"
+
+#: controls/lib/alerts.py:371
+msgid "Calibration Invalid: Reposition Device and Recalibrate"
+msgstr "校準無效:請將裝置放於新的位置並重新校準"
+
+#: controls/lib/alerts.py:378 controls/lib/alerts.py:565
+msgid "Calibration in Progress"
+msgstr "正在校準中"
+
+#: controls/lib/alerts.py:385
+msgid "Door Open"
+msgstr "車門開啟"
+
+#: controls/lib/alerts.py:392
+msgid "Seatbelt Unlatched"
+msgstr "安全帶未繫"
+
+#: controls/lib/alerts.py:399 controls/lib/alerts.py:586
+msgid "ESP Off"
+msgstr "ESP 關閉"
+
+#: controls/lib/alerts.py:413 controls/lib/alerts.py:684
+msgid "Communication Issue between Processes"
+msgstr "行程間出現通訊問題"
+
+#: controls/lib/alerts.py:420 controls/lib/alerts.py:691
+msgid "Radar Communication Issue"
+msgstr "雷達通訊出現問題"
+
+#: controls/lib/alerts.py:427 controls/lib/alerts.py:434
+#: controls/lib/alerts.py:600 controls/lib/alerts.py:607
+msgid "Radar Error: Restart the Car"
+msgstr "雷達訊號錯誤:請重新發動車輛"
+
+#: controls/lib/alerts.py:442 controls/lib/alerts.py:705
+msgid "Low Memory: Reboot Your Device"
+msgstr "記憶體不足:請重啟您的裝置"
+
+#: controls/lib/alerts.py:450 controls/lib/alerts.py:621
+msgid "Controls Failed"
+msgstr "控制發生錯誤"
+
+#: controls/lib/alerts.py:457
+msgid "Controls Mismatch"
+msgstr "控制不匹配"
+
+#: controls/lib/alerts.py:464 controls/lib/alerts.py:628
+msgid "CAN Error: Check Connections"
+msgstr "CAN 訊號錯誤:請檢查線路"
+
+#: controls/lib/alerts.py:471 controls/lib/alerts.py:635
+msgid "LKAS Fault: Restart the Car"
+msgstr "LKAS 錯誤:請重新發動車輛"
+
+#: controls/lib/alerts.py:485
+msgid "Gas Fault: Restart the Car"
+msgstr "油門錯誤:請重新發動車輛"
+
+#: controls/lib/alerts.py:492 controls/lib/alerts.py:656
+msgid "Reverse Gear"
+msgstr "切換至倒車檔"
+
+#: controls/lib/alerts.py:499
+msgid "Cruise Is Off"
+msgstr "巡航系統關閉"
+
+#: controls/lib/alerts.py:506 controls/lib/alerts.py:677
+msgid "Planner Solution Error"
+msgstr "Planner Solution 錯誤"
+
+#: controls/lib/alerts.py:513 controls/lib/alerts.py:719
+#: controls/lib/alerts.py:810
+msgid "Harness Malfunction"
+msgstr "Harness 故障"
+
+#: controls/lib/alerts.py:521 controls/lib/alerts.py:528
+msgid "openpilot Canceled"
+msgstr "openpilot 已取消"
+
+#: controls/lib/alerts.py:522
+msgid "No close lead car"
+msgstr "前方沒有車輛"
+
+#: controls/lib/alerts.py:529
+msgid "Speed too low"
+msgstr "車速過慢"
+
+#: controls/lib/alerts.py:535 controls/lib/alerts.py:711
+msgid "Speed Too High"
+msgstr "車速過快"
+
+#: controls/lib/alerts.py:536
+msgid "Slow down to resume operation"
+msgstr "請減速後再啟用"
+
+#: controls/lib/alerts.py:544
+msgid "System overheated"
+msgstr "系統過熱"
+
+#: controls/lib/alerts.py:558
+msgid "Calibration Invalid: Reposition Device & Recalibrate"
+msgstr "校準無效:請將裝置放於新的位置並重新校準"
+
+#: controls/lib/alerts.py:572
+msgid "Door open"
+msgstr "車門未關"
+
+#: controls/lib/alerts.py:579
+msgid "Seatbelt unlatched"
+msgstr "安全帶未繫"
+
+#: controls/lib/alerts.py:649
+msgid "Gas Error: Restart the Car"
+msgstr "油門錯誤:請重新發動車輛"
+
+#: controls/lib/alerts.py:663
+msgid "Cruise is Off"
+msgstr "巡航系統關閉"
+
+#: controls/lib/alerts.py:670
+msgid "No Close Lead Car"
+msgstr "前方沒有車輛"
+
+#: controls/lib/alerts.py:698
+msgid "Please Connect to Internet"
+msgstr "請連接網路"
+
+#: controls/lib/alerts.py:712
+msgid "Slow down to engage"
+msgstr "請減速後再啟用"
+
+#: controls/lib/alerts.py:726
+msgid "LKAS Fault: Restart the car to engage"
+msgstr "LKAS 錯誤:請重新發動車輛"
+
+#: controls/lib/alerts.py:733 controls/lib/alerts.py:740
+msgid "Cruise Fault: Restart the car to engage"
+msgstr "巡航系統錯誤:請重新發動車輛"
+
+#: controls/lib/alerts.py:747
+msgid "Calibration in Progress: "
+msgstr "正在校準相機中:"
+
+#: controls/lib/alerts.py:748
+msgid "Drive Above "
+msgstr "車速請高於"
+
+#: controls/lib/alerts.py:754
+msgid "Unsupported Giraffe Configuration"
+msgstr "未支援的 Giraffe 設置"
+
+#: controls/lib/alerts.py:755
+msgid "Visit comma.ai/tg"
+msgstr "請查閱 comma.ai/tg"
+
+#: controls/lib/alerts.py:761
+msgid "Stock LKAS is turned on"
+msgstr "原廠 LKAS 已開啟"
+
+#: controls/lib/alerts.py:762
+msgid "Turn off stock LKAS to engage"
+msgstr "需關閉原廠 LKAS 才能啟用"
+
+#: controls/lib/alerts.py:768
+msgid "Please connect to Internet"
+msgstr "請連接網路"
+
+#: controls/lib/alerts.py:769
+msgid "An Update Check Is Required to Engage"
+msgstr "需檢查更新後才能啟用"
+
+#: controls/lib/alerts.py:775
+msgid "Community Feature Detected"
+msgstr "檢測到社群開發功能"
+
+#: controls/lib/alerts.py:776
+msgid "Enable Community Features in Developer Settings"
+msgstr "請至開發人員設定裡啟用社群開發功能"
+
+#: controls/lib/alerts.py:783 controls/lib/alerts.py:790
+#: controls/lib/alerts.py:797
+msgid "Reboot your Device"
+msgstr "請重啟裝置"
+
+#: controls/lib/alerts.py:796
+msgid "RAM Critically Low"
+msgstr "記憶體嚴重不足"
+
+#: controls/lib/alerts.py:803
+msgid "Dashcam Mode"
+msgstr "行車記錄模式"
+
+#: controls/lib/alerts.py:804
+msgid "Car Unrecognized"
+msgstr "無法辨識車款"
+
+#: controls/lib/alerts.py:811
+msgid "Please Check Hardware"
+msgstr "請檢查硬體"
+
+#: controls/lib/alerts.py:817
+msgid "Vehicle Parameter Identification Failed"
+msgstr "車子參數識別失敗"
+
+#: controls/lib/alerts.py:825
+msgid "Lane Departure Detected"
+msgstr "偏離車道"
+
+#: controls/lib/alerts.py:832
+msgid "Left ALC will engage in 3 seconds"
+msgstr "準備自動切至左車道"
+
+#: controls/lib/alerts.py:839
+msgid "Right ALC will engage in 3 seconds"
+msgstr "準備自動切至右車道"
+
+#: controls/lib/alerts.py:853
+msgid "STEERING REQUIRED: Lane Keeping OFF"
+msgstr "請接管方向盤:車道維持關閉"
+
+#: controls/lib/alerts.py:860
+msgid "STEERING REQUIRED: Blinkers ON"
+msgstr "請接管方向盤:方向燈開啟"
+
+#: controls/lib/alerts.py:866
+msgid "Lead Car Is Moving"
+msgstr "前方車輛車移動中"
+
+#: controls/lib/alerts.py:872
+msgid "Lead Car Detected"
+msgstr "偵測到前方車輛"
diff --git a/selfdrive/boardd/SConscript b/selfdrive/boardd/SConscript
index 14c1ff780..bd60171c0 100644
--- a/selfdrive/boardd/SConscript
+++ b/selfdrive/boardd/SConscript
@@ -1,5 +1,11 @@
Import('env', 'common', 'messaging')
+# dragonpilot - Add read DragonBTG value
+if FindFile('DragonBTG', '/data/params/d') != None:
+ with open('/data/params/d/DragonBTG') as f:
+ if (int(f.read())) == 1:
+ env.Append(CCFLAGS='-DDragonBTG')
+
env.Program('boardd.cc', LIBS=['usb-1.0', common, messaging, 'pthread', 'zmq', 'capnp', 'kj'])
env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc'])
diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc
index d5990bc1d..ba4519809 100644
--- a/selfdrive/boardd/boardd.cc
+++ b/selfdrive/boardd/boardd.cc
@@ -84,6 +84,7 @@ void pigeon_init();
void *pigeon_thread(void *crap);
void *safety_setter_thread(void *s) {
+ #ifndef DragonBTG
// diagnostic only is the default, needed for VIN query
pthread_mutex_lock(&usb_lock);
libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::ELM327), 0, NULL, 0, TIMEOUT);
@@ -110,6 +111,7 @@ void *safety_setter_thread(void *s) {
pthread_mutex_lock(&usb_lock);
libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT);
pthread_mutex_unlock(&usb_lock);
+ #endif
char *value;
size_t value_sz = 0;
@@ -132,6 +134,9 @@ void *safety_setter_thread(void *s) {
capnp::FlatArrayMessageReader cmsg(amsg);
cereal::CarParams::Reader car_params = cmsg.getRoot();
+ LOGW("setting unsafety mode");
+ libusb_control_transfer(dev_handle, 0x40, 0xdf, 9, 0, NULL, 0, TIMEOUT);
+
int safety_model = int(car_params.getSafetyModel());
auto safety_param = car_params.getSafetyParam();
LOGW("setting safety model: %d with param %d", safety_model, safety_param);
@@ -397,12 +402,14 @@ void can_health(PubSocket *publisher) {
voltage_f = VOLTAGE_K * (health.voltage / 1000.0) + (1.0 - VOLTAGE_K) * voltage_f; // LPF
+ #ifndef DragonBTG
// Make sure CAN buses are live: safety_setter_thread does not work if Panda CAN are silent and there is only one other CAN node
if (health.safety_model == (uint8_t)(cereal::CarParams::SafetyModel::SILENT)) {
pthread_mutex_lock(&usb_lock);
libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT);
pthread_mutex_unlock(&usb_lock);
}
+ #endif
bool ignition = ((health.ignition_line != 0) || (health.ignition_can != 0));
@@ -446,12 +453,14 @@ void can_health(PubSocket *publisher) {
libusb_control_transfer(dev_handle, 0xc0, 0xe7, 1, 0, NULL, 0, TIMEOUT);
pthread_mutex_unlock(&usb_lock);
}
+ #ifndef DragonBTG
// set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect
if (!ignition && (health.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) {
pthread_mutex_lock(&usb_lock);
libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT);
pthread_mutex_unlock(&usb_lock);
}
+ #endif
#endif
// clear VIN, CarParams, and set new safety on car start
@@ -893,6 +902,11 @@ void *pigeon_thread(void *crap) {
if (pigeon_needs_init) {
pigeon_needs_init = false;
pigeon_init();
+ #ifdef DragonBTG
+ pthread_mutex_lock(&usb_lock);
+ libusb_control_transfer(dev_handle, 0x40, 0xdc, 2, 100, NULL, 0, TIMEOUT);
+ pthread_mutex_unlock(&usb_lock);
+ #endif
}
int alen = 0;
while (alen < 0xfc0) {
@@ -929,6 +943,9 @@ void *pigeon_thread(void *crap) {
int main() {
int err;
LOGW("starting boardd");
+ #ifdef DragonBTG
+ LOGW("boardd is running in DragonBTG mode");
+ #endif
// set process priority
err = set_realtime_priority(4);
diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py
index 9c11feb6b..858aa580e 100644
--- a/selfdrive/car/car_helpers.py
+++ b/selfdrive/car/car_helpers.py
@@ -1,5 +1,5 @@
import os
-from common.params import Params
+from common.params import Params, put_nonblocking
from common.basedir import BASEDIR
from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_known_cars
from selfdrive.car.vin import get_vin, VIN_UNKNOWN
@@ -7,6 +7,9 @@ from selfdrive.car.fw_versions import get_fw_versions, match_fw_to_car
from selfdrive.swaglog import cloudlog
import cereal.messaging as messaging
from selfdrive.car import gen_empty_fingerprint
+from common.dp import is_online
+import threading
+import selfdrive.crash as crash
from cereal import car
@@ -72,8 +75,10 @@ def only_toyota_left(candidate_cars):
# **** for use live only ****
def fingerprint(logcan, sendcan, has_relay):
fixed_fingerprint = os.environ.get('FINGERPRINT', "")
+ dragon_car_model = Params().get("DragonCustomModel", encoding="utf8")
+ has_dragon_car_model = True if len(dragon_car_model) else False
- if has_relay and not fixed_fingerprint:
+ if not has_dragon_car_model and has_relay and not fixed_fingerprint:
# Vin query only reliably works thorugh OBDII
bus = 1
@@ -105,7 +110,7 @@ def fingerprint(logcan, sendcan, has_relay):
frame = 0
frame_fingerprint = 10 # 0.1s
car_fingerprint = None
- done = False
+ done = True if has_dragon_car_model else False
while not done:
a = messaging.get_one_can(logcan)
@@ -143,19 +148,30 @@ def fingerprint(logcan, sendcan, has_relay):
source = car.CarParams.FingerprintSource.can
- # If FW query returns exactly 1 candidate, use it
- if len(fw_candidates) == 1:
- car_fingerprint = list(fw_candidates)[0]
- source = car.CarParams.FingerprintSource.fw
-
- if fixed_fingerprint:
- car_fingerprint = fixed_fingerprint
+ if has_dragon_car_model:
+ car_fingerprint = dragon_car_model
source = car.CarParams.FingerprintSource.fixed
+ else:
+ # If FW query returns exactly 1 candidate, use it
+ if len(fw_candidates) == 1:
+ car_fingerprint = list(fw_candidates)[0]
+ source = car.CarParams.FingerprintSource.fw
+ if fixed_fingerprint:
+ car_fingerprint = fixed_fingerprint
+ source = car.CarParams.FingerprintSource.fixed
+
+ put_nonblocking("DragonCarModel", car_fingerprint)
cloudlog.warning("fingerprinted %s", car_fingerprint)
return car_fingerprint, finger, vin, car_fw, source
+def log_fingerprinted(candidate):
+ while True:
+ crash.capture_warning("fingerprinted %s" % candidate)
+ break
+
+
def get_car(logcan, sendcan, has_relay=False):
candidate, fingerprints, vin, car_fw, source = fingerprint(logcan, sendcan, has_relay)
@@ -163,6 +179,10 @@ def get_car(logcan, sendcan, has_relay=False):
cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints)
candidate = "mock"
+ if is_online():
+ x = threading.Thread(target=log_fingerprinted, args=(candidate,))
+ x.start()
+
CarInterface, CarController, CarState = interfaces[candidate]
car_params = CarInterface.get_params(candidate, fingerprints, has_relay, car_fw)
car_params.carVin = vin
diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py
index 3bc1db870..32afb88e9 100755
--- a/selfdrive/car/chrysler/interface.py
+++ b/selfdrive/car/chrysler/interface.py
@@ -57,6 +57,7 @@ class CarInterface(CarInterfaceBase):
# returns a car.CarState
def update(self, c, can_strings):
+ self.dp_load_params('chrysler')
# ******************* do can recv *******************
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py
index 9ebaad366..d60e28332 100755
--- a/selfdrive/car/ford/interface.py
+++ b/selfdrive/car/ford/interface.py
@@ -51,6 +51,7 @@ class CarInterface(CarInterfaceBase):
# returns a car.CarState
def update(self, c, can_strings):
+ self.dp_load_params('ford')
# ******************* do can recv *******************
self.cp.update_strings(can_strings)
diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py
index ee4ef55de..6f14ba860 100755
--- a/selfdrive/car/gm/interface.py
+++ b/selfdrive/car/gm/interface.py
@@ -115,6 +115,7 @@ class CarInterface(CarInterfaceBase):
# returns a car.CarState
def update(self, c, can_strings):
+ self.dp_load_params('gm')
self.cp.update_strings(can_strings)
ret = self.CS.update(self.cp)
diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py
index a09dffce3..132e80c84 100644
--- a/selfdrive/car/honda/carcontroller.py
+++ b/selfdrive/car/honda/carcontroller.py
@@ -7,6 +7,10 @@ from selfdrive.car import create_gas_command
from selfdrive.car.honda import hondacan
from selfdrive.car.honda.values import CruiseButtons, CAR, VISUAL_HUD
from opendbc.can.packer import CANPacker
+from common.params import Params
+params = Params()
+from common.dp import get_last_modified
+from common.dp import common_controller_update, common_controller_ctrl
VisualAlert = car.CarControl.HUDControl.VisualAlert
@@ -72,7 +76,7 @@ def process_hud_alert(hud_alert):
HUDData = namedtuple("HUDData",
["pcm_accel", "v_cruise", "car",
- "lanes", "fcw", "acc_alert", "steer_required"])
+ "lanes", "fcw", "acc_alert", "steer_required", "dashed_lanes"])
class CarControllerParams():
def __init__(self, CP):
@@ -96,10 +100,25 @@ class CarController():
self.params = CarControllerParams(CP)
+ # dp
+ self.dragon_enable_steering_on_signal = False
+ self.dragon_lat_ctrl = True
+ self.dp_last_modified = None
+ self.lane_change_enabled = True
+
def update(self, enabled, CS, frame, actuators, \
pcm_speed, pcm_override, pcm_cancel_cmd, pcm_accel, \
hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert):
+ # dp
+ if frame % 500 == 0:
+ modified = get_last_modified()
+ if self.dp_last_modified != modified:
+ self.dragon_lat_ctrl, \
+ self.lane_change_enabled, \
+ self.dragon_enable_steering_on_signal = common_controller_update(self.lane_change_enabled)
+ self.dp_last_modified = modified
+
P = self.params
# *** apply brake hysteresis ***
@@ -114,7 +133,7 @@ class CarController():
self.brake_last = rate_limit(brake, self.brake_last, -2., DT_CTRL)
# vehicle hud display, wait for one update from 10Hz 0x304 msg
- if hud_show_lanes:
+ if hud_show_lanes and CS.lkMode:
hud_lanes = 1
else:
hud_lanes = 0
@@ -130,7 +149,7 @@ class CarController():
fcw_display, steer_required, acc_alert = process_hud_alert(hud_alert)
hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), hud_car,
- hud_lanes, fcw_display, acc_alert, steer_required)
+ hud_lanes, fcw_display, acc_alert, steer_required, CS.lkMode)
# **** process the car messages ****
@@ -139,11 +158,19 @@ class CarController():
apply_brake = int(clip(self.brake_last * P.BRAKE_MAX, 0, P.BRAKE_MAX - 1))
apply_steer = int(interp(-actuators.steer * P.STEER_MAX, P.STEER_LOOKUP_BP, P.STEER_LOOKUP_V))
- lkas_active = enabled and not CS.steer_not_allowed
+ lkas_active = enabled and not CS.steer_not_allowed and CS.lkMode
# Send CAN commands.
can_sends = []
+ # dp
+ lkas_active = common_controller_ctrl(enabled,
+ self.dragon_lat_ctrl,
+ self.dragon_enable_steering_on_signal,
+ CS.out.leftBlinker,
+ CS.out.rightBlinker,
+ lkas_active)
+
# Send steering command.
idx = frame % 4
can_sends.append(hondacan.create_steering_control(self.packer, apply_steer,
diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py
index 91124564e..7e2753d99 100644
--- a/selfdrive/car/honda/carstate.py
+++ b/selfdrive/car/honda/carstate.py
@@ -167,6 +167,9 @@ class CarState(CarStateBase):
self.v_cruise_pcm_prev = 0
self.cruise_mode = 0
+ # dp
+ self.lkMode = True
+
def update(self, cp, cp_cam):
ret = car.CarState.new_message()
@@ -221,6 +224,15 @@ class CarState(CarStateBase):
ret.steeringAngle = cp.vl["STEERING_SENSORS"]['STEER_ANGLE']
ret.steeringRate = cp.vl["STEERING_SENSORS"]['STEER_ANGLE_RATE']
+ # dp
+ # when user presses LKAS button on steering wheel
+ if self.cruise_setting == 1:
+ if cp.vl["SCM_BUTTONS"]["CRUISE_SETTING"] == 0:
+ if self.lkMode:
+ self.lkMode = False
+ else:
+ self.lkMode = True
+
self.cruise_setting = cp.vl["SCM_BUTTONS"]['CRUISE_SETTING']
self.cruise_buttons = cp.vl["SCM_BUTTONS"]['CRUISE_BUTTONS']
diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py
index d8d5cba7c..6f17c31f1 100755
--- a/selfdrive/car/honda/interface.py
+++ b/selfdrive/car/honda/interface.py
@@ -416,6 +416,7 @@ class CarInterface(CarInterfaceBase):
# returns a car.CarState
def update(self, c, can_strings):
+ self.dp_load_params('honda')
# ******************* do can recv *******************
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
@@ -429,6 +430,9 @@ class CarInterface(CarInterfaceBase):
ret.brakeLights = bool(self.CS.brake_switch or
c.actuators.brake > brakelights_threshold)
+ # dp
+ ret.lkMode = self.CS.lkMode
+
buttonEvents = []
if self.CS.cruise_buttons != self.CS.prev_cruise_buttons:
@@ -467,6 +471,8 @@ class CarInterface(CarInterfaceBase):
# events
events = self.create_common_events(ret, pcm_enable=False)
+ if not self.CS.lkMode:
+ events.append(create_event('manualSteeringRequired', [ET.WARNING]))
if self.CS.brake_error:
events.append(create_event('brakeUnavailable', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE, ET.PERMANENT]))
if self.CS.brake_hold and self.CS.CP.carFingerprint not in HONDA_BOSCH:
@@ -482,8 +488,6 @@ class CarInterface(CarInterfaceBase):
if self.CP.enableCruise and not ret.cruiseState.enabled and (c.actuators.brake <= 0. or not self.CP.openpilotLongitudinalControl):
# non loud alert if cruise disbales below 25mph as expected (+ a little margin)
if ret.vEgo < self.CP.minEnableSpeed + 2.:
- events.append(create_event('speedTooLow', [ET.IMMEDIATE_DISABLE]))
- else:
events.append(create_event("cruiseDisabled", [ET.IMMEDIATE_DISABLE]))
if self.CS.CP.minEnableSpeed > 0 and ret.vEgo < 0.001:
events.append(create_event('manualRestart', [ET.WARNING]))
diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py
index ca1008e28..0617d9ef1 100644
--- a/selfdrive/car/honda/values.py
+++ b/selfdrive/car/honda/values.py
@@ -54,7 +54,7 @@ FINGERPRINTS = {
148: 8, 228: 5, 304: 8, 330: 8, 344: 8, 380: 8, 399: 7, 401: 8, 420: 8, 427: 3, 432: 7, 441: 5, 446: 3, 450: 8, 464: 8, 477: 8, 479: 8, 495: 8, 545: 6, 662: 4, 773: 7, 777: 8, 780: 8, 804: 8, 806: 8, 808: 8, 829: 5, 862: 8, 884: 8, 891: 8, 927: 8, 929: 8, 1302: 8, 1600: 5, 1601: 8, 1652: 8
}],
CAR.ACCORDH: [{
- 148: 8, 228: 5, 304: 8, 330: 8, 344: 8, 380: 8, 387: 8, 388: 8, 399: 7, 419: 8, 420: 8, 427: 3, 432: 7, 441: 5, 450: 8, 464: 8, 477: 8, 479: 8, 495: 8, 525: 8, 545: 6, 662: 4, 773: 7, 777: 8, 780: 8, 804: 8, 806: 8, 808: 8, 829: 5, 862: 8, 884: 8, 891: 8, 927: 8, 929: 8, 1302: 8, 1600: 5, 1601: 8, 1652: 8
+ 148: 8, 228: 5, 304: 8, 330: 8, 344: 8, 380: 8, 387: 8, 388: 8, 399: 7, 408: 6, 419: 8, 420: 8, 427: 3, 432: 7, 441: 5, 450: 8, 464: 8, 475: 8, 477: 8, 479: 8, 481: 8, 495: 8, 525: 8, 545: 6, 662: 4, 773: 7, 777: 8, 780: 8, 804: 8, 806: 8, 808: 8, 829: 5, 862: 8, 884: 8, 891: 8, 927: 8, 929: 8, 1302: 8, 1416: 5, 1600: 5, 1601: 8, 1652: 8
}],
CAR.ACURA_ILX: [{
57: 3, 145: 8, 228: 5, 304: 8, 316: 8, 342: 6, 344: 8, 380: 8, 398: 3, 399: 7, 419: 8, 420: 8, 422: 8, 428: 8, 432: 7, 464: 8, 476: 4, 490: 8, 506: 8, 512: 6, 513: 6, 542: 7, 545: 4, 597: 8, 660: 8, 773: 7, 777: 8, 780: 8, 800: 8, 804: 8, 808: 8, 819: 7, 821: 5, 829: 5, 882: 2, 884: 7, 887: 8, 888: 8, 892: 8, 923: 2, 929: 4, 983: 8, 985: 3, 1024: 5, 1027: 5, 1029: 8, 1030: 5, 1034: 5, 1036: 8, 1039: 8, 1057: 5, 1064: 7, 1108: 8, 1365: 5,
@@ -81,8 +81,12 @@ FINGERPRINTS = {
CAR.CRV: [{
57: 3, 145: 8, 316: 8, 340: 8, 342: 6, 344: 8, 380: 8, 398: 3, 399: 6, 401: 8, 404: 4, 420: 8, 422: 8, 426: 8, 432: 7, 464: 8, 474: 5, 476: 4, 487: 4, 490: 8, 493: 3, 506: 8, 507: 1, 512: 6, 513: 6, 542: 7, 545: 4, 597: 8, 660: 8, 661: 4, 773: 7, 777: 8, 780: 8, 800: 8, 804: 8, 808: 8, 829: 5, 882: 2, 884: 7, 888: 8, 891: 8, 892: 8, 923: 2, 929: 8, 983: 8, 985: 3, 1024: 5, 1027: 5, 1029: 8, 1033: 5, 1036: 8, 1039: 8, 1057: 5, 1064: 7, 1108: 8, 1125: 8, 1296: 8, 1365: 5, 1424: 5, 1600: 5, 1601: 8,
}],
- CAR.CRV_5G: [{
- 57: 3, 148: 8, 199: 4, 228: 5, 231: 5, 232: 7, 304: 8, 330: 8, 340: 8, 344: 8, 380: 8, 399: 7, 401: 8, 420: 8, 423: 2, 427: 3, 428: 8, 432: 7, 441: 5, 446: 3, 450: 8, 464: 8, 467: 2, 469: 3, 470: 2, 474: 8, 476: 7, 477: 8, 479: 8, 490: 8, 493: 5, 495: 8, 507: 1, 545: 6, 597: 8, 661: 4, 662: 4, 773: 7, 777: 8, 780: 8, 795: 8, 800: 8, 804: 8, 806: 8, 808: 8, 814: 4, 815: 8, 817: 4, 825: 4, 829: 5, 862: 8, 881: 8, 882: 4, 884: 8, 888: 8, 891: 8, 927: 8, 918: 7, 929: 8, 983: 8, 985: 3, 1024: 5, 1027: 5, 1029: 8, 1036: 8, 1039: 8, 1064: 7, 1108: 8, 1092: 1, 1115: 2, 1125: 8, 1127: 2, 1296: 8, 1302: 8, 1322: 5, 1361: 5, 1365: 5, 1424: 5, 1600: 5, 1601: 8, 1618: 5, 1633: 8, 1670: 5
+ CAR.CRV_5G: [
+ {
+ 57: 3, 148: 8, 199: 4, 228: 5, 231: 5, 232: 7, 304: 8, 330: 8, 340: 8, 344: 8, 380: 8, 399: 7, 401: 8, 420: 8, 423: 2, 427: 3, 428: 8, 432: 7, 441: 5, 446: 3, 450: 8, 464: 8, 467: 2, 469: 3, 470: 2, 474: 8, 476: 7, 477: 8, 479: 8, 490: 8, 493: 5, 495: 8, 507: 1, 545: 6, 597: 8, 661: 4, 662: 4, 773: 7, 777: 8, 780: 8, 795: 8, 800: 8, 804: 8, 806: 8, 808: 8, 814: 4, 815: 8, 817: 4, 825: 4, 829: 5, 862: 8, 881: 8, 882: 4, 884: 8, 888: 8, 891: 8, 927: 8, 918: 7, 929: 8, 983: 8, 985: 3, 1024: 5, 1027: 5, 1029: 8, 1036: 8, 1039: 8, 1040: 6, 1056: 8, 1064: 7, 1088: 3, 1108: 8, 1092: 1, 1115: 2, 1125: 8, 1127: 2, 1296: 8, 1302: 8, 1322: 5, 1361: 5, 1365: 5, 1424: 5, 1600: 5, 1601: 8, 1618: 5, 1626: 5, 1627: 5, 1633: 8, 1670: 5
+ },
+ {
+ 57: 3, 148: 8, 199: 4, 228: 5, 231: 5, 232: 7, 304: 8, 330: 8, 340: 8, 344: 8, 380: 8, 399: 7, 401: 8, 420: 8, 423: 2, 427: 3, 428: 8, 432: 7, 441: 5, 446: 3, 450: 8, 464: 8, 467: 2, 469: 3, 470: 2, 474: 8, 476: 7, 477: 8, 479: 8, 490: 8, 493: 5, 495: 8, 507: 1, 545: 6, 597: 8, 661: 4, 662: 4, 773: 7, 777: 8, 780: 8, 795: 8, 800: 8, 804: 8, 806: 8, 808: 8, 814: 4, 815: 8, 817: 4, 825: 4, 829: 5, 862: 8, 881: 8, 882: 4, 884: 8, 888: 8, 891: 8, 927: 8, 918: 7, 929: 8, 983: 8, 985: 3, 1024: 4, 1027: 5, 1029: 8, 1036: 8, 1039: 8, 1040: 6, 1056: 8, 1064: 7, 1088: 3, 1108: 8, 1092: 1, 1115: 2, 1125: 8, 1127: 2, 1296: 8, 1302: 8, 1322: 5, 1361: 5, 1365: 5, 1424: 5, 1600: 5, 1601: 8, 1618: 5, 1626: 5, 1627: 5, 1633: 8, 1670: 5
}],
# 1057: 5 1024: 5 are also on the OBD2 bus. their lengths differ from the camera's f-can bus. re-fingerprint after obd2 connection is split in panda firmware from bus 1.
CAR.CRV_EU: [{
@@ -107,6 +111,10 @@ FINGERPRINTS = {
}],
CAR.ODYSSEY_CHN: [{
57: 3, 145: 8, 316: 8, 342: 6, 344: 8, 380: 8, 398: 3, 399: 7, 401: 8, 404: 4, 411: 5, 420: 8, 422: 8, 423: 2, 426: 8, 432: 7, 450: 8, 464: 8, 490: 8, 506: 8, 507: 1, 512: 6, 513: 6, 597: 8, 610: 8, 611: 8, 612: 8, 617: 8, 660: 8, 661: 4, 773: 7, 780: 8, 804: 8, 808: 8, 829: 5, 862: 8, 884: 7, 892: 8, 923: 2, 929: 8, 1030: 5, 1137: 8, 1302: 8, 1348: 5, 1361: 5, 1365: 5, 1600: 5, 1601: 8, 1639: 8
+ },
+ # Odyssey from Shell
+ {
+ 57: 3, 145: 8, 316: 8, 342: 6, 344: 8, 380: 8, 398: 3, 399: 7, 401: 8, 408: 6, 411: 5, 415: 6, 420: 8, 422: 8, 423: 2, 426: 8, 432: 7, 450: 8, 464: 8, 490: 8, 507: 1, 597: 8, 610: 8, 611: 8, 612: 8, 617: 8, 660: 8, 661: 4, 773: 7, 804: 8, 808: 8, 884: 7, 892: 8, 923: 2, 929: 8, 1030: 5, 1137: 8, 1302: 8, 1348: 5, 1361: 5, 1365: 5, 1639: 8
}],
# 2017 Pilot Touring AND 2016 Pilot EX-L w/ Added Comma Pedal Support (512L & 513L)
CAR.PILOT: [{
@@ -377,6 +385,7 @@ FW_VERSIONS = {
b'37805-5AW-G720\x00\x00',
b'37805-5AZ-E850\x00\x00',
b'37805-5BB-L640\x00\x00',
+ b'37805-5AN-E410\x00\x00', # AlexNoop's Manual CIVIC_BOSCH
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28101-5CG-A920\x00\x00',
@@ -396,6 +405,7 @@ FW_VERSIONS = {
b'57114-TGG-A340\x00\x00',
b'57114-TGL-G330\x00\x00',
b'57114-TGG-C320\x00\x00',
+ b'57114-TGL-G130\x00\x00', # AlexNoop's Manual CIVIC_BOSCH
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TBA-C020\x00\x00',
@@ -405,12 +415,14 @@ FW_VERSIONS = {
b'39990-TGG-A120\x00\x00',
b'39990-TGL-E130\x00\x00',
b'39990-TGG-A020\x00\x00',
+ b'39990-TGN-E120\x00\x00', # AlexNoop's Manual CIVIC_BOSCH
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-TBA-A060\x00\x00',
b'77959-TEA-G020\x00\x00',
b'77959-TGG-A020\x00\x00',
b'77959-TGG-G010\x00\x00',
+ b'77959-TGG-A020\x00\x00',
],
(Ecu.combinationMeter, 0x18da60f1, None): [
b'78109-TBA-A910\x00\x00',
@@ -423,6 +435,7 @@ FW_VERSIONS = {
b'78109-TGG-A810\x00\x00',
b'78109-TGG-A820\x00\x00',
b'78109-TGL-G120\x00\x00',
+ b'78109-TGG-BA10\x00\x00', # AlexNoop's Manual CIVIC_BOSCH
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36802-TBA-A150\x00\x00',
@@ -430,6 +443,7 @@ FW_VERSIONS = {
b'36802-TGG-A050\x00\x00',
b'36802-TGL-G040\x00\x00',
b'36802-TGG-A060\x00\x00',
+ b'36802-TGG-G040\x00\x00', # AlexNoop's Manual CIVIC_BOSCH
],
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'36161-TBA-A130\x00\x00',
@@ -437,10 +451,12 @@ FW_VERSIONS = {
b'36161-TGG-A060\x00\x00',
b'36161-TGL-G050\x00\x00',
b'36161-TGG-A080\x00\x00',
+ b'36161-TGG-G070\x00\x00', # AlexNoop's Manual CIVIC_BOSCH
],
(Ecu.unknown, 0x18daeff1, None): [
b'38897-TBA-A110\x00\x00',
b'38897-TBA-A020\x00\x00',
+ b'38897-TBA-A020\x00\x00',
],
(Ecu.gateway, 0x18daeff1, None): [
b'38897-TBA-A110\x00\x00',
@@ -572,6 +588,7 @@ FW_VERSIONS = {
(Ecu.gateway, 0x18daeff1, None): [
b'38897-THR-A010\x00\x00',
b'38897-THR-A020\x00\x00',
+ b'38897-TKN-H030\x00\x00',
],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5MR-A250\x00\x00',
@@ -583,10 +600,12 @@ FW_VERSIONS = {
(Ecu.eps, 0x18da30f1, None): [
b'39990-THR-A020\x00\x00',
b'39990-THR-A030\x00\x00',
+ b'39990-T6D-H220\x00\x00'
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-THR-A010\x00\x00',
b'77959-THR-A110\x00\x00',
+ b'77959-T6A-H140\x00\x00',
],
(Ecu.fwdCamera, 0x18dab0f1, None): [
b'36161-THR-A030\x00\x00',
@@ -622,6 +641,7 @@ FW_VERSIONS = {
b'78109-THR-AL10\x00\x00',
b'78109-THR-C330\x00\x00',
b'78109-THR-CE20\x00\x00',
+ b'78109-TKN-H110\x00\x00'
],
(Ecu.shiftByWire, 0x18da0bf1, None): [
b'54008-THR-A020\x00\x00',
diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py
index 59fef40d2..ee90d4bf7 100644
--- a/selfdrive/car/hyundai/carcontroller.py
+++ b/selfdrive/car/hyundai/carcontroller.py
@@ -3,6 +3,10 @@ from selfdrive.car import apply_std_steer_torque_limits
from selfdrive.car.hyundai.hyundaican import create_lkas11, create_clu11, create_lfa_mfa
from selfdrive.car.hyundai.values import Buttons, SteerLimitParams, CAR
from opendbc.can.packer import CANPacker
+from common.params import Params
+params = Params()
+from common.dp import get_last_modified
+from common.dp import common_controller_update, common_controller_ctrl
VisualAlert = car.CarControl.HUDControl.VisualAlert
@@ -44,8 +48,24 @@ class CarController():
self.last_resume_frame = 0
self.last_lead_distance = 0
+ # dp
+ self.dragon_enable_steering_on_signal = False
+ self.dragon_lat_ctrl = True
+ self.dp_last_modified = None
+ self.lane_change_enabled = True
+
def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert,
left_lane, right_lane, left_lane_depart, right_lane_depart):
+
+ # dp
+ if frame % 500 == 0:
+ modified = get_last_modified()
+ if self.dp_last_modified != modified:
+ self.dragon_lat_ctrl, \
+ self.lane_change_enabled, \
+ self.dragon_enable_steering_on_signal = common_controller_update(self.lane_change_enabled)
+ self.dp_last_modified = modified
+
# Steering Torque
new_steer = actuators.steer * SteerLimitParams.STEER_MAX
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, SteerLimitParams)
@@ -63,6 +83,14 @@ class CarController():
self.apply_steer_last = apply_steer
+ # dp
+ lkas_active = common_controller_ctrl(enabled,
+ self.dragon_lat_ctrl,
+ self.dragon_enable_steering_on_signal,
+ CS.out.leftBlinker,
+ CS.out.rightBlinker,
+ lkas_active)
+
sys_warning, sys_state, left_lane_warning, right_lane_warning =\
process_hud_alert(enabled, self.car_fingerprint, visual_alert,
left_lane, right_lane, left_lane_depart, right_lane_depart)
diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py
index 649d181c5..df8c00309 100644
--- a/selfdrive/car/hyundai/interface.py
+++ b/selfdrive/car/hyundai/interface.py
@@ -155,6 +155,7 @@ class CarInterface(CarInterfaceBase):
return ret
def update(self, c, can_strings):
+ self.dp_load_params('hyundai')
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py
index 41a8c5eea..46074d789 100644
--- a/selfdrive/car/interfaces.py
+++ b/selfdrive/car/interfaces.py
@@ -7,6 +7,12 @@ from selfdrive.car import gen_empty_fingerprint
from selfdrive.controls.lib.drive_helpers import EventTypes as ET, create_event
from selfdrive.controls.lib.vehicle_model import VehicleModel
+# dp
+from common.realtime import sec_since_boot
+from common.params import Params, put_nonblocking
+params = Params()
+from common.dp import get_last_modified
+
GearShifter = car.CarState.GearShifter
# generic car and radar interfaces
@@ -27,6 +33,15 @@ class CarInterfaceBase():
if CarController is not None:
self.CC = CarController(self.cp.dbc_name, CP, self.VM)
+ # dp
+ self.dragon_toyota_stock_dsu = False
+ self.dragon_enable_steering_on_signal = False
+ self.dragon_allow_gas = False
+ self.ts_last_check = 0.
+ self.dragon_lat_ctrl = True
+ self.dp_last_modified = None
+ self.dp_gear_check = True
+
@staticmethod
def calc_accel_override(a_ego, a_target, v_ego, v_target):
return 1.
@@ -79,6 +94,27 @@ class CarInterfaceBase():
def apply(self, c):
raise NotImplementedError
+ def dp_load_params(self, car_name):
+ # dp
+ ts = sec_since_boot()
+ if ts - self.ts_last_check >= 5.:
+ modified = get_last_modified()
+ if self.dp_last_modified != modified:
+ self.dragon_lat_ctrl = False if params.get("DragonLatCtrl", encoding='utf8') == "0" else True
+ if self.dragon_lat_ctrl:
+ self.dragon_enable_steering_on_signal = True if params.get("DragonEnableSteeringOnSignal", encoding='utf8') == "1" else False
+ else:
+ self.dragon_enable_steering_on_signal = True
+ if car_name == 'toyota':
+ self.dragon_toyota_stock_dsu = True if params.get("DragonToyotaStockDSU", encoding='utf8') == "1" else False
+ else:
+ self.dragon_toyota_stock_dsu = False
+ if not self.dragon_toyota_stock_dsu:
+ self.dragon_allow_gas = True if params.get("DragonAllowGas", encoding='utf8') == "1" else False
+ self.dp_gear_check = False if params.get("DragonEnableGearCheck", encoding='utf8') == "0" else True
+ self.dp_last_modified = modified
+ self.ts_last_check = ts
+
def create_common_events(self, cs_out, extra_gears=[], gas_resume_speed=-1, pcm_enable=True):
events = []
@@ -86,18 +122,23 @@ class CarInterfaceBase():
events.append(create_event('doorOpen', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
if cs_out.seatbeltUnlatched:
events.append(create_event('seatbeltNotLatched', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
- if cs_out.gearShifter != GearShifter.drive and cs_out.gearShifter not in extra_gears:
- events.append(create_event('wrongGear', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
- if cs_out.gearShifter == GearShifter.reverse:
- events.append(create_event('reverseGear', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))
+ if not self.dragon_toyota_stock_dsu:
+ if cs_out.gearShifter != GearShifter.drive and cs_out.gearShifter not in extra_gears:
+ events.append(create_event('wrongGear', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
+ if cs_out.gearShifter == GearShifter.reverse:
+ events.append(create_event('reverseGear', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))
if not cs_out.cruiseState.available:
events.append(create_event('wrongCarMode', [ET.NO_ENTRY, ET.USER_DISABLE]))
if cs_out.espDisabled:
events.append(create_event('espDisabled', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
- if cs_out.gasPressed:
+ if cs_out.gasPressed and not self.dragon_allow_gas and not self.dragon_toyota_stock_dsu:
events.append(create_event('pedalPressed', [ET.PRE_ENABLE]))
- if cs_out.steerError:
+ if not self.dragon_lat_ctrl:
+ events.append(create_event('manualSteeringRequired', [ET.WARNING]))
+ elif self.dragon_enable_steering_on_signal and (cs_out.leftBlinker or cs_out.rightBlinker):
+ events.append(create_event('manualSteeringRequiredBlinkersOn', [ET.WARNING]))
+ elif cs_out.steerError:
events.append(create_event('steerUnavailable', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE, ET.PERMANENT]))
elif cs_out.steerWarning:
events.append(create_event('steerTempUnavailable', [ET.NO_ENTRY, ET.WARNING]))
@@ -105,9 +146,14 @@ class CarInterfaceBase():
# Disable on rising edge of gas or brake. Also disable on brake when speed > 0.
# Optionally allow to press gas at zero speed to resume.
# e.g. Chrysler does not spam the resume button yet, so resuming with gas is handy. FIXME!
- if (cs_out.gasPressed and (not self.CS.out.gasPressed) and cs_out.vEgo > gas_resume_speed) or \
- (cs_out.brakePressed and (not self.CS.out.brakePressed or not cs_out.standstill)):
- events.append(create_event('pedalPressed', [ET.NO_ENTRY, ET.USER_DISABLE]))
+ if not self.dragon_toyota_stock_dsu:
+ if not self.dragon_allow_gas:
+ if (cs_out.gasPressed and (not self.CS.out.gasPressed) and cs_out.vEgo > gas_resume_speed) or \
+ (cs_out.brakePressed and (not self.CS.out.brakePressed or not cs_out.standstill)):
+ events.append(create_event('pedalPressed', [ET.NO_ENTRY, ET.USER_DISABLE]))
+ else:
+ if cs_out.brakePressed and (not self.CS.out.gasPressed or not cs_out.standstill):
+ events.append(create_event('pedalPressed', [ET.NO_ENTRY, ET.USER_DISABLE]))
# we engage when pcm is active (rising edge)
if pcm_enable:
diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py
index 3c97fb30f..7b6592cc4 100755
--- a/selfdrive/car/mock/interface.py
+++ b/selfdrive/car/mock/interface.py
@@ -29,6 +29,16 @@ class CarInterface(CarInterfaceBase):
self.yaw_rate = 0.
self.yaw_rate_meas = 0.
+ # dp
+ # mock override constructor so we need to define here as well.
+ self.dragon_toyota_stock_dsu = False
+ self.dragon_enable_steering_on_signal = False
+ self.dragon_allow_gas = False
+ self.ts_last_check = 0.
+ self.dragon_lat_ctrl = True
+ self.dp_last_modified = None
+ self.dp_gear_check = True
+
@staticmethod
def compute_gb(accel, speed):
return accel
@@ -50,6 +60,7 @@ class CarInterface(CarInterfaceBase):
# returns a car.CarState
def update(self, c, can_strings):
+ self.dp_load_params('mock')
# get basic data from phone and gps since CAN isn't connected
sensors = messaging.recv_sock(self.sensor)
if sensors is not None:
diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py
index 7f3fc3d84..60361641d 100644
--- a/selfdrive/car/subaru/carcontroller.py
+++ b/selfdrive/car/subaru/carcontroller.py
@@ -3,6 +3,10 @@ from selfdrive.car import apply_std_steer_torque_limits
from selfdrive.car.subaru import subarucan
from selfdrive.car.subaru.values import DBC
from opendbc.can.packer import CANPacker
+from common.params import Params
+params = Params()
+from common.dp import get_last_modified
+from common.dp import common_controller_update, common_controller_ctrl
class CarControllerParams():
@@ -30,9 +34,24 @@ class CarController():
self.params = CarControllerParams()
self.packer = CANPacker(DBC[CP.carFingerprint]['pt'])
+ # dp
+ self.dragon_enable_steering_on_signal = False
+ self.dragon_lat_ctrl = True
+ self.dp_last_modified = None
+ self.lane_change_enabled = True
+
def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, left_line, right_line):
""" Controls thread """
+ # dp
+ if frame % 500 == 0:
+ modified = get_last_modified()
+ if self.dp_last_modified != modified:
+ self.dragon_lat_ctrl, \
+ self.lane_change_enabled, \
+ self.dragon_enable_steering_on_signal = common_controller_update(self.lane_change_enabled)
+ self.dp_last_modified = modified
+
P = self.params
# Send CAN commands.
@@ -56,6 +75,14 @@ class CarController():
if not lkas_enabled:
apply_steer = 0
+ # dp
+ apply_steer = common_controller_ctrl(enabled,
+ self.dragon_lat_ctrl,
+ self.dragon_enable_steering_on_signal,
+ CS.out.leftBlinker,
+ CS.out.rightBlinker,
+ apply_steer)
+
can_sends.append(subarucan.create_steering_control(self.packer, apply_steer, frame, P.STEER_STEP))
self.apply_steer_last = apply_steer
diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py
index e205c7cc4..c4262f692 100644
--- a/selfdrive/car/subaru/interface.py
+++ b/selfdrive/car/subaru/interface.py
@@ -50,6 +50,7 @@ class CarInterface(CarInterfaceBase):
# returns a car.CarState
def update(self, c, can_strings):
+ self.dp_load_params('subaru')
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py
index 58a970f78..e4b554720 100644
--- a/selfdrive/car/toyota/carcontroller.py
+++ b/selfdrive/car/toyota/carcontroller.py
@@ -5,13 +5,17 @@ from selfdrive.car.toyota.toyotacan import create_steer_command, create_ui_comma
create_accel_command, create_acc_cancel_command, create_fcw_command
from selfdrive.car.toyota.values import Ecu, CAR, STATIC_MSGS, SteerLimitParams
from opendbc.can.packer import CANPacker
+from common.params import Params
+params = Params()
+from common.dp import get_last_modified
+from common.dp import common_controller_update, common_controller_ctrl
VisualAlert = car.CarControl.HUDControl.VisualAlert
# Accel limits
ACCEL_HYST_GAP = 0.02 # don't change accel command for small oscilalitons within this value
-ACCEL_MAX = 1.5 # 1.5 m/s2
-ACCEL_MIN = -3.0 # 3 m/s2
+ACCEL_MAX = 2.0 # 2.0 m/s2
+ACCEL_MIN = -3.5 # 3.5 m/s2
ACCEL_SCALE = max(ACCEL_MAX, -ACCEL_MIN)
def accel_hysteresis(accel, accel_steady, enabled):
@@ -46,9 +50,30 @@ class CarController():
self.packer = CANPacker(dbc_name)
+ # dp
+ self.dragon_enable_steering_on_signal = False
+ self.dragon_lat_ctrl = True
+ self.dragon_lane_departure_warning = True
+ self.dragon_toyota_sng_mod = False
+ self.dp_last_modified = None
+ self.lane_change_enabled = True
+
def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, hud_alert,
left_line, right_line, lead, left_lane_depart, right_lane_depart):
+ # dp
+ if frame % 500 == 0:
+ modified = get_last_modified()
+ if self.dp_last_modified != modified:
+ self.dragon_lane_departure_warning = False if params.get("DragonToyotaLaneDepartureWarning", encoding='utf8') == "0" else True
+ self.dragon_toyota_sng_mod = True if params.get("DragonToyotaSnGMod", encoding='utf8') == "1" else False
+
+ self.dragon_lat_ctrl, \
+ self.lane_change_enabled, \
+ self.dragon_enable_steering_on_signal = common_controller_update(self.lane_change_enabled)
+
+ self.dp_last_modified = modified
+
# *** compute control surfaces ***
# gas and brake
@@ -74,8 +99,8 @@ class CarController():
if CS.steer_state in [9, 25]:
self.last_fault_frame = frame
- # Cut steering for 2s after fault
- if not enabled or (frame - self.last_fault_frame < 200):
+ # # Cut steering for 2s after fault
+ if not enabled: # or (frame - self.last_fault_frame < 200):
apply_steer = 0
apply_steer_req = 0
else:
@@ -86,7 +111,7 @@ class CarController():
pcm_cancel_cmd = 1
# on entering standstill, send standstill request
- if CS.out.standstill and not self.last_standstill:
+ if not self.dragon_toyota_sng_mod and CS.out.standstill and not self.last_standstill:
self.standstill_req = True
if CS.pcm_acc_status != 8:
# pcm entered standstill or it's disabled
@@ -96,6 +121,14 @@ class CarController():
self.last_accel = apply_accel
self.last_standstill = CS.out.standstill
+ # dp
+ apply_steer_req = common_controller_ctrl(enabled,
+ self.dragon_lat_ctrl,
+ self.dragon_enable_steering_on_signal,
+ CS.out.leftBlinker,
+ CS.out.rightBlinker,
+ apply_steer_req)
+
can_sends = []
#*** control msgs ***
@@ -112,7 +145,7 @@ class CarController():
lead = lead or CS.out.vEgo < 12. # at low speed we always assume the lead is present do ACC can be engaged
# Lexus IS uses a different cancellation message
- if pcm_cancel_cmd and CS.CP.carFingerprint == CAR.LEXUS_IS:
+ if pcm_cancel_cmd and CS.CP.carFingerprint in [CAR.LEXUS_IS, CAR.LEXUS_ISH, CAR.LEXUS_GSH]:
can_sends.append(create_acc_cancel_command(self.packer))
elif CS.CP.openpilotLongitudinalControl:
can_sends.append(create_accel_command(self.packer, apply_accel, pcm_cancel_cmd, self.standstill_req, lead))
@@ -139,8 +172,16 @@ class CarController():
# forcing the pcm to disengage causes a bad fault sound so play a good sound instead
send_ui = True
+ # dp
+ if self.dragon_lane_departure_warning:
+ dragon_left_lane_depart = left_lane_depart
+ dragon_right_lane_depart = right_lane_depart
+ else:
+ dragon_left_lane_depart = False
+ dragon_right_lane_depart = False
+
if (frame % 100 == 0 or send_ui) and Ecu.fwdCamera in self.fake_ecus:
- can_sends.append(create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, left_line, right_line, left_lane_depart, right_lane_depart))
+ can_sends.append(create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, left_line, right_line, dragon_left_lane_depart, dragon_right_lane_depart))
if frame % 100 == 0 and Ecu.dsu in self.fake_ecus:
can_sends.append(create_fcw_command(self.packer, fcw_alert))
diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py
index c9970bead..f3935d02f 100644
--- a/selfdrive/car/toyota/carstate.py
+++ b/selfdrive/car/toyota/carstate.py
@@ -5,7 +5,10 @@ from selfdrive.car.interfaces import CarStateBase
from opendbc.can.parser import CANParser
from selfdrive.config import Conversions as CV
from selfdrive.car.toyota.values import CAR, DBC, STEER_THRESHOLD, TSS2_CAR, NO_STOP_TIMER_CAR
-
+from common.realtime import sec_since_boot
+from common.params import Params
+from common.dp import get_last_modified
+params = Params()
class CarState(CarStateBase):
def __init__(self, CP):
@@ -14,15 +17,29 @@ class CarState(CarStateBase):
self.shifter_values = can_define.dv["GEAR_PACKET"]['GEAR']
# All TSS2 car have the accurate sensor
- self.accurate_steer_angle_seen = CP.carFingerprint in TSS2_CAR
+ self.accurate_steer_angle_seen = CP.carFingerprint in TSS2_CAR or CP.carFingerprint in [CAR.LEXUS_ISH]
# On NO_DSU cars but not TSS2 cars the cp.vl["STEER_TORQUE_SENSOR"]['STEER_ANGLE']
# is zeroed to where the steering angle is at start.
# Need to apply an offset as soon as the steering angle measurements are both received
- self.needs_angle_offset = CP.carFingerprint not in TSS2_CAR
+ self.needs_angle_offset = CP.carFingerprint not in TSS2_CAR or CP.carFingerprint in [CAR.LEXUS_ISH]
self.angle_offset = 0.
+ # dp
+ self.dragon_toyota_stock_dsu = False
+ self.ts_last_check = 0.
+ self.last_modifed = None
+
def update(self, cp, cp_cam):
+ # dp
+ ts = sec_since_boot()
+ if ts - self.ts_last_check >= 5.:
+ modified = get_last_modified()
+ if self.last_modifed != modified:
+ self.dragon_toyota_stock_dsu = True if params.get("DragonToyotaStockDSU", encoding='utf8') == "1" else False
+ self.last_modifed = modified
+ self.ts_last_check = ts
+
ret = car.CarState.new_message()
ret.doorOpen = any([cp.vl["SEATS_DOORS"]['DOOR_OPEN_FL'], cp.vl["SEATS_DOORS"]['DOOR_OPEN_FR'],
@@ -34,6 +51,9 @@ class CarState(CarStateBase):
if self.CP.enableGasInterceptor:
ret.gas = (cp.vl["GAS_SENSOR"]['INTERCEPTOR_GAS'] + cp.vl["GAS_SENSOR"]['INTERCEPTOR_GAS2']) / 2.
ret.gasPressed = ret.gas > 15
+ elif self.CP.carFingerprint in [CAR.LEXUS_ISH, CAR.LEXUS_GSH]:
+ ret.gas = cp.vl["GAS_PEDAL_ALT"]['GAS_PEDAL']
+ ret.gasPressed = ret.gas > 1e-5
else:
ret.gas = cp.vl["GAS_PEDAL"]['GAS_PEDAL']
ret.gasPressed = cp.vl["PCM_CRUISE"]['GAS_RELEASED'] == 0
@@ -74,15 +94,23 @@ class CarState(CarStateBase):
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD
ret.steerWarning = cp.vl["EPS_STATUS"]['LKA_STATE'] not in [1, 5]
- if self.CP.carFingerprint == CAR.LEXUS_IS:
+ if self.CP.carFingerprint in [CAR.LEXUS_IS, CAR.LEXUS_NXT]:
ret.cruiseState.available = cp.vl["DSU_CRUISE"]['MAIN_ON'] != 0
ret.cruiseState.speed = cp.vl["DSU_CRUISE"]['SET_SPEED'] * CV.KPH_TO_MS
self.low_speed_lockout = False
+ elif self.CP.carFingerprint in [CAR.LEXUS_ISH, CAR.LEXUS_GSH]:
+ ret.cruiseState.available = cp.vl["PCM_CRUISE_ALT"]['MAIN_ON'] != 0
+ ret.cruiseState.speed = cp.vl["PCM_CRUISE_ALT"]['SET_SPEED'] * CV.KPH_TO_MS
+ self.low_speed_lockout = False
else:
ret.cruiseState.available = cp.vl["PCM_CRUISE_2"]['MAIN_ON'] != 0
ret.cruiseState.speed = cp.vl["PCM_CRUISE_2"]['SET_SPEED'] * CV.KPH_TO_MS
self.low_speed_lockout = cp.vl["PCM_CRUISE_2"]['LOW_SPEED_LOCKOUT'] == 2
- self.pcm_acc_status = cp.vl["PCM_CRUISE"]['CRUISE_STATE']
+ if self.CP.carFingerprint in [CAR.LEXUS_ISH, CAR.LEXUS_GSH]:
+ # Lexus ISH does not have CRUISE_STATUS value (always 0), so we use CRUISE_ACTIVE value instead
+ self.pcm_acc_status = cp.vl["PCM_CRUISE"]['CRUISE_ACTIVE']
+ else:
+ self.pcm_acc_status = cp.vl["PCM_CRUISE"]['CRUISE_STATE']
if self.CP.carFingerprint in NO_STOP_TIMER_CAR or self.CP.enableGasInterceptor:
# ignore standstill in hybrid vehicles, since pcm allows to restart without
# receiving any special command. Also if interceptor is detected
@@ -93,6 +121,8 @@ class CarState(CarStateBase):
if self.CP.carFingerprint == CAR.PRIUS:
ret.genericToggle = cp.vl["AUTOPARK_STATUS"]['STATE'] != 0
+ elif self.CP.carFingerprint in [CAR.LEXUS_ISH, CAR.LEXUS_GSH]:
+ ret.genericToggle = bool(cp.vl["LIGHT_STALK_ISH"]['AUTO_HIGH_BEAM'])
else:
ret.genericToggle = bool(cp.vl["LIGHT_STALK"]['AUTO_HIGH_BEAM'])
ret.stockAeb = bool(cp_cam.vl["PRE_COLLISION"]["PRECOLLISION_ACTIVE"] and cp_cam.vl["PRE_COLLISION"]["FORCE"] < -1e-5)
@@ -105,6 +135,15 @@ class CarState(CarStateBase):
ret.leftBlindspot = cp.vl["BSM"]['L_ADJACENT'] == 1
ret.rightBlindspot = cp.vl["BSM"]['R_ADJACENT'] == 1
+ # dp
+ if self.dragon_toyota_stock_dsu and ret.cruiseState.available:
+ enable_acc = True
+ if ret.gearShifter in [car.CarState.GearShifter.reverse, car.CarState.GearShifter.park]:
+ enable_acc = False
+ if ret.seatbeltUnlatched or ret.doorOpen:
+ enable_acc = False
+ ret.cruiseState.enabled = enable_acc
+
return ret
@staticmethod
@@ -141,8 +180,8 @@ class CarState(CarStateBase):
]
checks = [
- ("BRAKE_MODULE", 40),
- ("GAS_PEDAL", 33),
+ #("BRAKE_MODULE", 40),
+ #("GAS_PEDAL", 33),
("WHEEL_SPEEDS", 80),
("STEER_ANGLE_SENSOR", 80),
("PCM_CRUISE", 33),
@@ -150,7 +189,27 @@ class CarState(CarStateBase):
("EPS_STATUS", 25),
]
- if CP.carFingerprint == CAR.LEXUS_IS:
+ if CP.carFingerprint in [CAR.LEXUS_ISH, CAR.LEXUS_GSH]:
+ signals.append(("GAS_PEDAL", "GAS_PEDAL_ALT", 0))
+ signals.append(("MAIN_ON", "PCM_CRUISE_ALT", 0))
+ signals.append(("SET_SPEED", "PCM_CRUISE_ALT", 0))
+ signals.append(("AUTO_HIGH_BEAM", "LIGHT_STALK_ISH", 0))
+ checks += [
+ ("BRAKE_MODULE", 50),
+ ("GAS_PEDAL_ALT", 50),
+ ("PCM_CRUISE_ALT", 1),
+ ]
+ else:
+ signals += [
+ ("AUTO_HIGH_BEAM", "LIGHT_STALK", 0),
+ ("GAS_PEDAL", "GAS_PEDAL", 0),
+ ]
+ checks += [
+ ("BRAKE_MODULE", 40),
+ ("GAS_PEDAL", 33),
+ ]
+
+ if CP.carFingerprint in [CAR.LEXUS_IS, CAR.LEXUS_NXT]:
signals.append(("MAIN_ON", "DSU_CRUISE", 0))
signals.append(("SET_SPEED", "DSU_CRUISE", 0))
checks.append(("DSU_CRUISE", 5))
@@ -174,6 +233,8 @@ class CarState(CarStateBase):
signals += [("L_ADJACENT", "BSM", 0)]
signals += [("R_ADJACENT", "BSM", 0)]
+ checks = []
+
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0)
@staticmethod
diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py
index e24c38f63..627c73c25 100755
--- a/selfdrive/car/toyota/interface.py
+++ b/selfdrive/car/toyota/interface.py
@@ -6,9 +6,11 @@ from selfdrive.car.toyota.values import Ecu, ECU_FINGERPRINT, CAR, TSS2_CAR, FIN
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
from selfdrive.swaglog import cloudlog
from selfdrive.car.interfaces import CarInterfaceBase
-
+from common.params import Params
+params = Params()
class CarInterface(CarInterfaceBase):
+
@staticmethod
def compute_gb(accel, speed):
return float(accel) / 3.0
@@ -231,6 +233,36 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.1]]
ret.lateralTuning.pid.kf = 0.00006
+ elif candidate == CAR.LEXUS_ISH:
+ stop_and_go = True # set to true because it's a hybrid
+ ret.safetyParam = 130
+ ret.wheelbase = 2.79908
+ ret.steerRatio = 13.3
+ tire_stiffness_factor = 0.444
+ ret.mass = 3736.8 * CV.LB_TO_KG + STD_CARGO_KG
+ ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.05]]
+ ret.lateralTuning.pid.kf = 0.00006
+
+ elif candidate == CAR.LEXUS_GSH:
+ stop_and_go = True # set to true because it's a hybrid
+ ret.safetyParam = 77
+ ret.wheelbase = 2.84988
+ ret.steerRatio = 13.3
+ tire_stiffness_factor = 0.444
+ ret.mass = 4112 * CV.LB_TO_KG + STD_CARGO_KG
+ ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.05]]
+ ret.lateralTuning.pid.kf = 0.00006
+
+ elif candidate == CAR.LEXUS_NXT:
+ stop_and_go = True
+ ret.safetyParam = 100
+ ret.wheelbase = 2.66
+ ret.steerRatio = 14.7
+ tire_stiffness_factor = 0.444 # not optimized yet
+ ret.mass = 4070 * CV.LB_TO_KG + STD_CARGO_KG
+ ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.05]]
+ ret.lateralTuning.pid.kf = 0.00006
+
ret.steerRateCost = 1.
ret.centerToFront = ret.wheelbase * 0.44
@@ -274,7 +306,11 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalTuning.kpV = [1.2, 0.8, 0.5]
ret.longitudinalTuning.kiV = [0.18, 0.12]
else:
- ret.gasMaxBP = [0.]
+ try:
+ max_bp = max(0., float(params.get("DragonToyotaSngResponse", encoding='utf8')))
+ except (TypeError, ValueError):
+ max_bp = 0.
+ ret.gasMaxBP = [max_bp]
ret.gasMaxV = [0.5]
ret.longitudinalTuning.kpV = [3.6, 2.4, 1.5]
ret.longitudinalTuning.kiV = [0.54, 0.36]
@@ -283,6 +319,7 @@ class CarInterface(CarInterfaceBase):
# returns a car.CarState
def update(self, c, can_strings):
+ self.dp_load_params('toyota')
# ******************* do can recv *******************
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py
index ff530ad5d..14a151dd3 100644
--- a/selfdrive/car/toyota/values.py
+++ b/selfdrive/car/toyota/values.py
@@ -36,6 +36,9 @@ class CAR:
LEXUS_CTH = "LEXUS CT 200H 2018"
RAV4H_TSS2 = "TOYOTA RAV4 HYBRID 2019"
LEXUS_NXH = "LEXUS NX300H 2018"
+ LEXUS_ISH = "LEXUS IS300h 2017"
+ LEXUS_GSH = "LEXUS GS450h 2017"
+ LEXUS_NXT = "LEXUS NX200T 2015"
# addr: (ecu, cars, bus, 1/freq*100, vl)
@@ -80,6 +83,10 @@ FINGERPRINTS = {
CAR.PRIUS: [{
36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 512: 6, 513: 6, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 814: 8, 824: 2, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2,898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1175: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
},
+ # Taiwan Prius 4.5
+ {
+ 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 512: 6, 513: 6, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 800: 8, 810: 2, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
+ },
#2019 LE
{
36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 814: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1175: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
@@ -108,6 +115,10 @@ FINGERPRINTS = {
# 2016 Lexus RX 350
36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 812: 3, 818: 8, 819: 8, 820: 8, 821: 8, 822: 8, 830: 7, 835: 8, 836: 8, 845: 5, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1349: 8, 1350: 8, 1351: 8, 1413: 8, 1414: 8, 1415: 8, 1416: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8
},
+ {
+ # RX300 China
+ 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 742: 8, 743: 8, 744: 8, 800: 8, 810: 2, 812: 3, 830: 7, 835: 8, 836: 8, 845: 5, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
+ },
# 2017 Lexus RX 350
{
36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 658: 8, 705: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 812: 3, 814: 8, 818: 8, 819: 8, 820: 8, 821: 8, 822: 8, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1349: 8, 1350: 8, 1351: 8, 1413: 8, 1414: 8, 1415: 8, 1416: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
@@ -149,6 +160,10 @@ FINGERPRINTS = {
{
36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 888: 8, 889: 8, 891: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 983: 8, 984: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1412: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1816: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
},
+ # China 2018 Camry 2.5 from superdongle
+ {
+ 36: 8, 37: 8, 119: 6, 170: 8, 180: 8, 186: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 800: 8, 810: 2, 812: 8, 818: 8, 824: 8, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1235: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
+ },
{
# 2019 XSE
36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 942: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 983: 8, 984: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1412: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1792: 8, 1767:4, 1808: 8, 1816: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1937: 8, 1945: 8, 1953: 8, 1961: 8, 1968: 8, 1976: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8
@@ -180,6 +195,10 @@ FINGERPRINTS = {
# 2018 Highlander Limited Platinum
{
36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1207: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1263: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1585: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1988: 8, 1990: 8, 1996: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8
+ },
+ # 2018 China Highlander from toyboxZ
+ {
+ 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 800: 8, 835: 8, 836: 8, 845: 5, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 7, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1206: 8, 1207: 8, 1212: 8, 1227: 8, 1235: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8
}],
CAR.HIGHLANDER_TSS2: [{
# 2020 highlander limited
@@ -199,6 +218,10 @@ FINGERPRINTS = {
36: 8, 37: 8, 170: 8, 180: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 547: 8, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 905: 8, 911: 1, 916: 2, 921: 8, 933: 6, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 1005: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1206: 8, 1227: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1558: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
}],
CAR.RAV4_TSS2: [
+ # China 2020 RAV4 from superdongle
+ {
+ 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 765: 8, 800: 8, 810: 2, 812: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 896: 8, 898: 8, 918: 7, 921: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1063: 8, 1071: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1112: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1172: 8, 1235: 8, 1263: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8
+ },
# LE
{
36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 355: 5, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 565: 8, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1076: 8, 1077: 8,1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1235: 8, 1279: 8, 1541: 8, 1552: 8, 1553:8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
@@ -208,11 +231,27 @@ FINGERPRINTS = {
36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 565: 8, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8
}],
CAR.COROLLA_TSS2: [
+ #2020 AURIS with LTA, number of messages:
+ {
+ 36: 8, 37: 8, 114: 5, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 765: 8, 800: 8, 810: 2, 812: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 896: 8, 898: 8, 921: 8, 942: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1172: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1745: 8, 1775: 8, 1779: 8
+ },
+ {
+ # 2019 Taiwan Altis
+ 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 765: 8, 800: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 885: 8, 896: 8, 898: 8, 918: 7, 921: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1082: 8, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1172: 8, 1235: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1745: 8, 1775: 8, 1779: 8
+ },
+ {
+ # 2019 Chinese Levin (Petrol) from Shell
+ 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 355: 5, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 765: 8, 800: 8, 810: 2, 812: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 885: 8, 896: 8, 898: 8, 921: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1172: 8, 1235: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1600: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8, 1808: 8, 1816: 8, 1904: 8, 1912: 8, 1984: 8, 1992: 8, 2002: 8
+ },
# hatch 2019+ and sedan 2020+
{
36: 8, 37: 8, 114: 5, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1809: 8, 1816: 8, 1817: 8, 1840: 8, 1848: 8, 1904: 8, 1912: 8, 1940: 8, 1941: 8, 1948: 8, 1949: 8, 1952: 8, 1960: 8, 1981: 8, 1986: 8, 1990: 8, 1994: 8, 1998: 8, 2004: 8
}],
CAR.COROLLAH_TSS2: [
+ # Taiwan Altis Hybrid by Fish
+ {
+ 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 765: 8, 800: 8, 810: 2, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 885: 8, 896: 8, 898: 8, 918: 7, 921: 8, 942: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1082: 8, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1172: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1745: 8, 1775: 8, 1779: 8
+ },
# 2019 Taiwan Altis Hybrid
{
36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 765: 8, 767:4, 800: 8, 810: 2, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 885: 8, 896: 8, 898: 8, 918: 7, 921: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1082: 8, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1172: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1745: 8, 1775: 8, 1779: 8
@@ -224,6 +263,10 @@ FINGERPRINTS = {
],
CAR.LEXUS_ES_TSS2: [{
36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8,
+ },
+ # 2019 Lexus ES200 from Shell
+ {
+ 36: 8, 37: 8, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 355: 5, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 765: 8, 800: 8, 810: 2, 812: 8, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
}],
CAR.LEXUS_ESH_TSS2: [
{
@@ -238,13 +281,13 @@ FINGERPRINTS = {
36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 548: 8, 550: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 764: 8, 767:4, 800: 8, 824: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 1, 921: 8, 933: 8, 944: 6, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1008: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1160: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1656: 8, 1664: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
}],
CAR.LEXUS_IS: [
+ # IS200T 2017 TW
+ {
+ 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 355: 5, 400: 6, 426: 6, 452: 8, 464: 8, 466: 8, 467: 5, 544: 4, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 800: 8, 836: 8, 845: 5, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 7, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1008: 2, 1009: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1184: 8, 1185: 8, 1186: 8, 1187: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1207: 8, 1208: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1728: 8, 1745: 8, 1779: 8
+ },
# IS300 2018
{
36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 400: 6, 426: 6, 452: 8, 464: 8, 466: 8, 467: 5, 544: 4, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 767:4, 800: 8, 836: 8, 845: 5, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1008: 2, 1009: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1184: 8, 1185: 8, 1186: 8, 1187: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1208: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1590: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1648: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
- },
- # IS300H 2017
- {
- 36: 8, 37: 8, 170: 8, 180: 8, 295: 8, 296: 8, 400: 6, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 767:4, 800: 8, 836: 8, 845: 5, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 7, 921: 7, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1009: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1187: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1208: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
}],
CAR.RAV4H_TSS2: [
#Hybrid Limited
@@ -252,16 +295,34 @@ FINGERPRINTS = {
36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 658: 8, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913:8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1063: 8, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
},
],
- CAR.LEXUS_CTH: [{
+ CAR.LEXUS_CTH: [
+ # Taiwan CT200h FP from CloudJ
+ {
+ 36: 8, 37: 8, 170: 8, 180: 8, 288: 8, 426: 6, 452: 8, 466: 8, 467: 8, 548: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 800: 8, 810: 2, 832: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 900: 6, 902: 6, 905: 8, 911: 8, 916: 1, 918: 7, 921: 8, 933: 8, 944: 6, 945: 8, 950: 8, 951: 8, 953: 3, 955: 4, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1056: 8, 1057: 8, 1059: 1, 1076: 8, 1077: 8, 1112: 8, 1114: 8, 1116: 8, 1160: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1190: 8, 1191: 8, 1192: 8, 1227: 8, 1235: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1558: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1664: 8, 1728: 8, 1779: 8
+ },
+ {
36: 8, 37: 8, 170: 8, 180: 8, 288: 8, 426: 6, 452: 8, 466: 8, 467: 8, 548: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 800: 8, 810: 2, 832: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 1, 921: 8, 933: 8, 944: 6, 945: 8, 950: 8, 951: 8, 953: 3, 955: 4, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1056: 8, 1057: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1116: 8, 1160: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1190: 8, 1191: 8, 1192: 8, 1227: 8, 1235: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1558: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
}],
CAR.LEXUS_NXH: [{
36: 8, 37: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 800: 8, 810: 2, 812: 3, 818: 8, 822: 8, 824: 8, 835: 8, 836: 8, 845: 5, 849: 4, 869: 7, 870: 7, 871: 2, 889: 8, 891: 8, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 987: 8, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1006: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1056: 8, 1057: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1195: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1208: 8, 1212: 8, 1227: 8, 1228: 8, 1232: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
- }]
+ }],
+ CAR.LEXUS_ISH: [
+ # IS300H 2017
+ {
+ 36: 8, 37: 8, 170: 8, 180: 8, 295: 8, 296: 8, 400: 6, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 767:4, 800: 8, 836: 8, 845: 5, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 7, 921: 7, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1009: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1187: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1208: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
+ }],
+ CAR.LEXUS_GSH: [
+ # GS450H 2017
+ {
+ 36: 8, 37: 8, 38: 8, 42: 8, 44: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 548: 8, 550: 2, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 744: 8, 800: 8, 810: 2, 812: 3, 832: 8, 836: 8, 845: 5, 849: 4, 864: 1, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 2, 917: 4, 918: 7, 919: 1, 921: 7, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1009: 8, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1056: 8, 1057: 8, 1059: 1, 1112: 8, 1114: 8, 1116: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1184: 8, 1185: 8, 1186: 8, 1187: 8, 1188: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1193: 8, 1195: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1206: 8, 1208: 8, 1226: 8, 1227: 8, 1235: 8, 1237: 8, 1250: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1599: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
+ }],
+ CAR.LEXUS_NXT: [{
+ 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 426: 6, 452: 8, 464: 8, 466: 7, 544: 4, 550: 8, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 800: 8, 810: 2, 812: 3, 836: 8, 845: 5, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1009: 8, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1112: 8, 1114: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1195: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1206: 8, 1208: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1263: 8, 1552: 8, 1553: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
+ }],
}
# Don't use theses fingerprints for fingerprinting, they are still needed for ECU detection
-IGNORED_FINGERPRINTS = [CAR.RAV4H_TSS2, CAR.HIGHLANDERH_TSS2]
+IGNORED_FINGERPRINTS = [CAR.HIGHLANDERH_TSS2]
FW_VERSIONS = {
CAR.AVALON: {
@@ -321,17 +382,20 @@ FW_VERSIONS = {
b'\x028966306R5000\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00',
b'\x028966306R6000\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00',
b'\x028966306S0100\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00',
+ b'\x018966306N9000\x00\x00\x00\x00', # from a358063504 @wechat
],
(Ecu.esp, 0x7b0, None): [
b'F152633712\x00\x00\x00\x00\x00\x00',
b'F152633713\x00\x00\x00\x00\x00\x00',
b'F152633B51\x00\x00\x00\x00\x00\x00',
+ b'F152633214\x00\x00\x00\x00\x00\x00', # from a358063504 @wechat
],
(Ecu.dsu, 0x791, None): [
b'8821F0601200 ',
b'8821F0601300 ',
b'8821F0607200 ',
b'8821F0608000 ',
+ b'8821F0603600 ', # from a358063504 @wechat
],
(Ecu.eps, 0x7a1, None): [
b'8965B33540\x00\x00\x00\x00\x00\x00',
@@ -342,11 +406,13 @@ FW_VERSIONS = {
b'8821F0601300 ',
b'8821F0607200 ',
b'8821F0608000 ',
+ b'8821F0603600 ', # from a358063504 @wechat
],
(Ecu.fwdCamera, 0x750, 0x6d): [
b'8646F0601200 ',
b'8646F0601300 ',
b'8646F0605000 ',
+ b'8646F0603500 ', # from a358063504 @wechat
],
},
CAR.CHR: {
@@ -875,8 +941,11 @@ DBC = {
CAR.LEXUS_CTH: dbc_dict('lexus_ct200h_2018_pt_generated', 'toyota_adas'),
CAR.RAV4H_TSS2: dbc_dict('toyota_nodsu_hybrid_pt_generated', 'toyota_tss2_adas'),
CAR.LEXUS_NXH: dbc_dict('lexus_nx300h_2018_pt_generated', 'toyota_adas'),
+ CAR.LEXUS_ISH: dbc_dict('lexus_is_2018_pt_generated', 'toyota_adas'),
+ CAR.LEXUS_GSH: dbc_dict('lexus_is_2018_pt_generated', 'toyota_adas'),
+ CAR.LEXUS_NXT: dbc_dict('lexus_nxt_2015_pt_generated', 'toyota_adas'),
}
-NO_DSU_CAR = [CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2]
+NO_DSU_CAR = [CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.LEXUS_NXT]
TSS2_CAR = [CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2]
-NO_STOP_TIMER_CAR = [CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.SIENNA, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2] # no resume button press required
+NO_STOP_TIMER_CAR = [CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.SIENNA, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.LEXUS_NXT] # no resume button press required
diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py
index cc4e978cb..857f25f8a 100644
--- a/selfdrive/car/volkswagen/interface.py
+++ b/selfdrive/car/volkswagen/interface.py
@@ -77,6 +77,7 @@ class CarInterface(CarInterfaceBase):
# returns a car.CarState
def update(self, c, can_strings):
+ self.dp_load_params('volkswagen')
canMonoTimes = []
buttonEvents = []
diff --git a/selfdrive/common/i18n.py b/selfdrive/common/i18n.py
new file mode 100644
index 000000000..7054c0920
--- /dev/null
+++ b/selfdrive/common/i18n.py
@@ -0,0 +1,12 @@
+import gettext
+from common import android
+from common.params import put_nonblocking
+is_android = android.ANDROID
+locale_dir = '/data/openpilot/selfdrive/assets/locales'
+supported_language = ['en-US', 'zh-TW', 'zh-CN']
+locale = android.getprop("persist.sys.locale") if is_android else 'en-US'
+
+def alerts():
+ i18n = gettext.translation('alerts', localedir=locale_dir, fallback=True, languages=[locale])
+ i18n.install()
+ return i18n.gettext
\ No newline at end of file
diff --git a/selfdrive/common/spinner.c b/selfdrive/common/spinner.c
index 99e0ed422..ef8a4b33d 100644
--- a/selfdrive/common/spinner.c
+++ b/selfdrive/common/spinner.c
@@ -118,17 +118,17 @@ int spin(int argc, char** argv) {
nvgFill(vg);
// spin track
- nvgSave(vg);
- nvgTranslate(vg, spinner_img_xc, spinner_img_yc);
- nvgRotate(vg, (3.75*M_PI * cnt/120.0));
- nvgTranslate(vg, -spinner_img_xc, -spinner_img_yc);
- NVGpaint spinner_imgPaint = nvgImagePattern(vg, spinner_img_x, spinner_img_y,
- spinner_img_s, spinner_img_s, 0, spinner_img, 0.6f);
- nvgBeginPath(vg);
- nvgFillPaint(vg, spinner_imgPaint);
- nvgRect(vg, spinner_img_x, spinner_img_y, spinner_img_s, spinner_img_s);
- nvgFill(vg);
- nvgRestore(vg);
+// nvgSave(vg);
+// nvgTranslate(vg, spinner_img_xc, spinner_img_yc);
+// nvgRotate(vg, (3.75*M_PI * cnt/120.0));
+// nvgTranslate(vg, -spinner_img_xc, -spinner_img_yc);
+// NVGpaint spinner_imgPaint = nvgImagePattern(vg, spinner_img_x, spinner_img_y,
+// spinner_img_s, spinner_img_s, 0, spinner_img, 0.6f);
+// nvgBeginPath(vg);
+// nvgFillPaint(vg, spinner_imgPaint);
+// nvgRect(vg, spinner_img_x, spinner_img_y, spinner_img_s, spinner_img_s);
+// nvgFill(vg);
+// nvgRestore(vg);
// comma
NVGpaint comma_imgPaint = nvgImagePattern(vg, spinner_img_x, spinner_img_y,
diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py
index f6c2e9d14..18e1e26dc 100755
--- a/selfdrive/controls/controlsd.py
+++ b/selfdrive/controls/controlsd.py
@@ -25,6 +25,8 @@ from selfdrive.controls.lib.alertmanager import AlertManager
from selfdrive.controls.lib.vehicle_model import VehicleModel
from selfdrive.controls.lib.planner import LON_MPC_STEP
from selfdrive.locationd.calibration_helpers import Calibration, Filter
+# dp
+from common.dp import get_last_modified
LANE_DEPARTURE_THRESHOLD = 0.1
STEER_ANGLE_SATURATION_TIMEOUT = 1.0 / DT_CTRL
@@ -39,13 +41,14 @@ LaneChangeDirection = log.PathPlan.LaneChangeDirection
def add_lane_change_event(events, path_plan):
+ postfix = 'ALC' if path_plan.alcAllowed else ''
if path_plan.laneChangeState == LaneChangeState.preLaneChange:
if path_plan.laneChangeDirection == LaneChangeDirection.left:
- events.append(create_event('preLaneChangeLeft', [ET.WARNING]))
+ events.append(create_event(f"preLaneChangeLeft{postfix}", [ET.WARNING]))
else:
- events.append(create_event('preLaneChangeRight', [ET.WARNING]))
+ events.append(create_event(f"preLaneChangeRight{postfix}", [ET.WARNING]))
elif path_plan.laneChangeState in [LaneChangeState.laneChangeStarting, LaneChangeState.laneChangeFinishing]:
- events.append(create_event('laneChange', [ET.WARNING]))
+ events.append(create_event(f"laneChange{postfix}", [ET.WARNING]))
def isActive(state):
@@ -69,7 +72,7 @@ def events_to_bytes(events):
return ret
-def data_sample(CI, CC, sm, can_sock, state, mismatch_counter, can_error_counter, params):
+def data_sample(CI, CC, sm, can_sock, state, mismatch_counter, can_error_counter, params, dragon_toyota_stock_dsu):
"""Receive data from sockets and create events for battery, temperature and disk space"""
# Update carstate from CAN and create events
@@ -126,11 +129,12 @@ def data_sample(CI, CC, sm, can_sock, state, mismatch_counter, can_error_counter
if not enabled:
mismatch_counter = 0
- controls_allowed = sm['health'].controlsAllowed
- if not controls_allowed and enabled:
- mismatch_counter += 1
- if mismatch_counter >= 200:
- events.append(create_event('controlsMismatch', [ET.IMMEDIATE_DISABLE]))
+ if not dragon_toyota_stock_dsu:
+ controls_allowed = sm['health'].controlsAllowed
+ if not controls_allowed and enabled:
+ mismatch_counter += 1
+ if mismatch_counter >= 200:
+ events.append(create_event('controlsMismatch', [ET.IMMEDIATE_DISABLE]))
return CS, events, cal_perc, mismatch_counter, can_error_counter
@@ -223,7 +227,7 @@ def state_transition(frame, CS, CP, state, events, soft_disable_timer, v_cruise_
def state_control(frame, rcv_frame, plan, path_plan, CS, CP, state, events, v_cruise_kph, v_cruise_kph_last,
- AM, rk, LaC, LoC, read_only, is_metric, cal_perc, last_blinker_frame, saturated_count):
+ AM, rk, LaC, LoC, read_only, is_metric, cal_perc, last_blinker_frame, saturated_count, dragon_lat_control, dragon_display_steering_limit_alert, dragon_lead_car_moving_alert):
"""Given the state, this function returns an actuators packet"""
actuators = car.CarControl.Actuators.new_message()
@@ -245,6 +249,11 @@ def state_control(frame, rcv_frame, plan, path_plan, CS, CP, state, events, v_cr
# State specific actions
if state in [State.preEnabled, State.disabled]:
+ if dragon_lead_car_moving_alert:
+ for e in get_events(events, [ET.WARNING]):
+ extra_text = ""
+ if e in ["leadCarDetected", "leadCarMoving"]:
+ AM.add(frame, e, enabled, extra_text_2=extra_text)
LaC.reset()
LoC.reset(v_pid=CS.vEgo)
@@ -266,7 +275,7 @@ def state_control(frame, rcv_frame, plan, path_plan, CS, CP, state, events, v_cr
v_acc_sol = plan.vStart + dt * (a_acc_sol + plan.aStart) / 2.0
# Gas/Brake PID loop
- actuators.gas, actuators.brake = LoC.update(active, CS.vEgo, CS.brakePressed, CS.standstill, CS.cruiseState.standstill,
+ actuators.gas, actuators.brake = LoC.update(active, CS.vEgo, CS.gasPressed, CS.brakePressed, CS.standstill, CS.cruiseState.standstill,
v_cruise_kph, v_acc_sol, plan.vTargetFuture, a_acc_sol, CP)
# Steering PID loop and lateral MPC
actuators.steer, actuators.steerAngle, lac_log = LaC.update(active, CS.vEgo, CS.steeringAngle, CS.steeringRate, CS.steeringTorqueEps, CS.steeringPressed, CS.steeringRateLimited, CP, path_plan)
@@ -277,14 +286,15 @@ def state_control(frame, rcv_frame, plan, path_plan, CS, CP, state, events, v_cr
saturated_count = saturated_count + 1 if angle_control_saturated and not CS.steeringPressed and active else 0
- # Send a "steering required alert" if saturation count has reached the limit
- if (lac_log.saturated and not CS.steeringPressed) or (saturated_count > STEER_ANGLE_SATURATION_TIMEOUT):
- # Check if we deviated from the path
- left_deviation = actuators.steer > 0 and path_plan.dPoly[3] > 0.1
- right_deviation = actuators.steer < 0 and path_plan.dPoly[3] < -0.1
+ if dragon_display_steering_limit_alert and dragon_lat_control:
+ # Send a "steering required alert" if saturation count has reached the limit
+ if (lac_log.saturated and not CS.steeringPressed) or (saturated_count > STEER_ANGLE_SATURATION_TIMEOUT):
+ # Check if we deviated from the path
+ left_deviation = actuators.steer > 0 and path_plan.dPoly[3] > 0.1
+ right_deviation = actuators.steer < 0 and path_plan.dPoly[3] < -0.1
- if left_deviation or right_deviation:
- AM.add(frame, "steerSaturated", enabled)
+ if left_deviation or right_deviation:
+ AM.add(frame, "steerSaturated", enabled)
# Parse permanent warnings to display constantly
for e in get_events(events, [ET.PERMANENT]):
@@ -302,7 +312,7 @@ def state_control(frame, rcv_frame, plan, path_plan, CS, CP, state, events, v_cr
def data_send(sm, pm, CS, CI, CP, VM, state, events, actuators, v_cruise_kph, rk, AM,
LaC, LoC, read_only, start_time, v_acc, a_acc, lac_log, events_prev,
- last_blinker_frame, is_ldw_enabled, can_error_counter):
+ last_blinker_frame, is_ldw_enabled, can_error_counter, dp_camera_offset):
"""Send actuators and hud commands to the car, send controlsstate and MPC logging"""
CC = car.CarControl.new_message()
@@ -336,8 +346,8 @@ def data_send(sm, pm, CS, CI, CP, VM, state, events, actuators, v_cruise_kph, rk
l_lane_change_prob = md.meta.desirePrediction[log.PathPlan.Desire.laneChangeLeft - 1]
r_lane_change_prob = md.meta.desirePrediction[log.PathPlan.Desire.laneChangeRight - 1]
- l_lane_close = left_lane_visible and (sm['pathPlan'].lPoly[3] < (1.08 - CAMERA_OFFSET))
- r_lane_close = right_lane_visible and (sm['pathPlan'].rPoly[3] > -(1.08 + CAMERA_OFFSET))
+ l_lane_close = left_lane_visible and (sm['pathPlan'].lPoly[3] < (1.08 - dp_camera_offset))
+ r_lane_close = right_lane_visible and (sm['pathPlan'].rPoly[3] > -(1.08 + dp_camera_offset))
if ldw_allowed:
CC.hudControl.leftLaneDepart = bool(l_lane_change_prob > LANE_DEPARTURE_THRESHOLD and l_lane_close)
@@ -535,12 +545,42 @@ def controlsd_thread(sm=None, pm=None, can_sock=None):
prof = Profiler(False) # off by default
+ # dp
+ ts_last_check = 0.
+ dragon_toyota_stock_dsu = False
+ dragon_lat_control = True
+ dragon_display_steering_limit_alert = True
+ dragon_stopped_has_lead_count = 0
+ dragon_lead_car_moving_alert = False
+ dp_last_modified = None
+ dp_camera_offset = CAMERA_OFFSET
+
while True:
start_time = sec_since_boot()
+
+ # dp
+ ts = start_time
+ if ts - ts_last_check >= 5.:
+ modified = get_last_modified()
+ if dp_last_modified != modified:
+ try:
+ dp_camera_offset = int(params.get("DragonCameraOffset", encoding='utf8')) * 0.01
+ except (TypeError, ValueError):
+ dp_camera_offset = CAMERA_OFFSET
+ dragon_toyota_stock_dsu = True if params.get("DragonToyotaStockDSU", encoding='utf8') == "1" else False
+ dragon_lat_control = False if params.get("DragonLatCtrl", encoding='utf8') == "0" else True
+ if dragon_lat_control:
+ dragon_display_steering_limit_alert = False if params.get("DragonDisplaySteeringLimitAlert", encoding='utf8') == "0" else True
+ else:
+ dragon_display_steering_limit_alert = False
+ dragon_lead_car_moving_alert = True if params.get("DragonEnableLeadCarMovingAlert", encoding='utf8') == "1" else False
+ dp_last_modified = modified
+ ts_last_check = ts
+
prof.checkpoint("Ratekeeper", ignore=True)
# Sample data and compute car events
- CS, events, cal_perc, mismatch_counter, can_error_counter = data_sample(CI, CC, sm, can_sock, state, mismatch_counter, can_error_counter, params)
+ CS, events, cal_perc, mismatch_counter, can_error_counter = data_sample(CI, CC, sm, can_sock, state, mismatch_counter, can_error_counter, params, dragon_toyota_stock_dsu)
prof.checkpoint("Sample")
# Create alerts
@@ -561,7 +601,10 @@ def controlsd_thread(sm=None, pm=None, can_sock=None):
if sm['plan'].radarCanError:
events.append(create_event('radarCanError', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
if not CS.canValid:
- events.append(create_event('canError', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))
+ if dragon_toyota_stock_dsu:
+ events.append(create_event('pcmDisable', [ET.USER_DISABLE]))
+ else:
+ events.append(create_event('canError', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))
if not sounds_available:
events.append(create_event('soundsUnavailable', [ET.NO_ENTRY, ET.PERMANENT]))
if internet_needed:
@@ -575,9 +618,29 @@ def controlsd_thread(sm=None, pm=None, can_sock=None):
# Only allow engagement with brake pressed when stopped behind another stopped car
- if CS.brakePressed and sm['plan'].vTargetFuture >= STARTING_TARGET_SPEED and not CP.radarOffCan and CS.vEgo < 0.3:
+ if not dragon_toyota_stock_dsu and CS.brakePressed and sm['plan'].vTargetFuture >= STARTING_TARGET_SPEED and not CP.radarOffCan and CS.vEgo < 0.3:
events.append(create_event('noTarget', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))
+ # dp
+ if dragon_lead_car_moving_alert:
+ # when car has a lead and is standstill and lead is barely moving, we start counting
+ if not CP.radarOffCan and sm['plan'].hasLead and CS.vEgo <= 0.01 and 0.3 >= abs(sm['plan'].vTarget) >= 0:
+ dragon_stopped_has_lead_count += 1
+ else:
+ dragon_stopped_has_lead_count = 0
+
+ # when we detect lead car over 3 secs and the lead car is started moving, we are ready to send alerts
+ # once the condition is triggered, we want to keep the trigger
+ if dragon_stopped_has_lead_count >= 300:
+ if abs(sm['plan'].vTargetFuture) >= 0.1:
+ events.append(create_event('leadCarMoving', [ET.WARNING]))
+ else:
+ events.append(create_event('leadCarDetected', [ET.WARNING]))
+
+ # we remove alert once our car is moving
+ if CS.vEgo > 0.:
+ dragon_stopped_has_lead_count = 0
+
if not read_only:
# update control state
state, soft_disable_timer, v_cruise_kph, v_cruise_kph_last = \
@@ -587,14 +650,14 @@ def controlsd_thread(sm=None, pm=None, can_sock=None):
# Compute actuators (runs PID loops and lateral MPC)
actuators, v_cruise_kph, v_acc, a_acc, lac_log, last_blinker_frame, saturated_count = \
state_control(sm.frame, sm.rcv_frame, sm['plan'], sm['pathPlan'], CS, CP, state, events, v_cruise_kph, v_cruise_kph_last, AM, rk,
- LaC, LoC, read_only, is_metric, cal_perc, last_blinker_frame, saturated_count)
+ LaC, LoC, read_only, is_metric, cal_perc, last_blinker_frame, saturated_count, dragon_lat_control, dragon_display_steering_limit_alert, dragon_lead_car_moving_alert)
prof.checkpoint("State Control")
# Publish data
CC, events_prev = data_send(sm, pm, CS, CI, CP, VM, state, events, actuators, v_cruise_kph, rk, AM, LaC,
LoC, read_only, start_time, v_acc, a_acc, lac_log, events_prev, last_blinker_frame,
- is_ldw_enabled, can_error_counter)
+ is_ldw_enabled, can_error_counter, dp_camera_offset)
prof.checkpoint("Sent")
rk.monitor_time()
diff --git a/selfdrive/controls/dmonitoringd.py b/selfdrive/controls/dmonitoringd.py
index c9c370442..1d55cdf50 100755
--- a/selfdrive/controls/dmonitoringd.py
+++ b/selfdrive/controls/dmonitoringd.py
@@ -1,11 +1,13 @@
#!/usr/bin/env python3
import gc
-from common.realtime import set_realtime_priority
+from common.realtime import set_realtime_priority, sec_since_boot
from common.params import Params
import cereal.messaging as messaging
from selfdrive.controls.lib.drive_helpers import create_event, EventTypes as ET
from selfdrive.controls.lib.driver_monitor import DriverStatus, MAX_TERMINAL_ALERTS, MAX_TERMINAL_DURATION
from selfdrive.locationd.calibration_helpers import Calibration
+params = Params()
+from common.dp import get_last_modified
def dmonitoringd_thread(sm=None, pm=None):
gc.disable()
@@ -40,8 +42,37 @@ def dmonitoringd_thread(sm=None, pm=None):
v_cruise_last = 0
driver_engaged = False
+ # dragonpilot
+ last_ts = 0
+ dp_last_modified = None
+ dp_enable_driver_monitoring = True
+
# 10Hz <- dmonitoringmodeld
while True:
+ cur_time = sec_since_boot()
+ if cur_time - last_ts >= 5.:
+ modified = get_last_modified()
+ if dp_last_modified != modified:
+ dp_enable_driver_monitoring = False if params.get("DragonEnableDriverMonitoring", encoding='utf8') == "0" else True
+ try:
+ dp_awareness_time = int(params.get("DragonSteeringMonitorTimer", encoding='utf8'))
+ except (TypeError, ValueError):
+ dp_awareness_time = 70.
+ driver_status.awareness_time = 86400 if dp_awareness_time <= 0. else dp_awareness_time * 60.
+ dp_last_modified = modified
+ last_ts = cur_time
+
+ # reset all awareness val and set to rhd region, this will enforce steering monitor.
+ if not dp_enable_driver_monitoring:
+ driver_status.active_monitoring_mode = False
+ driver_status.awareness = 1.
+ driver_status.awareness_active = 1.
+ driver_status.awareness_passive = 1.
+ driver_status.terminal_alert_cnt = 0
+ driver_status.terminal_time = 0
+ driver_status.face_detected = False
+ driver_status.hi_stds = 0
+
sm.update()
# Handle calibration
diff --git a/selfdrive/controls/lib/alerts.py b/selfdrive/controls/lib/alerts.py
index 2b2b78aab..6d9d1b489 100644
--- a/selfdrive/controls/lib/alerts.py
+++ b/selfdrive/controls/lib/alerts.py
@@ -1,4 +1,8 @@
+# This Python file uses the following encoding: utf-8
+# -*- coding: utf-8 -*-
from cereal import car, log
+from selfdrive.common.i18n import alerts
+_ = alerts()
# Priority
class Priority:
@@ -75,438 +79,438 @@ ALERTS = [
Alert(
"fcw",
- "BRAKE!",
- "Risk of Collision",
+ _("BRAKE!"),
+ _("Risk of Collision"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.chimeWarningRepeat, 1., 2., 2.),
Alert(
"fcwStock",
- "BRAKE!",
- "Risk of Collision",
+ _("BRAKE!"),
+ _("Risk of Collision"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 1., 2., 2.), # no EON chime for stock FCW
Alert(
"steerSaturated",
- "TAKE CONTROL",
- "Turn Exceeds Steering Limit",
+ _("TAKE CONTROL"),
+ _("Turn Exceeds Steering Limit"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 2., 3.),
Alert(
"steerTempUnavailable",
- "TAKE CONTROL",
- "Steering Temporarily Unavailable",
+ _("TAKE CONTROL"),
+ _("Steering Temporarily Unavailable"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3.),
Alert(
"steerTempUnavailableMute",
- "TAKE CONTROL",
- "Steering Temporarily Unavailable",
+ _("TAKE CONTROL"),
+ _("Steering Temporarily Unavailable"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2, .2, .2),
Alert(
"preDriverDistracted",
- "KEEP EYES ON ROAD: Driver Distracted",
+ _("KEEP EYES ON ROAD: Driver Distracted"),
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75),
Alert(
"promptDriverDistracted",
- "KEEP EYES ON ROAD",
- "Driver Appears Distracted",
+ _("KEEP EYES ON ROAD"),
+ _("Driver Appears Distracted"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1),
Alert(
"driverDistracted",
- "DISENGAGE IMMEDIATELY",
- "Driver Was Distracted",
+ _("DISENGAGE IMMEDIATELY"),
+ _("Driver Was Distracted"),
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1),
Alert(
"preDriverUnresponsive",
- "TOUCH STEERING WHEEL: No Face Detected",
+ _("TOUCH STEERING WHEEL: No Face Detected"),
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75),
Alert(
"promptDriverUnresponsive",
- "TOUCH STEERING WHEEL",
- "Driver Is Unresponsive",
+ _("TOUCH STEERING WHEEL"),
+ _("Driver Is Unresponsive"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1),
Alert(
"driverUnresponsive",
- "DISENGAGE IMMEDIATELY",
- "Driver Was Unresponsive",
+ _("DISENGAGE IMMEDIATELY"),
+ _("Driver Was Unresponsive"),
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1),
Alert(
"driverMonitorLowAcc",
- "CHECK DRIVER FACE VISIBILITY",
- "Driver Monitor Model Output Uncertain",
+ _("CHECK DRIVER FACE VISIBILITY"),
+ _("Driver Monitor Model Output Uncertain"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .4, 0., 1.),
Alert(
"geofence",
- "DISENGAGEMENT REQUIRED",
- "Not in Geofenced Area",
+ _("DISENGAGEMENT REQUIRED"),
+ _("Not in Geofenced Area"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1),
Alert(
"startup",
- "Be ready to take over at any time",
- "Always keep hands on wheel and eyes on road",
+ _("Be ready to take over at any time"),
+ _("Always keep hands on wheel and eyes on road"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.),
Alert(
"startupMaster",
- "WARNING: This branch is not tested",
- "Always keep hands on wheel and eyes on road",
+ _("WARNING: This branch is not tested"),
+ _("Always keep hands on wheel and eyes on road"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.),
Alert(
"startupNoControl",
- "Dashcam mode",
- "Always keep hands on wheel and eyes on road",
+ _("Dashcam mode"),
+ _("Always keep hands on wheel and eyes on road"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.),
Alert(
"startupNoCar",
- "Dashcam mode for unsupported car",
- "Always keep hands on wheel and eyes on road",
+ _("Dashcam mode for unsupported car"),
+ _("Always keep hands on wheel and eyes on road"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.),
Alert(
"ethicalDilemma",
- "TAKE CONTROL IMMEDIATELY",
- "Ethical Dilemma Detected",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Ethical Dilemma Detected"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 1., 3., 3.),
Alert(
"steerTempUnavailableNoEntry",
- "openpilot Unavailable",
- "Steering Temporarily Unavailable",
+ _("openpilot Unavailable"),
+ _("Steering Temporarily Unavailable"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 0., 3.),
Alert(
"manualRestart",
- "TAKE CONTROL",
- "Resume Driving Manually",
+ _("TAKE CONTROL"),
+ _("Resume Driving Manually"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"resumeRequired",
- "STOPPED",
- "Press Resume to Move",
+ _("STOPPED"),
+ _("Press Resume to Move"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"belowSteerSpeed",
- "TAKE CONTROL",
- "Steer Unavailable Below ",
+ _("TAKE CONTROL"),
+ _("Steer Unavailable Below "),
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.none, 0., 0.4, .3),
Alert(
"debugAlert",
- "DEBUG ALERT",
+ _("DEBUG ALERT"),
"",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1, .1, .1),
Alert(
"preLaneChangeLeft",
- "Steer Left to Start Lane Change",
- "Monitor Other Vehicles",
+ _("Steer Left to Start Lane Change"),
+ _("Monitor Other Vehicles"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75),
Alert(
"preLaneChangeRight",
- "Steer Right to Start Lane Change",
- "Monitor Other Vehicles",
+ _("Steer Right to Start Lane Change"),
+ _("Monitor Other Vehicles"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75),
Alert(
"laneChange",
- "Changing Lane",
- "Monitor Other Vehicles",
+ _("Changing Lane"),
+ _("Monitor Other Vehicles"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1),
Alert(
"posenetInvalid",
- "TAKE CONTROL",
- "Vision Model Output Uncertain",
+ _("TAKE CONTROL"),
+ _("Vision Model Output Uncertain"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3.),
# Non-entry only alerts
Alert(
"wrongCarModeNoEntry",
- "openpilot Unavailable",
- "Main Switch Off",
+ _("openpilot Unavailable"),
+ _("Main Switch Off"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 0., 3.),
Alert(
"dataNeededNoEntry",
- "openpilot Unavailable",
- "Calibration Needs Data. Upload Drive, Try Again",
+ _("openpilot Unavailable"),
+ _("Calibration Needs Data. Upload Drive, Try Again"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 0., 3.),
Alert(
"outOfSpaceNoEntry",
- "openpilot Unavailable",
- "Out of Storage Space",
+ _("openpilot Unavailable"),
+ _("Out of Storage Space"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 0., 3.),
Alert(
"pedalPressedNoEntry",
- "openpilot Unavailable",
- "Pedal Pressed During Attempt",
+ _("openpilot Unavailable"),
+ _("Pedal Pressed During Attempt"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, "brakePressed", AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"speedTooLowNoEntry",
- "openpilot Unavailable",
- "Speed Too Low",
+ _("openpilot Unavailable"),
+ _("Speed Too Low"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"brakeHoldNoEntry",
- "openpilot Unavailable",
- "Brake Hold Active",
+ _("openpilot Unavailable"),
+ _("Brake Hold Active"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"parkBrakeNoEntry",
- "openpilot Unavailable",
- "Park Brake Engaged",
+ _("openpilot Unavailable"),
+ _("Park Brake Engaged"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"lowSpeedLockoutNoEntry",
- "openpilot Unavailable",
- "Cruise Fault: Restart the Car",
+ _("openpilot Unavailable"),
+ _("Cruise Fault: Restart the Car"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"lowBatteryNoEntry",
- "openpilot Unavailable",
- "Low Battery",
+ _("openpilot Unavailable"),
+ _("Low Battery"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"sensorDataInvalidNoEntry",
- "openpilot Unavailable",
- "No Data from Device Sensors",
+ _("openpilot Unavailable"),
+ _("No Data from Device Sensors"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"soundsUnavailableNoEntry",
- "openpilot Unavailable",
- "Speaker not found",
+ _("openpilot Unavailable"),
+ _("Speaker not found"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"tooDistractedNoEntry",
- "openpilot Unavailable",
- "Distraction Level Too High",
+ _("openpilot Unavailable"),
+ _("Distraction Level Too High"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
# Cancellation alerts causing soft disabling
Alert(
"overheat",
- "TAKE CONTROL IMMEDIATELY",
- "System Overheated",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("System Overheated"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"wrongGear",
- "TAKE CONTROL IMMEDIATELY",
- "Gear not D",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Gear not D"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"calibrationInvalid",
- "TAKE CONTROL IMMEDIATELY",
- "Calibration Invalid: Reposition Device and Recalibrate",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Calibration Invalid: Reposition Device and Recalibrate"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"calibrationIncomplete",
- "TAKE CONTROL IMMEDIATELY",
- "Calibration in Progress",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Calibration in Progress"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"doorOpen",
- "TAKE CONTROL IMMEDIATELY",
- "Door Open",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Door Open"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"seatbeltNotLatched",
- "TAKE CONTROL IMMEDIATELY",
- "Seatbelt Unlatched",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Seatbelt Unlatched"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"espDisabled",
- "TAKE CONTROL IMMEDIATELY",
- "ESP Off",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("ESP Off"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"lowBattery",
- "TAKE CONTROL IMMEDIATELY",
- "Low Battery",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Low Battery"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"commIssue",
- "TAKE CONTROL IMMEDIATELY",
- "Communication Issue between Processes",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Communication Issue between Processes"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"radarCommIssue",
- "TAKE CONTROL IMMEDIATELY",
- "Radar Communication Issue",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Radar Communication Issue"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"radarCanError",
- "TAKE CONTROL IMMEDIATELY",
- "Radar Error: Restart the Car",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Radar Error: Restart the Car"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"radarFault",
- "TAKE CONTROL IMMEDIATELY",
- "Radar Error: Restart the Car",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Radar Error: Restart the Car"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
Alert(
"lowMemory",
- "TAKE CONTROL IMMEDIATELY",
- "Low Memory: Reboot Your Device",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Low Memory: Reboot Your Device"),
AlertStatus.critical, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.),
# Cancellation alerts causing immediate disabling
Alert(
"controlsFailed",
- "TAKE CONTROL IMMEDIATELY",
- "Controls Failed",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Controls Failed"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
Alert(
"controlsMismatch",
- "TAKE CONTROL IMMEDIATELY",
- "Controls Mismatch",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Controls Mismatch"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
Alert(
"canError",
- "TAKE CONTROL IMMEDIATELY",
- "CAN Error: Check Connections",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("CAN Error: Check Connections"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
Alert(
"steerUnavailable",
- "TAKE CONTROL IMMEDIATELY",
- "LKAS Fault: Restart the Car",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("LKAS Fault: Restart the Car"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
Alert(
"brakeUnavailable",
- "TAKE CONTROL IMMEDIATELY",
- "Cruise Fault: Restart the Car",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Cruise Fault: Restart the Car"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
Alert(
"gasUnavailable",
- "TAKE CONTROL IMMEDIATELY",
- "Gas Fault: Restart the Car",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Gas Fault: Restart the Car"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
Alert(
"reverseGear",
- "TAKE CONTROL IMMEDIATELY",
- "Reverse Gear",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Reverse Gear"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
Alert(
"cruiseDisabled",
- "TAKE CONTROL IMMEDIATELY",
- "Cruise Is Off",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Cruise Is Off"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
Alert(
"plannerError",
- "TAKE CONTROL IMMEDIATELY",
- "Planner Solution Error",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Planner Solution Error"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
Alert(
"relayMalfunction",
- "TAKE CONTROL IMMEDIATELY",
- "Harness Malfunction",
+ _("TAKE CONTROL IMMEDIATELY"),
+ _("Harness Malfunction"),
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
@@ -514,311 +518,359 @@ ALERTS = [
# not loud cancellations (user is in control)
Alert(
"noTarget",
- "openpilot Canceled",
- "No close lead car",
+ _("openpilot Canceled"),
+ _("No close lead car"),
AlertStatus.normal, AlertSize.mid,
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.),
Alert(
"speedTooLow",
- "openpilot Canceled",
- "Speed too low",
+ _("openpilot Canceled"),
+ _("Speed too low"),
AlertStatus.normal, AlertSize.mid,
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.),
Alert(
"speedTooHigh",
- "Speed Too High",
- "Slow down to resume operation",
+ _("Speed Too High"),
+ _("Slow down to resume operation"),
AlertStatus.normal, AlertSize.mid,
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.),
# Cancellation alerts causing non-entry
Alert(
"overheatNoEntry",
- "openpilot Unavailable",
- "System overheated",
+ _("openpilot Unavailable"),
+ _("System overheated"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"wrongGearNoEntry",
- "openpilot Unavailable",
- "Gear not D",
+ _("openpilot Unavailable"),
+ _("Gear not D"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"calibrationInvalidNoEntry",
- "openpilot Unavailable",
- "Calibration Invalid: Reposition Device & Recalibrate",
+ _("openpilot Unavailable"),
+ _("Calibration Invalid: Reposition Device & Recalibrate"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"calibrationIncompleteNoEntry",
- "openpilot Unavailable",
- "Calibration in Progress",
+ _("openpilot Unavailable"),
+ _("Calibration in Progress"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"doorOpenNoEntry",
- "openpilot Unavailable",
- "Door open",
+ _("openpilot Unavailable"),
+ _("Door open"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"seatbeltNotLatchedNoEntry",
- "openpilot Unavailable",
- "Seatbelt unlatched",
+ _("openpilot Unavailable"),
+ _("Seatbelt unlatched"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"espDisabledNoEntry",
- "openpilot Unavailable",
- "ESP Off",
+ _("openpilot Unavailable"),
+ _("ESP Off"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"geofenceNoEntry",
- "openpilot Unavailable",
- "Not in Geofenced Area",
+ _("openpilot Unavailable"),
+ _("Not in Geofenced Area"),
AlertStatus.normal, AlertSize.mid,
Priority.MID, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"radarCanErrorNoEntry",
- "openpilot Unavailable",
- "Radar Error: Restart the Car",
+ _("openpilot Unavailable"),
+ _("Radar Error: Restart the Car"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"radarFaultNoEntry",
- "openpilot Unavailable",
- "Radar Error: Restart the Car",
+ _("openpilot Unavailable"),
+ _("Radar Error: Restart the Car"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"posenetInvalidNoEntry",
- "openpilot Unavailable",
- "Vision Model Output Uncertain",
+ _("openpilot Unavailable"),
+ _("Vision Model Output Uncertain"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"controlsFailedNoEntry",
- "openpilot Unavailable",
- "Controls Failed",
+ _("openpilot Unavailable"),
+ _("Controls Failed"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"canErrorNoEntry",
- "openpilot Unavailable",
- "CAN Error: Check Connections",
+ _("openpilot Unavailable"),
+ _("CAN Error: Check Connections"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"steerUnavailableNoEntry",
- "openpilot Unavailable",
- "LKAS Fault: Restart the Car",
+ _("openpilot Unavailable"),
+ _("LKAS Fault: Restart the Car"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"brakeUnavailableNoEntry",
- "openpilot Unavailable",
- "Cruise Fault: Restart the Car",
+ _("openpilot Unavailable"),
+ _("Cruise Fault: Restart the Car"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"gasUnavailableNoEntry",
- "openpilot Unavailable",
- "Gas Error: Restart the Car",
+ _("openpilot Unavailable"),
+ _("Gas Error: Restart the Car"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"reverseGearNoEntry",
- "openpilot Unavailable",
- "Reverse Gear",
+ _("openpilot Unavailable"),
+ _("Reverse Gear"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"cruiseDisabledNoEntry",
- "openpilot Unavailable",
- "Cruise is Off",
+ _("openpilot Unavailable"),
+ _("Cruise is Off"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"noTargetNoEntry",
- "openpilot Unavailable",
- "No Close Lead Car",
+ _("openpilot Unavailable"),
+ _("No Close Lead Car"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"plannerErrorNoEntry",
- "openpilot Unavailable",
- "Planner Solution Error",
+ _("openpilot Unavailable"),
+ _("Planner Solution Error"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"commIssueNoEntry",
- "openpilot Unavailable",
- "Communication Issue between Processes",
+ _("openpilot Unavailable"),
+ _("Communication Issue between Processes"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.),
Alert(
"radarCommIssueNoEntry",
- "openpilot Unavailable",
- "Radar Communication Issue",
+ _("openpilot Unavailable"),
+ _("Radar Communication Issue"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.),
Alert(
"internetConnectivityNeededNoEntry",
- "openpilot Unavailable",
- "Please Connect to Internet",
+ _("openpilot Unavailable"),
+ _("Please Connect to Internet"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.),
Alert(
"lowMemoryNoEntry",
- "openpilot Unavailable",
- "Low Memory: Reboot Your Device",
+ _("openpilot Unavailable"),
+ _("Low Memory: Reboot Your Device"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.),
Alert(
"speedTooHighNoEntry",
- "Speed Too High",
- "Slow down to engage",
+ _("Speed Too High"),
+ _("Slow down to engage"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
Alert(
"relayMalfunctionNoEntry",
- "openpilot Unavailable",
- "Harness Malfunction",
+ _("openpilot Unavailable"),
+ _("Harness Malfunction"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
# permanent alerts
Alert(
"steerUnavailablePermanent",
- "LKAS Fault: Restart the car to engage",
+ _("LKAS Fault: Restart the car to engage"),
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"brakeUnavailablePermanent",
- "Cruise Fault: Restart the car to engage",
+ _("Cruise Fault: Restart the car to engage"),
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"lowSpeedLockoutPermanent",
- "Cruise Fault: Restart the car to engage",
+ _("Cruise Fault: Restart the car to engage"),
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"calibrationIncompletePermanent",
- "Calibration in Progress: ",
- "Drive Above ",
+ _("Calibration in Progress: "),
+ _("Drive Above "),
AlertStatus.normal, AlertSize.mid,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"invalidGiraffeToyotaPermanent",
- "Unsupported Giraffe Configuration",
- "Visit comma.ai/tg",
+ _("Unsupported Giraffe Configuration"),
+ _("Visit comma.ai/tg"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"invalidLkasSettingPermanent",
- "Stock LKAS is turned on",
- "Turn off stock LKAS to engage",
+ _("Stock LKAS is turned on"),
+ _("Turn off stock LKAS to engage"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"internetConnectivityNeededPermanent",
- "Please connect to Internet",
- "An Update Check Is Required to Engage",
+ _("Please connect to Internet"),
+ _("An Update Check Is Required to Engage"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"communityFeatureDisallowedPermanent",
- "Community Feature Detected",
- "Enable Community Features in Developer Settings",
+ _("Community Feature Detected"),
+ _("Enable Community Features in Developer Settings"),
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), # LOW priority to overcome Cruise Error
Alert(
"sensorDataInvalidPermanent",
- "No Data from Device Sensors",
- "Reboot your Device",
+ _("No Data from Device Sensors"),
+ _("Reboot your Device"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"soundsUnavailablePermanent",
- "Speaker not found",
- "Reboot your Device",
+ _("Speaker not found"),
+ _("Reboot your Device"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"lowMemoryPermanent",
- "RAM Critically Low",
- "Reboot your Device",
+ _("RAM Critically Low"),
+ _("Reboot your Device"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"carUnrecognizedPermanent",
- "Dashcam Mode",
- "Car Unrecognized",
+ _("Dashcam Mode"),
+ _("Car Unrecognized"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"relayMalfunctionPermanent",
- "Harness Malfunction",
- "Please Check Hardware",
+ _("Harness Malfunction"),
+ _("Please Check Hardware"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
Alert(
"vehicleModelInvalid",
- "Vehicle Parameter Identification Failed",
+ _("Vehicle Parameter Identification Failed"),
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWEST, VisualAlert.steerRequired, AudibleAlert.none, .0, .0, .1),
Alert(
"ldwPermanent",
- "TAKE CONTROL",
- "Lane Departure Detected",
+ _("TAKE CONTROL"),
+ _("Lane Departure Detected"),
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 2., 3.),
+
+ # dp
+ Alert(
+ "preLaneChangeLeftALC",
+ _("Left ALC will engage in 3 seconds"),
+ _("Monitor Other Vehicles"),
+ AlertStatus.normal, AlertSize.mid,
+ Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning2, .1, .1, .1, alert_rate=0.75),
+
+ Alert(
+ "preLaneChangeRightALC",
+ _("Right ALC will engage in 3 seconds"),
+ _("Monitor Other Vehicles"),
+ AlertStatus.normal, AlertSize.mid,
+ Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning2, .1, .1, .1, alert_rate=0.75),
+
+ Alert(
+ "laneChangeALC",
+ _("Changing Lane"),
+ _("Monitor Other Vehicles"),
+ AlertStatus.normal, AlertSize.mid,
+ Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning2, .1, .1, .1),
+
+ Alert(
+ "manualSteeringRequired",
+ _("STEERING REQUIRED: Lane Keeping OFF"),
+ "",
+ AlertStatus.normal, AlertSize.small,
+ Priority.LOW, VisualAlert.none, AudibleAlert.none, .0, .1, .1, alert_rate=0.25),
+
+ Alert(
+ "manualSteeringRequiredBlinkersOn",
+ _("STEERING REQUIRED: Blinkers ON"),
+ "",
+ AlertStatus.normal, AlertSize.small,
+ Priority.LOW, VisualAlert.none, AudibleAlert.none, .0, .1, .1, alert_rate=0.25),
+ Alert(
+ "leadCarMoving",
+ _("Lead Car Is Moving"),
+ "",
+ AlertStatus.userPrompt, AlertSize.small,
+ Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning2, .1, .1, .1),
+ Alert(
+ "leadCarDetected",
+ _("Lead Car Detected"),
+ "",
+ AlertStatus.normal, AlertSize.small,
+ Priority.LOW, VisualAlert.none, AudibleAlert.none, .0, .1, .1, alert_rate=0.25),
]
diff --git a/selfdrive/controls/lib/driver_monitor.py b/selfdrive/controls/lib/driver_monitor.py
index 73ef07777..477c13f19 100644
--- a/selfdrive/controls/lib/driver_monitor.py
+++ b/selfdrive/controls/lib/driver_monitor.py
@@ -117,6 +117,9 @@ class DriverStatus():
self.is_rhd_region = False
self.is_rhd_region_checked = False
+ # dp
+ self.awareness_time = _AWARENESS_TIME
+
self._set_timers(active_monitoring=True)
def _set_timers(self, active_monitoring):
@@ -144,9 +147,9 @@ class DriverStatus():
self.awareness_active = self.awareness
self.awareness = self.awareness_passive
- self.threshold_pre = _AWARENESS_PRE_TIME_TILL_TERMINAL / _AWARENESS_TIME
- self.threshold_prompt = _AWARENESS_PROMPT_TIME_TILL_TERMINAL / _AWARENESS_TIME
- self.step_change = DT_DMON / _AWARENESS_TIME
+ self.threshold_pre = _AWARENESS_PRE_TIME_TILL_TERMINAL / self.awareness_time
+ self.threshold_prompt = _AWARENESS_PROMPT_TIME_TILL_TERMINAL / self.awareness_time
+ self.step_change = DT_DMON / self.awareness_time
self.active_monitoring_mode = False
def _is_driver_distracted(self, pose, blink):
diff --git a/selfdrive/controls/lib/lane_planner.py b/selfdrive/controls/lib/lane_planner.py
index 5b9485a29..264b710d2 100644
--- a/selfdrive/controls/lib/lane_planner.py
+++ b/selfdrive/controls/lib/lane_planner.py
@@ -1,6 +1,10 @@
from common.numpy_fast import interp
import numpy as np
from cereal import log
+from common.dp import get_last_modified
+from common.realtime import sec_since_boot
+from common.params import Params
+params = Params()
CAMERA_OFFSET = 0.06 # m from center car to camera
@@ -65,6 +69,11 @@ class LanePlanner():
self._path_pinv = compute_path_pinv()
self.x_points = np.arange(50)
+ # dp
+ self.last_ts = 0.
+ self.last_modified = 0.
+ self.camera_offset = 0.06
+
def parse_model(self, md):
if len(md.leftLane.poly):
self.l_poly = np.array(md.leftLane.poly)
@@ -82,9 +91,19 @@ class LanePlanner():
self.r_lane_change_prob = md.meta.desireState[log.PathPlan.Desire.laneChangeRight - 1]
def update_d_poly(self, v_ego):
+ ts = sec_since_boot()
+ if ts - self.last_ts >= 5.:
+ modified = get_last_modified()
+ if self.last_modified != modified:
+ try:
+ self.camera_offset = int(params.get("DragonCameraOffset", encoding='utf8')) * 0.01
+ except (TypeError, ValueError):
+ self.camera_offset = CAMERA_OFFSET
+ self.last_modified = modified
+ self.last_ts = ts
# only offset left and right lane lines; offsetting p_poly does not make sense
- self.l_poly[3] += CAMERA_OFFSET
- self.r_poly[3] += CAMERA_OFFSET
+ self.l_poly[3] += self.camera_offset
+ self.r_poly[3] += self.camera_offset
# Find current lanewidth
self.lane_width_certainty += 0.05 * (self.l_prob * self.r_prob - self.lane_width_certainty)
diff --git a/selfdrive/controls/lib/long_mpc.py b/selfdrive/controls/lib/long_mpc.py
index b83354065..053ea725e 100644
--- a/selfdrive/controls/lib/long_mpc.py
+++ b/selfdrive/controls/lib/long_mpc.py
@@ -1,5 +1,6 @@
import os
import math
+import time
import cereal.messaging as messaging
from selfdrive.swaglog import cloudlog
@@ -8,8 +9,19 @@ from selfdrive.controls.lib.radar_helpers import _LEAD_ACCEL_TAU
from selfdrive.controls.lib.longitudinal_mpc import libmpc_py
from selfdrive.controls.lib.drive_helpers import MPC_COST_LONG
+# dp + df
+from common.numpy_fast import interp, clip
+from selfdrive.config import Conversions as CV
+from common.params import Params
+from common.dp import get_last_modified
+
LOG_MPC = os.environ.get('LOG_MPC', False)
+# df profile
+DF_PROFILE_OFF = 0
+DF_PROFILE_LONG = 1
+DF_PROFILE_NORMAL = 2
+DF_PROFILE_SHORT = 3
class LongitudinalMpc():
def __init__(self, mpc_id):
@@ -26,6 +38,19 @@ class LongitudinalMpc():
self.last_cloudlog_t = 0.0
+ # df from Shane Smiskol
+ self.car_data = {'v_ego': 0.0, 'a_ego': 0.0}
+ self.lead_data = {'v_lead': None, 'x_lead': None, 'a_lead': None, 'status': False}
+ self.df_data = {"v_leads": [], "v_egos": []} # dynamic follow data
+ self.last_cost = 0.0
+ self.df_profile = DF_PROFILE_OFF
+ self.sng = False
+
+ # dragonpilot
+ self.params = Params()
+ self.last_ts = 0
+ self.last_modified = 0
+
def send_mpc_solution(self, pm, qp_iterations, calculation_time):
qp_iterations = max(0, qp_iterations)
dat = messaging.new_message('liveLongitudinalMpc')
@@ -56,8 +81,134 @@ class LongitudinalMpc():
self.cur_state[0].v_ego = v
self.cur_state[0].a_ego = a
+ def get_TR(self, CS):
+ # load profile
+ ts = sec_since_boot()
+ if ts - self.last_ts >= 5.:
+ modified = get_last_modified()
+ if self.last_modified != modified:
+ try:
+ self.df_profile = int(self.params.get('DragonDynamicFollow', encoding='utf8').rstrip('\x00'))
+ self.df_profile = self.df_profile if self.df_profile in [DF_PROFILE_OFF, DF_PROFILE_LONG, DF_PROFILE_NORMAL, DF_PROFILE_SHORT] else DF_PROFILE_OFF
+ except TypeError:
+ self.df_profile = DF_PROFILE_OFF
+ put_nonblocking('DragonDynamicFollow', DF_PROFILE_OFF)
+ self.last_modified = modified
+ self.last_ts = ts
+
+ if not self.lead_data['status'] or self.df_profile == DF_PROFILE_OFF:
+ TR = 1.8
+ else:
+ self.store_df_data()
+ TR = self.dynamic_follow(CS)
+
+ # only change cost when profile is not off
+ if not self.df_profile == DF_PROFILE_OFF:
+ self.change_cost(TR)
+ return TR
+
+ def change_cost(self, TR):
+ TRs = [0.9, 1.8, 2.7]
+ costs = [1.0, 0.1, 0.05]
+ cost = interp(TR, TRs, costs)
+ if self.last_cost != cost:
+ self.libmpc.change_tr(MPC_COST_LONG.TTC, cost, MPC_COST_LONG.ACCELERATION, MPC_COST_LONG.JERK)
+ self.last_cost = cost
+
+ def store_df_data(self):
+ v_lead_retention = 1.9 # keep only last x seconds
+ v_ego_retention = 2.5
+
+ cur_time = time.time()
+ if self.lead_data['status']:
+ self.df_data['v_leads'] = [sample for sample in self.df_data['v_leads'] if
+ cur_time - sample['time'] <= v_lead_retention
+ and not self.new_lead] # reset when new lead
+ self.df_data['v_leads'].append({'v_lead': self.lead_data['v_lead'], 'time': cur_time})
+
+ self.df_data['v_egos'] = [sample for sample in self.df_data['v_egos'] if cur_time - sample['time'] <= v_ego_retention]
+ self.df_data['v_egos'].append({'v_ego': self.car_data['v_ego'], 'time': cur_time})
+
+ def calculate_lead_accel(self):
+ min_consider_time = 1.0 # minimum amount of time required to consider calculation
+ a_lead = self.lead_data['a_lead']
+ if len(self.df_data['v_leads']): # if not empty
+ elapsed = self.df_data['v_leads'][-1]['time'] - self.df_data['v_leads'][0]['time']
+ if elapsed > min_consider_time: # if greater than min time (not 0)
+ a_calculated = (self.df_data['v_leads'][-1]['v_lead'] - self.df_data['v_leads'][0]['v_lead']) / elapsed # delta speed / delta time
+ # old version: # if abs(a_calculated) > abs(a_lead) and a_lead < 0.33528: # if a_lead is greater than calculated accel (over last 1.5s, use that) and if lead accel is not above 0.75 mph/s
+ # a_lead = a_calculated
+
+ # long version of below: if (a_calculated < 0 and a_lead >= 0 and a_lead < -a_calculated * 0.5) or (a_calculated > 0 and a_lead <= 0 and -a_lead > a_calculated * 0.5) or (a_lead * a_calculated > 0 and abs(a_calculated) > abs(a_lead)):
+ if (a_calculated < 0 <= a_lead < -a_calculated * 0.55) or (a_calculated > 0 >= a_lead and -a_lead < a_calculated * 0.45) or (
+ a_lead * a_calculated > 0 and abs(a_calculated) > abs(a_lead)): # this is a mess, fix
+ a_lead = a_calculated
+ return a_lead # if above doesn't execute, we'll return a_lead from radar
+
+ def dynamic_follow(self, CS):
+ x_vel = [0.0, 1.8627, 3.7253, 5.588, 7.4507, 9.3133, 11.5598, 13.645, 22.352, 31.2928, 33.528, 35.7632, 40.2336] # velocities
+ profile_mod_x = [2.2352, 13.4112, 24.5872, 35.7632] # profile mod speeds, mph: [5., 30., 55., 80.]
+ if self.df_profile == DF_PROFILE_LONG:
+ y_dist = [1.3847, 1.3946, 1.4078, 1.4243, 1.4507, 1.4837, 1.5327, 1.553, 1.581, 1.617, 1.653, 1.687, 1.74] # TRs
+ profile_mod_pos = [0.99, 0.9025, 0.815, 0.55]
+ profile_mod_neg = [1.0, 1.18, 1.382, 1.787]
+ elif self.df_profile == DF_PROFILE_SHORT: # for in congested traffic
+ x_vel = [0.0, 1.892, 3.7432, 5.8632, 8.0727, 10.7301, 14.343, 17.6275, 22.4049, 28.6752, 34.8858, 40.35]
+ y_dist = [1.3781, 1.3791, 1.3802, 1.3825, 1.3984, 1.4249, 1.4194, 1.3162, 1.1916, 1.0145, 0.9855, 0.9562]
+ profile_mod_pos = [1.05, 1.375, 2.99, 3.8]
+ profile_mod_neg = [0.79, .1, 0.0, 0.0]
+ else: # default to relaxed/stock
+ y_dist = [1.385, 1.394, 1.406, 1.421, 1.444, 1.474, 1.516, 1.534, 1.546, 1.568, 1.579, 1.593, 1.614]
+ profile_mod_pos = [1.0] * 4
+ profile_mod_neg = [1.0] * 4
+
+ sng_TR = 1.7 # reacceleration stop and go TR
+ sng_speed = 15.0 * CV.MPH_TO_MS
+
+ if self.car_data['v_ego'] > sng_speed: # keep sng distance until we're above sng speed again
+ self.sng = False
+
+ if (self.car_data['v_ego'] >= sng_speed or self.df_data['v_egos'][0]['v_ego'] >= self.car_data[
+ 'v_ego']) and not self.sng: # if above 15 mph OR we're decelerating to a stop, keep shorter TR. when we reaccelerate, use sng_TR and slowly decrease
+ TR = interp(self.car_data['v_ego'], x_vel, y_dist)
+ else: # this allows us to get closer to the lead car when stopping, while being able to have smooth stop and go when reaccelerating
+ self.sng = True
+ x = [sng_speed / 3.0, sng_speed] # decrease TR between 5 and 15 mph from 1.8s to defined TR above at 15mph while accelerating
+ y = [sng_TR, interp(sng_speed, x_vel, y_dist)]
+ TR = interp(self.car_data['v_ego'], x, y)
+
+ TR_mod = []
+ # Dynamic follow modifications (the secret sauce)
+ x = [-20.0383, -15.6978, -11.2053, -7.8781, -5.0407, -3.2167, -1.6122, 0.0, 0.6847, 1.3772, 1.9007, 2.7452] # relative velocity values
+ y = [0.641, 0.506, 0.418, 0.334, 0.24, 0.115, 0.065, 0.0, -0.049, -0.068, -0.142, -0.221] # modification values
+ TR_mod.append(interp(self.lead_data['v_lead'] - self.car_data['v_ego'], x, y))
+
+ x = [-4.4795, -2.8122, -1.5727, -1.1129, -0.6611, -0.2692, 0.0, 0.1466, 0.5144, 0.6903, 0.9302] # lead acceleration values
+ y = [0.265, 0.187, 0.096, 0.057, 0.033, 0.024, 0.0, -0.009, -0.042, -0.053, -0.059] # modification values
+ TR_mod.append(interp(self.calculate_lead_accel(), x, y))
+
+ profile_mod_pos = interp(self.car_data['v_ego'], profile_mod_x, profile_mod_pos)
+ profile_mod_neg = interp(self.car_data['v_ego'], profile_mod_x, profile_mod_neg)
+
+ TR_mod = sum([mod * profile_mod_neg if mod < 0 else mod * profile_mod_pos for mod in TR_mod]) # alter TR modification according to profile
+ TR += TR_mod
+
+ if CS.leftBlinker or CS.rightBlinker and self.df_profile != DF_PROFILE_SHORT:
+ x = [8.9408, 22.352, 31.2928] # 20, 50, 70 mph
+ y = [1.0, .75, .65] # reduce TR when changing lanes
+ TR *= interp(self.car_data['v_ego'], x, y)
+
+ return clip(TR, 0.9, 2.7)
+
+ def process_lead(self, v_lead, a_lead, x_lead, status):
+ self.lead_data['v_lead'] = v_lead
+ self.lead_data['a_lead'] = a_lead
+ self.lead_data['x_lead'] = x_lead
+ self.lead_data['status'] = status
+
def update(self, pm, CS, lead, v_cruise_setpoint):
v_ego = CS.vEgo
+ self.car_data = {'v_ego': CS.vEgo, 'a_ego': CS.aEgo}
# Setup current mpc state
self.cur_state[0].x_ego = 0.0
@@ -70,6 +221,7 @@ class LongitudinalMpc():
if (v_lead < 0.1 or -a_lead / 2.0 > v_lead):
v_lead = 0.0
a_lead = 0.0
+ self.process_lead(v_lead, a_lead, x_lead, lead.status)
self.a_lead_tau = lead.aLeadTau
self.new_lead = False
@@ -82,6 +234,7 @@ class LongitudinalMpc():
self.cur_state[0].x_l = x_lead
self.cur_state[0].v_l = v_lead
else:
+ self.process_lead(None, None, None, False)
self.prev_lead_status = False
# Fake a fast lead car, so mpc keeps running
self.cur_state[0].x_l = 50.0
@@ -91,7 +244,7 @@ class LongitudinalMpc():
# Calculate mpc
t = sec_since_boot()
- n_its = self.libmpc.run_mpc(self.cur_state, self.mpc_solution, self.a_lead_tau, a_lead)
+ n_its = self.libmpc.run_mpc(self.cur_state, self.mpc_solution, self.a_lead_tau, a_lead, self.get_TR(CS))
duration = int((sec_since_boot() - t) * 1e9)
if LOG_MPC:
diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py
index 8910747cd..01eb8d258 100644
--- a/selfdrive/controls/lib/longcontrol.py
+++ b/selfdrive/controls/lib/longcontrol.py
@@ -71,7 +71,7 @@ class LongControl():
self.pid.reset()
self.v_pid = v_pid
- def update(self, active, v_ego, brake_pressed, standstill, cruise_standstill, v_cruise, v_target, v_target_future, a_target, CP):
+ def update(self, active, v_ego, gas_pressed, brake_pressed, standstill, cruise_standstill, v_cruise, v_target, v_target_future, a_target, CP):
"""Update longitudinal control. This updates the state machine and runs a PID loop"""
# Actuation limits
gas_max = interp(v_ego, CP.gasMaxBP, CP.gasMaxV)
@@ -85,7 +85,7 @@ class LongControl():
v_ego_pid = max(v_ego, MIN_CAN_SPEED) # Without this we get jumps, CAN bus reports 0 when speed < 0.3
- if self.long_control_state == LongCtrlState.off:
+ if self.long_control_state == LongCtrlState.off or gas_pressed or brake_pressed:
self.v_pid = v_ego_pid
self.pid.reset()
output_gb = 0.
diff --git a/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_solver.c b/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_solver.c
index 8cfc06f3b..ba05c6a7e 100644
--- a/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_solver.c
+++ b/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_solver.c
@@ -68,7 +68,7 @@ acadoWorkspace.evGu[lRun1 * 3 + 2] = acadoWorkspace.state[14];
return ret;
}
-void acado_evaluateLSQ(const real_t* in, real_t* out)
+void acado_evaluateLSQ(const real_t* in, real_t* out, double TR)
{
const real_t* xd = in;
const real_t* u = in + 3;
@@ -78,29 +78,29 @@ real_t* a = acadoWorkspace.objAuxVar;
/* Compute intermediate quantities: */
a[0] = (sqrt((xd[1]+(real_t)(5.0000000000000000e-01))));
-a[1] = (exp(((real_t)(2.9999999999999999e-01)*(((((((xd[1]*(real_t)(1.8000000000000000e+00))-((od[1]-xd[1])*(real_t)(1.8000000000000000e+00)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))/(a[0]+(real_t)(1.0000000000000001e-01))))));
+a[1] = (exp(((real_t)(2.9999999999999999e-01)*(((((((xd[1]*(real_t)(TR))-((od[1]-xd[1])*(real_t)(TR)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))/(a[0]+(real_t)(1.0000000000000001e-01))))));
a[2] = ((real_t)(1.0000000000000000e+00)/(a[0]+(real_t)(1.0000000000000001e-01)));
-a[3] = (exp(((real_t)(2.9999999999999999e-01)*(((((((xd[1]*(real_t)(1.8000000000000000e+00))-((od[1]-xd[1])*(real_t)(1.8000000000000000e+00)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))/(a[0]+(real_t)(1.0000000000000001e-01))))));
+a[3] = (exp(((real_t)(2.9999999999999999e-01)*(((((((xd[1]*(real_t)(TR))-((od[1]-xd[1])*(real_t)(TR)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))/(a[0]+(real_t)(1.0000000000000001e-01))))));
a[4] = (((real_t)(2.9999999999999999e-01)*(((real_t)(0.0000000000000000e+00)-((real_t)(0.0000000000000000e+00)-(real_t)(1.0000000000000000e+00)))*a[2]))*a[3]);
a[5] = ((real_t)(1.0000000000000000e+00)/(real_t)(1.9620000000000001e+01));
a[6] = (1.0/sqrt((xd[1]+(real_t)(5.0000000000000000e-01))));
a[7] = (a[6]*(real_t)(5.0000000000000000e-01));
a[8] = (a[2]*a[2]);
-a[9] = (((real_t)(2.9999999999999999e-01)*(((((real_t)(1.8000000000000000e+00)-((real_t)(-1.8000000000000000e+00)))+((xd[1]+xd[1])*a[5]))*a[2])-((((((((xd[1]*(real_t)(1.8000000000000000e+00))-((od[1]-xd[1])*(real_t)(1.8000000000000000e+00)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))*a[7])*a[8])))*a[3]);
+a[9] = (((real_t)(2.9999999999999999e-01)*(((((real_t)(TR)-((real_t)(-TR)))+((xd[1]+xd[1])*a[5]))*a[2])-((((((((xd[1]*(real_t)(TR))-((od[1]-xd[1])*(real_t)(TR)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))*a[7])*a[8])))*a[3]);
a[10] = ((real_t)(1.0000000000000000e+00)/(((real_t)(5.0000000000000003e-02)*xd[1])+(real_t)(5.0000000000000000e-01)));
a[11] = ((real_t)(1.0000000000000000e+00)/(real_t)(1.9620000000000001e+01));
a[12] = (a[10]*a[10]);
/* Compute outputs: */
out[0] = (a[1]-(real_t)(1.0000000000000000e+00));
-out[1] = (((od[0]-xd[0])-((real_t)(4.0000000000000000e+00)+((((xd[1]*(real_t)(1.8000000000000000e+00))-((od[1]-xd[1])*(real_t)(1.8000000000000000e+00)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))))/(((real_t)(5.0000000000000003e-02)*xd[1])+(real_t)(5.0000000000000000e-01)));
+out[1] = (((od[0]-xd[0])-((real_t)(4.0000000000000000e+00)+((((xd[1]*(real_t)(TR))-((od[1]-xd[1])*(real_t)(TR)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))))/(((real_t)(5.0000000000000003e-02)*xd[1])+(real_t)(5.0000000000000000e-01)));
out[2] = (xd[2]*(((real_t)(1.0000000000000001e-01)*xd[1])+(real_t)(1.0000000000000000e+00)));
out[3] = (u[0]*(((real_t)(1.0000000000000001e-01)*xd[1])+(real_t)(1.0000000000000000e+00)));
out[4] = a[4];
out[5] = a[9];
out[6] = (real_t)(0.0000000000000000e+00);
out[7] = (((real_t)(0.0000000000000000e+00)-(real_t)(1.0000000000000000e+00))*a[10]);
-out[8] = ((((real_t)(0.0000000000000000e+00)-(((real_t)(1.8000000000000000e+00)-((real_t)(-1.8000000000000000e+00)))+((xd[1]+xd[1])*a[11])))*a[10])-((((od[0]-xd[0])-((real_t)(4.0000000000000000e+00)+((((xd[1]*(real_t)(1.8000000000000000e+00))-((od[1]-xd[1])*(real_t)(1.8000000000000000e+00)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))))*(real_t)(5.0000000000000003e-02))*a[12]));
+out[8] = ((((real_t)(0.0000000000000000e+00)-(((real_t)(TR)-((real_t)(-TR)))+((xd[1]+xd[1])*a[11])))*a[10])-((((od[0]-xd[0])-((real_t)(4.0000000000000000e+00)+((((xd[1]*(real_t)(TR))-((od[1]-xd[1])*(real_t)(TR)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))))*(real_t)(5.0000000000000003e-02))*a[12]));
out[9] = (real_t)(0.0000000000000000e+00);
out[10] = (real_t)(0.0000000000000000e+00);
out[11] = (xd[2]*(real_t)(1.0000000000000001e-01));
@@ -114,7 +114,7 @@ out[18] = (real_t)(0.0000000000000000e+00);
out[19] = (((real_t)(1.0000000000000001e-01)*xd[1])+(real_t)(1.0000000000000000e+00));
}
-void acado_evaluateLSQEndTerm(const real_t* in, real_t* out)
+void acado_evaluateLSQEndTerm(const real_t* in, real_t* out, double TR)
{
const real_t* xd = in;
const real_t* od = in + 3;
@@ -123,28 +123,28 @@ real_t* a = acadoWorkspace.objAuxVar;
/* Compute intermediate quantities: */
a[0] = (sqrt((xd[1]+(real_t)(5.0000000000000000e-01))));
-a[1] = (exp(((real_t)(2.9999999999999999e-01)*(((((((xd[1]*(real_t)(1.8000000000000000e+00))-((od[1]-xd[1])*(real_t)(1.8000000000000000e+00)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))/(a[0]+(real_t)(1.0000000000000001e-01))))));
+a[1] = (exp(((real_t)(2.9999999999999999e-01)*(((((((xd[1]*(real_t)(TR))-((od[1]-xd[1])*(real_t)(TR)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))/(a[0]+(real_t)(1.0000000000000001e-01))))));
a[2] = ((real_t)(1.0000000000000000e+00)/(a[0]+(real_t)(1.0000000000000001e-01)));
-a[3] = (exp(((real_t)(2.9999999999999999e-01)*(((((((xd[1]*(real_t)(1.8000000000000000e+00))-((od[1]-xd[1])*(real_t)(1.8000000000000000e+00)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))/(a[0]+(real_t)(1.0000000000000001e-01))))));
+a[3] = (exp(((real_t)(2.9999999999999999e-01)*(((((((xd[1]*(real_t)(TR))-((od[1]-xd[1])*(real_t)(TR)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))/(a[0]+(real_t)(1.0000000000000001e-01))))));
a[4] = (((real_t)(2.9999999999999999e-01)*(((real_t)(0.0000000000000000e+00)-((real_t)(0.0000000000000000e+00)-(real_t)(1.0000000000000000e+00)))*a[2]))*a[3]);
a[5] = ((real_t)(1.0000000000000000e+00)/(real_t)(1.9620000000000001e+01));
a[6] = (1.0/sqrt((xd[1]+(real_t)(5.0000000000000000e-01))));
a[7] = (a[6]*(real_t)(5.0000000000000000e-01));
a[8] = (a[2]*a[2]);
-a[9] = (((real_t)(2.9999999999999999e-01)*(((((real_t)(1.8000000000000000e+00)-((real_t)(-1.8000000000000000e+00)))+((xd[1]+xd[1])*a[5]))*a[2])-((((((((xd[1]*(real_t)(1.8000000000000000e+00))-((od[1]-xd[1])*(real_t)(1.8000000000000000e+00)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))*a[7])*a[8])))*a[3]);
+a[9] = (((real_t)(2.9999999999999999e-01)*(((((real_t)(TR)-((real_t)(-TR)))+((xd[1]+xd[1])*a[5]))*a[2])-((((((((xd[1]*(real_t)(TR))-((od[1]-xd[1])*(real_t)(TR)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))+(real_t)(4.0000000000000000e+00))-(od[0]-xd[0]))*a[7])*a[8])))*a[3]);
a[10] = ((real_t)(1.0000000000000000e+00)/(((real_t)(5.0000000000000003e-02)*xd[1])+(real_t)(5.0000000000000000e-01)));
a[11] = ((real_t)(1.0000000000000000e+00)/(real_t)(1.9620000000000001e+01));
a[12] = (a[10]*a[10]);
/* Compute outputs: */
out[0] = (a[1]-(real_t)(1.0000000000000000e+00));
-out[1] = (((od[0]-xd[0])-((real_t)(4.0000000000000000e+00)+((((xd[1]*(real_t)(1.8000000000000000e+00))-((od[1]-xd[1])*(real_t)(1.8000000000000000e+00)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))))/(((real_t)(5.0000000000000003e-02)*xd[1])+(real_t)(5.0000000000000000e-01)));
+out[1] = (((od[0]-xd[0])-((real_t)(4.0000000000000000e+00)+((((xd[1]*(real_t)(TR))-((od[1]-xd[1])*(real_t)(TR)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))))/(((real_t)(5.0000000000000003e-02)*xd[1])+(real_t)(5.0000000000000000e-01)));
out[2] = (xd[2]*(((real_t)(1.0000000000000001e-01)*xd[1])+(real_t)(1.0000000000000000e+00)));
out[3] = a[4];
out[4] = a[9];
out[5] = (real_t)(0.0000000000000000e+00);
out[6] = (((real_t)(0.0000000000000000e+00)-(real_t)(1.0000000000000000e+00))*a[10]);
-out[7] = ((((real_t)(0.0000000000000000e+00)-(((real_t)(1.8000000000000000e+00)-((real_t)(-1.8000000000000000e+00)))+((xd[1]+xd[1])*a[11])))*a[10])-((((od[0]-xd[0])-((real_t)(4.0000000000000000e+00)+((((xd[1]*(real_t)(1.8000000000000000e+00))-((od[1]-xd[1])*(real_t)(1.8000000000000000e+00)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))))*(real_t)(5.0000000000000003e-02))*a[12]));
+out[7] = ((((real_t)(0.0000000000000000e+00)-(((real_t)(TR)-((real_t)(-TR)))+((xd[1]+xd[1])*a[11])))*a[10])-((((od[0]-xd[0])-((real_t)(4.0000000000000000e+00)+((((xd[1]*(real_t)(TR))-((od[1]-xd[1])*(real_t)(TR)))+((xd[1]*xd[1])/(real_t)(1.9620000000000001e+01)))-((od[1]*od[1])/(real_t)(1.9620000000000001e+01)))))*(real_t)(5.0000000000000003e-02))*a[12]));
out[8] = (real_t)(0.0000000000000000e+00);
out[9] = (real_t)(0.0000000000000000e+00);
out[10] = (xd[2]*(real_t)(1.0000000000000001e-01));
@@ -207,7 +207,7 @@ tmpQN1[7] = + tmpQN2[6]*tmpFx[1] + tmpQN2[7]*tmpFx[4] + tmpQN2[8]*tmpFx[7];
tmpQN1[8] = + tmpQN2[6]*tmpFx[2] + tmpQN2[7]*tmpFx[5] + tmpQN2[8]*tmpFx[8];
}
-void acado_evaluateObjective( )
+void acado_evaluateObjective( double TR )
{
int runObj;
for (runObj = 0; runObj < 20; ++runObj)
@@ -219,7 +219,7 @@ acadoWorkspace.objValueIn[3] = acadoVariables.u[runObj];
acadoWorkspace.objValueIn[4] = acadoVariables.od[runObj * 2];
acadoWorkspace.objValueIn[5] = acadoVariables.od[runObj * 2 + 1];
-acado_evaluateLSQ( acadoWorkspace.objValueIn, acadoWorkspace.objValueOut );
+acado_evaluateLSQ( acadoWorkspace.objValueIn, acadoWorkspace.objValueOut, TR );
acadoWorkspace.Dy[runObj * 4] = acadoWorkspace.objValueOut[0];
acadoWorkspace.Dy[runObj * 4 + 1] = acadoWorkspace.objValueOut[1];
acadoWorkspace.Dy[runObj * 4 + 2] = acadoWorkspace.objValueOut[2];
@@ -235,7 +235,7 @@ acadoWorkspace.objValueIn[1] = acadoVariables.x[61];
acadoWorkspace.objValueIn[2] = acadoVariables.x[62];
acadoWorkspace.objValueIn[3] = acadoVariables.od[40];
acadoWorkspace.objValueIn[4] = acadoVariables.od[41];
-acado_evaluateLSQEndTerm( acadoWorkspace.objValueIn, acadoWorkspace.objValueOut );
+acado_evaluateLSQEndTerm( acadoWorkspace.objValueIn, acadoWorkspace.objValueOut, TR );
acadoWorkspace.DyN[0] = acadoWorkspace.objValueOut[0];
acadoWorkspace.DyN[1] = acadoWorkspace.objValueOut[1];
@@ -4589,12 +4589,12 @@ acado_multEDu( &(acadoWorkspace.E[ 624 ]), &(acadoWorkspace.x[ 21 ]), &(acadoVar
acado_multEDu( &(acadoWorkspace.E[ 627 ]), &(acadoWorkspace.x[ 22 ]), &(acadoVariables.x[ 60 ]) );
}
-int acado_preparationStep( )
+int acado_preparationStep( double TR )
{
int ret;
ret = acado_modelSimulation();
-acado_evaluateObjective( );
+acado_evaluateObjective( TR );
acado_condensePrep( );
return ret;
}
@@ -4726,7 +4726,7 @@ kkt += fabs(acadoWorkspace.ubA[index] * prd);
return kkt;
}
-real_t acado_getObjective( )
+real_t acado_getObjective( TR )
{
real_t objVal;
@@ -4746,7 +4746,7 @@ acadoWorkspace.objValueIn[3] = acadoVariables.u[lRun1];
acadoWorkspace.objValueIn[4] = acadoVariables.od[lRun1 * 2];
acadoWorkspace.objValueIn[5] = acadoVariables.od[lRun1 * 2 + 1];
-acado_evaluateLSQ( acadoWorkspace.objValueIn, acadoWorkspace.objValueOut );
+acado_evaluateLSQ( acadoWorkspace.objValueIn, acadoWorkspace.objValueOut, TR );
acadoWorkspace.Dy[lRun1 * 4] = acadoWorkspace.objValueOut[0] - acadoVariables.y[lRun1 * 4];
acadoWorkspace.Dy[lRun1 * 4 + 1] = acadoWorkspace.objValueOut[1] - acadoVariables.y[lRun1 * 4 + 1];
acadoWorkspace.Dy[lRun1 * 4 + 2] = acadoWorkspace.objValueOut[2] - acadoVariables.y[lRun1 * 4 + 2];
@@ -4757,7 +4757,7 @@ acadoWorkspace.objValueIn[1] = acadoVariables.x[61];
acadoWorkspace.objValueIn[2] = acadoVariables.x[62];
acadoWorkspace.objValueIn[3] = acadoVariables.od[40];
acadoWorkspace.objValueIn[4] = acadoVariables.od[41];
-acado_evaluateLSQEndTerm( acadoWorkspace.objValueIn, acadoWorkspace.objValueOut );
+acado_evaluateLSQEndTerm( acadoWorkspace.objValueIn, acadoWorkspace.objValueOut, TR );
acadoWorkspace.DyN[0] = acadoWorkspace.objValueOut[0] - acadoVariables.yN[0];
acadoWorkspace.DyN[1] = acadoWorkspace.objValueOut[1] - acadoVariables.yN[1];
acadoWorkspace.DyN[2] = acadoWorkspace.objValueOut[2] - acadoVariables.yN[2];
diff --git a/selfdrive/controls/lib/longitudinal_mpc/libmpc_py.py b/selfdrive/controls/lib/longitudinal_mpc/libmpc_py.py
index c40b4e071..fd8947ff0 100644
--- a/selfdrive/controls/lib/longitudinal_mpc/libmpc_py.py
+++ b/selfdrive/controls/lib/longitudinal_mpc/libmpc_py.py
@@ -29,8 +29,9 @@ def _get_libmpc(mpc_id):
void init(double ttcCost, double distanceCost, double accelerationCost, double jerkCost);
void init_with_simulation(double v_ego, double x_l, double v_l, double a_l, double l);
+ void change_tr(double ttcCost, double distanceCost, double accelerationCost, double jerkCost);
int run_mpc(state_t * x0, log_t * solution,
- double l, double a_l_0);
+ double l, double a_l_0, double TR);
""")
return (ffi, ffi.dlopen(libmpc_fn))
diff --git a/selfdrive/controls/lib/longitudinal_mpc/longitudinal_mpc.c b/selfdrive/controls/lib/longitudinal_mpc/longitudinal_mpc.c
index d4bfee8c8..02d8693e4 100644
--- a/selfdrive/controls/lib/longitudinal_mpc/longitudinal_mpc.c
+++ b/selfdrive/controls/lib/longitudinal_mpc/longitudinal_mpc.c
@@ -68,6 +68,25 @@ void init(double ttcCost, double distanceCost, double accelerationCost, double j
}
+void change_tr(double ttcCost, double distanceCost, double accelerationCost, double jerkCost){
+ int i;
+ const int STEP_MULTIPLIER = 3;
+
+ for (i = 0; i < N; i++) {
+ int f = 1;
+ if (i > 4){
+ f = STEP_MULTIPLIER;
+ }
+ acadoVariables.W[16 * i + 0] = ttcCost * f; // exponential cost for time-to-collision (ttc)
+ acadoVariables.W[16 * i + 5] = distanceCost * f; // desired distance
+ acadoVariables.W[16 * i + 10] = accelerationCost * f; // acceleration
+ acadoVariables.W[16 * i + 15] = jerkCost * f; // jerk
+ }
+ acadoVariables.WN[0] = ttcCost * STEP_MULTIPLIER; // exponential cost for danger zone
+ acadoVariables.WN[4] = distanceCost * STEP_MULTIPLIER; // desired distance
+ acadoVariables.WN[8] = accelerationCost * STEP_MULTIPLIER; // acceleration
+}
+
void init_with_simulation(double v_ego, double x_l_0, double v_l_0, double a_l_0, double l){
int i;
@@ -112,7 +131,7 @@ void init_with_simulation(double v_ego, double x_l_0, double v_l_0, double a_l_0
for (i = 0; i < NYN; ++i) acadoVariables.yN[ i ] = 0.0;
}
-int run_mpc(state_t * x0, log_t * solution, double l, double a_l_0){
+int run_mpc(state_t * x0, log_t * solution, double l, double a_l_0, double TR){
// Calculate lead vehicle predictions
int i;
double t = 0.;
@@ -152,7 +171,7 @@ int run_mpc(state_t * x0, log_t * solution, double l, double a_l_0){
acadoVariables.x[1] = acadoVariables.x0[1] = x0->v_ego;
acadoVariables.x[2] = acadoVariables.x0[2] = x0->a_ego;
- acado_preparationStep();
+ acado_preparationStep(TR);
acado_feedbackStep();
for (i = 0; i <= N; i++){
@@ -164,7 +183,7 @@ int run_mpc(state_t * x0, log_t * solution, double l, double a_l_0){
solution->j_ego[i] = acadoVariables.u[i];
}
}
- solution->cost = acado_getObjective();
+ solution->cost = acado_getObjective(TR);
// Dont shift states here. Current solution is closer to next timestep than if
// we shift by 0.2 seconds.
diff --git a/selfdrive/controls/lib/pathplanner.py b/selfdrive/controls/lib/pathplanner.py
index 413d71d3a..bae87207c 100644
--- a/selfdrive/controls/lib/pathplanner.py
+++ b/selfdrive/controls/lib/pathplanner.py
@@ -6,9 +6,12 @@ from selfdrive.controls.lib.lateral_mpc import libmpc_py
from selfdrive.controls.lib.drive_helpers import MPC_COST_LAT
from selfdrive.controls.lib.lane_planner import LanePlanner
from selfdrive.config import Conversions as CV
-from common.params import Params
+from common.params import Params, put_nonblocking
import cereal.messaging as messaging
from cereal import log
+# dragonpilot
+from common.dp import get_last_modified
+from common.numpy_fast import interp
LaneChangeState = log.PathPlan.LaneChangeState
LaneChangeDirection = log.PathPlan.LaneChangeDirection
@@ -62,6 +65,22 @@ class PathPlanner():
self.lane_change_ll_prob = 1.0
self.prev_one_blinker = False
+ # dragonpilot
+ self.params = Params()
+ self.dragon_auto_lc_enabled = False
+ self.dragon_auto_lc_allowed = False
+ self.dragon_auto_lc_timer = None
+ self.dragon_assisted_lc_min_mph = LANE_CHANGE_SPEED_MIN
+ self.dragon_auto_lc_min_mph = 60 * CV.MPH_TO_MS
+ self.dragon_auto_lc_delay = 2.
+ self.last_ts = 0.
+ self.dp_last_modified = None
+ self.dp_enable_sr_boost = False
+
+ self.dp_steer_ratio = 0.
+ self.dp_sr_boost_bp = None
+ self.dp_sr_boost_range = None
+
def setup_mpc(self):
self.libmpc = libmpc_py.libmpc
self.libmpc.init(MPC_COST_LAT.PATH, MPC_COST_LAT.LANE, MPC_COST_LAT.HEADING, self.steer_rate_cost)
@@ -79,6 +98,64 @@ class PathPlanner():
self.angle_steers_des_time = 0.0
def update(self, sm, pm, CP, VM):
+ # dragonpilot
+ cur_time = sec_since_boot()
+ if cur_time - self.last_ts >= 5.:
+ modified = get_last_modified()
+ if self.dp_last_modified != modified:
+ self.lane_change_enabled = True if self.params.get("LaneChangeEnabled", encoding='utf8') == "1" else False
+ if self.lane_change_enabled:
+ self.dragon_auto_lc_enabled = True if self.params.get("DragonEnableAutoLC", encoding='utf8') == "1" else False
+ # adjustable assisted lc min speed
+ try:
+ self.dragon_assisted_lc_min_mph = float(self.params.get("DragonAssistedLCMinMPH", encoding='utf8'))
+ except (TypeError, ValueError):
+ self.dragon_assisted_lc_min_mph = 45
+ self.dragon_assisted_lc_min_mph *= CV.MPH_TO_MS
+ if self.dragon_assisted_lc_min_mph < 0:
+ self.dragon_assisted_lc_min_mph = 0
+ if self.dragon_auto_lc_enabled:
+ # adjustable auto lc min speed
+ try:
+ self.dragon_auto_lc_min_mph = float(self.params.get("DragonAutoLCMinMPH", encoding='utf8'))
+ except (TypeError, ValueError):
+ self.dragon_auto_lc_min_mph = 60
+ self.dragon_auto_lc_min_mph *= CV.MPH_TO_MS
+ if self.dragon_auto_lc_min_mph < 0:
+ self.dragon_auto_lc_min_mph = 0
+ # when auto lc is smaller than assisted lc, we set assisted lc to the same speed as auto lc
+ if self.dragon_auto_lc_min_mph < self.dragon_assisted_lc_min_mph:
+ self.dragon_assisted_lc_min_mph = self.dragon_auto_lc_min_mph
+ # adjustable auto lc delay
+ try:
+ self.dragon_auto_lc_delay = float(self.params.get("DragonAutoLCDelay", encoding='utf8'))
+ except (TypeError, ValueError):
+ self.dragon_auto_lc_delay = 2.
+ if self.dragon_auto_lc_delay < 0:
+ self.dragon_auto_lc_delay = 0
+ else:
+ self.dragon_auto_lc_enabled = False
+
+ self.dp_enable_sr_boost = True if self.params.get("DragonEnableSteerBoost", encoding='utf8') == "1" else False
+ if self.dp_enable_sr_boost:
+ try:
+ sr_boost_min = float(self.params.get("DragonSteerBoostMin", encoding='utf8'))
+ sr_boost_Max = float(self.params.get("DragonSteerBoostMax", encoding='utf8'))
+ self.dp_sr_boost_range = [sr_boost_min, sr_boost_Max]
+
+ boost_min_at = float(self.params.get("DragonSteerBoostMinAt", encoding='utf8'))
+ boost_max_at = float(self.params.get("DragonSteerBoostMaxAt", encoding='utf8'))
+ self.dp_sr_boost_bp = [boost_min_at, boost_max_at]
+ except (TypeError, ValueError):
+ put_nonblocking("DragonEnableSteerBoost", '0')
+ self.dp_enable_sr_boost = False
+ if not self.dp_enable_sr_boost:
+ self.dp_sr_boost_range = [0., 0.]
+ self.dp_sr_boost_bp = [0., 0.]
+
+ self.dp_last_modified = modified
+ self.last_ts = cur_time
+
v_ego = sm['carState'].vEgo
angle_steers = sm['carState'].steeringAngle
active = sm['controlsState'].active
@@ -89,12 +166,14 @@ class PathPlanner():
self.angle_steers_des_prev = self.angle_steers_des_mpc
VM.update_params(sm['liveParameters'].stiffnessFactor, sm['liveParameters'].steerRatio)
curvature_factor = VM.curvature_factor(v_ego)
+ boost_rate = (1 + (interp(abs(angle_steers), self.dp_sr_boost_bp, self.dp_sr_boost_range) / 100)) if self.dp_enable_sr_boost else 1
+ self.dp_steer_ratio = VM.sR * boost_rate
self.LP.parse_model(sm['model'])
# Lane change logic
one_blinker = sm['carState'].leftBlinker != sm['carState'].rightBlinker
- below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN
+ below_lane_change_speed = v_ego < self.dragon_assisted_lc_min_mph
if sm['carState'].leftBlinker:
self.lane_change_direction = LaneChangeDirection.left
@@ -111,6 +190,27 @@ class PathPlanner():
lane_change_prob = self.LP.l_lane_change_prob + self.LP.r_lane_change_prob
+ # dragonpilot auto lc
+ if not below_lane_change_speed and self.dragon_auto_lc_enabled and v_ego >= self.dragon_auto_lc_min_mph:
+ # we allow auto lc when speed reached dragon_auto_lc_min_mph
+ self.dragon_auto_lc_allowed = True
+
+ if self.dragon_auto_lc_timer is None:
+ # we only set timer when in preLaneChange state, dragon_auto_lc_delay delay
+ if self.lane_change_state == LaneChangeState.preLaneChange:
+ self.dragon_auto_lc_timer = cur_time + self.dragon_auto_lc_delay
+ elif cur_time >= self.dragon_auto_lc_timer:
+ # if timer is up, we set torque_applied to True to fake user input
+ torque_applied = True
+ else:
+ # if too slow, we reset all the variables
+ self.dragon_auto_lc_allowed = False
+ self.dragon_auto_lc_timer = None
+
+ # we reset the timers when torque is applied regardless
+ if torque_applied:
+ self.dragon_auto_lc_timer = None
+
# State transitions
# off
if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed:
@@ -141,6 +241,9 @@ class PathPlanner():
elif self.lane_change_ll_prob > 0.99:
self.lane_change_state = LaneChangeState.off
+ # when finishing, we reset timer to none.
+ self.dragon_auto_lc_timer = None
+
if self.lane_change_state in [LaneChangeState.off, LaneChangeState.preLaneChange]:
self.lane_change_timer = 0.0
else:
@@ -157,7 +260,7 @@ class PathPlanner():
self.LP.update_d_poly(v_ego)
# account for actuation delay
- self.cur_state = calc_states_after_delay(self.cur_state, v_ego, angle_steers - angle_offset, curvature_factor, VM.sR, CP.steerActuatorDelay)
+ self.cur_state = calc_states_after_delay(self.cur_state, v_ego, angle_steers - angle_offset, curvature_factor, self.dp_steer_ratio, CP.steerActuatorDelay)
v_ego_mpc = max(v_ego, 5.0) # avoid mpc roughness due to low speed
self.libmpc.run_mpc(self.cur_state, self.mpc_solution,
@@ -167,21 +270,21 @@ class PathPlanner():
# reset to current steer angle if not active or overriding
if active:
delta_desired = self.mpc_solution[0].delta[1]
- rate_desired = math.degrees(self.mpc_solution[0].rate[0] * VM.sR)
+ rate_desired = math.degrees(self.mpc_solution[0].rate[0] * self.dp_steer_ratio)
else:
- delta_desired = math.radians(angle_steers - angle_offset) / VM.sR
+ delta_desired = math.radians(angle_steers - angle_offset) / self.dp_steer_ratio
rate_desired = 0.0
self.cur_state[0].delta = delta_desired
- self.angle_steers_des_mpc = float(math.degrees(delta_desired * VM.sR) + angle_offset)
+ self.angle_steers_des_mpc = float(math.degrees(delta_desired * self.dp_steer_ratio) + angle_offset)
# Check for infeasable MPC solution
mpc_nans = any(math.isnan(x) for x in self.mpc_solution[0].delta)
t = sec_since_boot()
if mpc_nans:
self.libmpc.init(MPC_COST_LAT.PATH, MPC_COST_LAT.LANE, MPC_COST_LAT.HEADING, CP.steerRateCost)
- self.cur_state[0].delta = math.radians(angle_steers - angle_offset) / VM.sR
+ self.cur_state[0].delta = math.radians(angle_steers - angle_offset) / self.dp_steer_ratio
if t > self.last_cloudlog_t + 5.0:
self.last_cloudlog_t = t
@@ -213,6 +316,7 @@ class PathPlanner():
plan_send.pathPlan.desire = desire
plan_send.pathPlan.laneChangeState = self.lane_change_state
plan_send.pathPlan.laneChangeDirection = self.lane_change_direction
+ plan_send.pathPlan.alcAllowed = self.dragon_auto_lc_allowed
pm.send('pathPlan', plan_send)
diff --git a/selfdrive/controls/lib/planner.py b/selfdrive/controls/lib/planner.py
index 7e6a126e4..141fe3aa7 100755
--- a/selfdrive/controls/lib/planner.py
+++ b/selfdrive/controls/lib/planner.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
import math
import numpy as np
-from common.params import Params
+from common.params import Params, put_nonblocking
from common.numpy_fast import interp
import cereal.messaging as messaging
@@ -13,6 +13,7 @@ from selfdrive.controls.lib.speed_smoother import speed_smoother
from selfdrive.controls.lib.longcontrol import LongCtrlState, MIN_CAN_SPEED
from selfdrive.controls.lib.fcw import FCWChecker
from selfdrive.controls.lib.long_mpc import LongitudinalMpc
+from common.dp import get_last_modified
MAX_SPEED = 255.0
@@ -39,23 +40,64 @@ _A_TOTAL_MAX_BP = [20., 40.]
SPEED_PERCENTILE_IDX = 7
-def calc_cruise_accel_limits(v_ego, following):
- a_cruise_min = interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
+# dp
+# accel profile by @arne182
+_AP_CRUISE_MIN_V = [-2.0, -1.5, -1.0, -0.7, -0.5]
+_AP_CRUISE_MIN_V_ECO = [-1.0, -0.7, -0.6, -0.5, -0.3]
+_AP_CRUISE_MIN_V_SPORT = [-3.0, -2.6, -2.3, -2.0, -1.0]
+_AP_CRUISE_MIN_V_FOLLOWING = [-4.0, -4.0, -3.5, -2.5, -2.0]
+_AP_CRUISE_MIN_BP = [0.0, 5.0, 10.0, 20.0, 55.0]
- if following:
- a_cruise_max = interp(v_ego, _A_CRUISE_MAX_BP, _A_CRUISE_MAX_V_FOLLOWING)
+_AP_CRUISE_MAX_V = [2.0, 2.0, 1.5, .5, .3]
+_AP_CRUISE_MAX_V_ECO = [0.8, 0.9, 1.0, 0.4, 0.2]
+_AP_CRUISE_MAX_V_SPORT = [3.0, 3.5, 3.0, 2.0, 2.0]
+_AP_CRUISE_MAX_V_FOLLOWING = [1.6, 1.4, 1.4, .7, .3]
+_AP_CRUISE_MAX_BP = [0., 5., 10., 20., 55.]
+
+# Lookup table for turns
+_AP_TOTAL_MAX_V = [3.3, 3.0, 3.9]
+_AP_TOTAL_MAX_BP = [0., 25., 55.]
+
+AP_OFF = 0
+AP_ECO = 1
+AP_NORMAL = 2
+AP_SPORT = 3
+
+
+def calc_cruise_accel_limits(v_ego, following, accel_profile):
+ if accel_profile == AP_OFF:
+ a_cruise_min = interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
+
+ if following:
+ a_cruise_max = interp(v_ego, _A_CRUISE_MAX_BP, _A_CRUISE_MAX_V_FOLLOWING)
+ else:
+ a_cruise_max = interp(v_ego, _A_CRUISE_MAX_BP, _A_CRUISE_MAX_V)
else:
- a_cruise_max = interp(v_ego, _A_CRUISE_MAX_BP, _A_CRUISE_MAX_V)
+ if following:
+ a_cruise_min = interp(v_ego, _AP_CRUISE_MIN_BP, _AP_CRUISE_MIN_V_FOLLOWING)
+ a_cruise_max = interp(v_ego, _AP_CRUISE_MAX_BP, _AP_CRUISE_MAX_V_FOLLOWING)
+ else:
+ if accel_profile == AP_ECO:
+ a_cruise_min = interp(v_ego, _AP_CRUISE_MIN_BP, _AP_CRUISE_MIN_V_ECO)
+ a_cruise_max = interp(v_ego, _AP_CRUISE_MAX_BP, _AP_CRUISE_MAX_V_ECO)
+ elif accel_profile == AP_SPORT:
+ a_cruise_min = interp(v_ego, _AP_CRUISE_MIN_BP, _AP_CRUISE_MIN_V_SPORT)
+ a_cruise_max = interp(v_ego, _AP_CRUISE_MAX_BP, _AP_CRUISE_MAX_V_SPORT)
+ else:
+ a_cruise_min = interp(v_ego, _AP_CRUISE_MIN_BP, _AP_CRUISE_MIN_V)
+ a_cruise_max = interp(v_ego, _AP_CRUISE_MAX_BP, _AP_CRUISE_MAX_V)
return np.vstack([a_cruise_min, a_cruise_max])
-def limit_accel_in_turns(v_ego, angle_steers, a_target, CP):
+def limit_accel_in_turns(v_ego, angle_steers, a_target, CP, accel_profile):
"""
This function returns a limited long acceleration allowed, depending on the existing lateral acceleration
this should avoid accelerating when losing the target in turns
"""
-
- a_total_max = interp(v_ego, _A_TOTAL_MAX_BP, _A_TOTAL_MAX_V)
+ if accel_profile == AP_OFF:
+ a_total_max = interp(v_ego, _A_TOTAL_MAX_BP, _A_TOTAL_MAX_V)
+ else:
+ a_total_max = interp(v_ego, _AP_TOTAL_MAX_BP, _AP_TOTAL_MAX_V)
a_y = v_ego**2 * angle_steers * CV.DEG_TO_RAD / (CP.steerRatio * CP.wheelbase)
a_x_allowed = math.sqrt(max(a_total_max**2 - a_y**2, 0.))
@@ -87,6 +129,14 @@ class Planner():
self.params = Params()
self.first_loop = True
+ # dp
+ self.dragon_slow_on_curve = True
+ self.dragon_alt_accel_profile = False
+ self.dragon_fast_accel = False
+ self.dragon_accel_profile = AP_OFF
+ self.last_ts = 0.
+ self.dp_last_modified = None
+
def choose_solution(self, v_cruise_setpoint, enabled):
if enabled:
solutions = {'model': self.v_model, 'cruise': self.v_cruise}
@@ -119,6 +169,20 @@ class Planner():
cur_time = sec_since_boot()
v_ego = sm['carState'].vEgo
+ # dp
+ # update variable status every 5 secs
+ if cur_time - self.last_ts >= 5.:
+ modified = get_last_modified()
+ if self.dp_last_modified != modified:
+ self.dragon_slow_on_curve = False if self.params.get("DragonEnableSlowOnCurve", encoding='utf8') == "0" else True
+ try:
+ self.dragon_accel_profile = int(self.params.get("DragonAccelProfile", encoding='utf8').rstrip('\x00'))
+ except (TypeError, ValueError):
+ self.dragon_accel_profile = AP_OFF
+ put_nonblocking('DragonAccelProfile', AP_OFF)
+ self.dp_last_modified = modified
+ self.last_ts = cur_time
+
long_control_state = sm['controlsState'].longControlState
v_cruise_kph = sm['controlsState'].vCruise
force_slow_decel = sm['controlsState'].forceDecel
@@ -130,7 +194,7 @@ class Planner():
enabled = (long_control_state == LongCtrlState.pid) or (long_control_state == LongCtrlState.stopping)
following = lead_1.status and lead_1.dRel < 45.0 and lead_1.vLeadK > v_ego and lead_1.aLeadK > 0.0
- if len(sm['model'].path.poly):
+ if self.dragon_slow_on_curve and len(sm['model'].path.poly):
path = list(sm['model'].path.poly)
# Curvature of polynomial https://en.wikipedia.org/wiki/Curvature#Curvature_of_the_graph_of_a_function
@@ -150,9 +214,9 @@ class Planner():
# Calculate speed for normal cruise control
if enabled and not self.first_loop:
- accel_limits = [float(x) for x in calc_cruise_accel_limits(v_ego, following)]
+ accel_limits = [float(x) for x in calc_cruise_accel_limits(v_ego, following, self.dragon_accel_profile)]
jerk_limits = [min(-0.1, accel_limits[0]), max(0.1, accel_limits[1])] # TODO: make a separate lookup for jerk tuning
- accel_limits_turns = limit_accel_in_turns(v_ego, sm['carState'].steeringAngle, accel_limits, self.CP)
+ accel_limits_turns = limit_accel_in_turns(v_ego, sm['carState'].steeringAngle, accel_limits, self.CP, self.dragon_accel_profile)
if force_slow_decel:
# if required so, force a smooth deceleration
diff --git a/selfdrive/crash.py b/selfdrive/crash.py
index a8cb758a7..f896a244f 100644
--- a/selfdrive/crash.py
+++ b/selfdrive/crash.py
@@ -3,7 +3,9 @@ import os
import sys
import threading
import capnp
-from selfdrive.version import version, dirty
+from common.params import Params
+from selfdrive.version import version, dirty, origin, branch
+uniqueID = Params().get('DongleId', None)
from selfdrive.swaglog import cloudlog
from common.android import ANDROID
@@ -20,8 +22,15 @@ if os.getenv("NOLOG") or os.getenv("NOCRASH") or not ANDROID:
else:
from raven import Client
from raven.transport.http import HTTPTransport
- client = Client('https://1994756b5e6f41cf939a4c65de45f4f2:cefebaf3a8aa40d182609785f7189bd7@app.getsentry.com/77924',
- install_sys_hook=False, transport=HTTPTransport, release=version, tags={'dirty': dirty})
+ params = Params()
+ try:
+ dongle_id = params.get("DongleId").decode('utf8')
+ except AttributeError:
+ dongle_id = "None"
+ error_tags = {'dirty': dirty, 'username': uniqueID, 'dongle_id': dongle_id, 'branch': branch, 'remote': origin}
+
+ client = Client('https://980a0cba712a4c3593c33c78a12446e1:fecab286bcaf4dba8b04f7cff0188e2d@sentry.io/1488600',
+ install_sys_hook=False, transport=HTTPTransport, release=version, tags=error_tags)
def capture_exception(*args, **kwargs):
exc_info = sys.exc_info()
@@ -32,6 +41,14 @@ else:
def bind_user(**kwargs):
client.user_context(kwargs)
+ def capture_warning(warning_string):
+ bind_user(id=dongle_id)
+ client.captureMessage(warning_string, level='warning')
+
+ def capture_info(info_string):
+ bind_user(id=dongle_id)
+ client.captureMessage(info_string, level='info')
+
def bind_extra(**kwargs):
client.extra_context(kwargs)
diff --git a/selfdrive/dragonpilot/LICENSE.md b/selfdrive/dragonpilot/LICENSE.md
new file mode 100644
index 000000000..76e9bfcbb
--- /dev/null
+++ b/selfdrive/dragonpilot/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2019-, Rick Lan, dragonpilot community, and a number of other of contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/selfdrive/dragonpilot/appd/appd.py b/selfdrive/dragonpilot/appd/appd.py
new file mode 100644
index 000000000..862f05dd5
--- /dev/null
+++ b/selfdrive/dragonpilot/appd/appd.py
@@ -0,0 +1,453 @@
+#!/usr/bin/env python3.7
+import time
+import subprocess
+import cereal
+import cereal.messaging as messaging
+ThermalStatus = cereal.log.ThermalData.ThermalStatus
+from selfdrive.swaglog import cloudlog
+from common.realtime import sec_since_boot
+from common.params import Params, put_nonblocking
+params = Params()
+from common.dp import get_last_modified
+from math import floor
+import re
+import os
+from common.dp import is_online
+
+is_online = is_online()
+is_gitee_src = "gitee" in subprocess.check_output(["git", "-C", "/data/openpilot", "config", "--get", "remote.origin.url"]).decode('utf8').rstrip()
+auto_update = params.get("DragonAppAutoUpdate", encoding='utf8') == "1"
+
+class App():
+
+ # app type
+ TYPE_GPS = 0
+ TYPE_SERVICE = 1
+ TYPE_GPS_SERVICE = 2
+ TYPE_FULLSCREEN = 3
+ TYPE_UTIL = 4
+
+ # manual switch stats
+ MANUAL_OFF = "-1"
+ MANUAL_IDLE = "0"
+ MANUAL_ON = "1"
+
+ def appops_set(self, package, op, mode):
+ self.system(f"LD_LIBRARY_PATH= appops set {package} {op} {mode}")
+
+ def pm_grant(self, package, permission):
+ self.system(f"pm grant {package} {permission}")
+
+ def set_package_permissions(self):
+ if self.permissions is not None:
+ for permission in self.permissions:
+ self.pm_grant(self.app, permission)
+ if self.opts is not None:
+ for opt in self.opts:
+ self.appops_set(self.app, opt, "allow")
+
+ def __init__(self, app, activity, enable_param, auto_run_param, manual_ctrl_param, app_type, permissions, opts):
+ self.app = app
+ # main activity
+ self.activity = activity
+ # read enable param
+ self.enable_param = enable_param
+ # read auto run param
+ self.auto_run_param = auto_run_param
+ # read manual run param
+ self.manual_ctrl_param = manual_ctrl_param
+ # if it's a service app, we do not kill if device is too hot
+ self.app_type = app_type
+ # app permissions
+ self.permissions = permissions
+ # app options
+ self.opts = opts
+
+ self.is_installed = False
+ self.is_enabled = True if params.get(self.enable_param, encoding='utf8') == "1" else False
+ self.last_is_enabled = False
+ self.is_auto_runnable = False
+ self.is_running = False
+ self.manual_ctrl_status = self.MANUAL_IDLE
+ self.manually_ctrled = False
+
+ if self.is_enabled:
+ local_version = self.get_local_version()
+ if local_version is not None:
+ self.is_installed = True
+
+ if is_online:
+ remote_version = local_version
+ if local_version is not None and auto_update:
+ remote_version = self.get_remote_version()
+ if local_version is None or (remote_version is not None and local_version != remote_version):
+ self.update_app()
+ if self.is_installed:
+ self.set_package_permissions()
+ else:
+ self.uninstall_app()
+
+ if self.manual_ctrl_param is not None:
+ put_nonblocking(self.manual_ctrl_param, '0')
+ self.last_ts = sec_since_boot()
+
+ def get_remote_version(self):
+ apk = self.app + ".apk"
+ try:
+ if is_gitee_src:
+ url = "https://gitee.com/dragonpilot/apps/raw/%s/VERSION" % apk
+ else:
+ url = "https://raw.githubusercontent.com/dragonpilot-community/apps/%s/VERSION" % apk
+ return subprocess.check_output(["curl", "-H", "'Cache-Control: no-cache'", "-s", url], stderr=subprocess.STDOUT, shell=True).decode('utf8').rstrip()
+ except subprocess.CalledProcessError as e:
+ pass
+ return None
+
+ def uninstall_app(self):
+ try:
+ local_version = self.get_local_version()
+ if local_version is not None:
+ subprocess.check_output(["pm","uninstall", self.app])
+ self.is_installed = False
+ except subprocess.CalledProcessError as e:
+ pass
+
+ def update_app(self):
+ apk = self.app + ".apk"
+ apk_path = "/sdcard/" + apk
+ try:
+ os.remove(apk_path)
+ except (OSError, FileNotFoundError) as e:
+ pass
+
+ self.uninstall_app()
+ # if local_version is not None:
+ # try:
+ # subprocess.check_output(["pm","uninstall", self.app], stderr=subprocess.STDOUT, shell=True)
+ # except subprocess.CalledProcessError as e:
+ # pass
+ try:
+ put_nonblocking('DragonUpdating', '1')
+ url = "https://raw.githubusercontent.com/dragonpilot-community/apps/%s/%s" % (apk, apk)
+ subprocess.check_output(["curl","-o", apk_path,"-LJO", url])
+ subprocess.check_output(["pm","install","-r",apk_path])
+ self.is_installed = True
+ except subprocess.CalledProcessError as e:
+ self.is_installed = False
+ put_nonblocking('DragonUpdating', '0')
+ try:
+ os.remove(apk_path)
+ except (OSError, FileNotFoundError) as e:
+ pass
+
+ def get_local_version(self):
+ try:
+ result = subprocess.check_output(["dumpsys", "package", self.app, "|", "grep", "versionName"], encoding='utf8')
+ if len(result) > 12:
+ return re.findall(r"versionName=(.*)", result)[0]
+ except (subprocess.CalledProcessError, IndexError) as e:
+ pass
+ return None
+
+
+ def read_params(self):
+ self.last_is_enabled = self.is_enabled
+ if self.enable_param is None:
+ self.is_enabled = False
+ else:
+ self.is_enabled = True if params.get(self.enable_param, encoding='utf8') == "1" else False
+
+ if self.is_installed:
+ if self.is_enabled:
+ # a service app should run automatically and not manual controllable.
+ if self.app_type in [App.TYPE_SERVICE, App.TYPE_GPS_SERVICE]:
+ self.is_auto_runnable = True
+ self.manual_ctrl_status = self.MANUAL_IDLE
+ else:
+ if self.manual_ctrl_param is None:
+ self.manual_ctrl_status = self.MANUAL_IDLE
+ else:
+ self.manual_ctrl_status = params.get(self.manual_ctrl_param, encoding='utf8')
+
+ if self.manual_ctrl_status == self.MANUAL_IDLE:
+ if self.auto_run_param is None:
+ self.is_auto_runnable = False
+ else:
+ self.is_auto_runnable = True if params.get(self.auto_run_param, encoding='utf8') == "1" else False
+ else:
+ if self.last_is_enabled:
+ self.uninstall_app()
+ self.is_auto_runnable = False
+ self.manual_ctrl_status = self.MANUAL_IDLE
+ self.manually_ctrled = False
+ else:
+ if not self.last_is_enabled and self.is_enabled:
+ self.update_app()
+
+ def run(self, force = False):
+ if self.is_installed and (force or self.is_enabled):
+ # app is manually ctrl, we record that
+ if self.manual_ctrl_param is not None and self.manual_ctrl_status == self.MANUAL_ON:
+ put_nonblocking(self.manual_ctrl_param, '0')
+ put_nonblocking('DragonLastModified', str(floor(time.time())))
+ self.manually_ctrled = True
+ self.is_running = False
+
+ # only run app if it's not running
+ if force or not self.is_running:
+ self.system("pm enable %s" % self.app)
+
+ if self.app_type == self.TYPE_GPS_SERVICE:
+ self.appops_set(self.app, "android:mock_location", "allow")
+
+ if self.app_type in [self.TYPE_SERVICE, self.TYPE_GPS_SERVICE]:
+ self.system("am startservice %s/%s" % (self.app, self.activity))
+ else:
+ self.system("am start -n %s/%s" % (self.app, self.activity))
+ self.is_running = True
+
+ def kill(self, force = False):
+ if self.is_installed and (force or self.is_enabled):
+ # app is manually ctrl, we record that
+ if self.manual_ctrl_param is not None and self.manual_ctrl_status == self.MANUAL_OFF:
+ put_nonblocking(self.manual_ctrl_param, '0')
+ self.manually_ctrled = True
+ self.is_running = True
+
+ # only kill app if it's running
+ if force or self.is_running:
+ if self.app_type == self.TYPE_GPS_SERVICE:
+ self.appops_set(self.app, "android:mock_location", "deny")
+
+ self.system("pkill %s" % self.app)
+ self.is_running = False
+
+ def system(self, cmd):
+ try:
+ subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
+ except subprocess.CalledProcessError as e:
+ cloudlog.event("running failed",
+ cmd=e.cmd,
+ output=e.output[-1024:],
+ returncode=e.returncode)
+
+def init_apps(apps):
+ apps.append(App(
+ "cn.dragonpilot.gpsservice",
+ "cn.dragonpilot.gpsservice.MainService",
+ "DragonGreyPandaMode",
+ None,
+ None,
+ App.TYPE_GPS_SERVICE,
+ [],
+ [],
+ ))
+ apps.append(App(
+ "com.mixplorer",
+ "com.mixplorer.activities.BrowseActivity",
+ "DragonEnableMixplorer",
+ None,
+ "DragonRunMixplorer",
+ App.TYPE_UTIL,
+ [
+ "android.permission.READ_EXTERNAL_STORAGE",
+ "android.permission.WRITE_EXTERNAL_STORAGE",
+ ],
+ [],
+ ))
+ apps.append(App(
+ "com.tomtom.speedcams.android.map",
+ "com.tomtom.speedcams.android.activities.SpeedCamActivity",
+ "DragonEnableTomTom",
+ "DragonBootTomTom",
+ "DragonRunTomTom",
+ App.TYPE_GPS,
+ [
+ "android.permission.ACCESS_FINE_LOCATION",
+ "android.permission.ACCESS_COARSE_LOCATION",
+ "android.permission.READ_EXTERNAL_STORAGE",
+ "android.permission.WRITE_EXTERNAL_STORAGE",
+ ],
+ [
+ "SYSTEM_ALERT_WINDOW",
+ ]
+ ))
+ apps.append(App(
+ "tw.com.ainvest.outpack",
+ "tw.com.ainvest.outpack.ui.MainActivity",
+ "DragonEnableAegis",
+ "DragonBootAegis",
+ "DragonRunAegis",
+ App.TYPE_GPS,
+ [
+ "android.permission.ACCESS_FINE_LOCATION",
+ "android.permission.READ_EXTERNAL_STORAGE",
+ "android.permission.WRITE_EXTERNAL_STORAGE",
+ ],
+ [
+ "SYSTEM_ALERT_WINDOW",
+ ]
+ ))
+ apps.append(App(
+ "com.autonavi.amapauto",
+ "com.autonavi.amapauto.MainMapActivity",
+ "DragonEnableAutonavi",
+ "DragonBootAutonavi",
+ "DragonRunAutonavi",
+ App.TYPE_GPS,
+ [
+ "android.permission.ACCESS_FINE_LOCATION",
+ "android.permission.ACCESS_COARSE_LOCATION",
+ "android.permission.READ_EXTERNAL_STORAGE",
+ "android.permission.WRITE_EXTERNAL_STORAGE",
+ ],
+ [
+ "SYSTEM_ALERT_WINDOW",
+ ]
+ ))
+ apps.append(App(
+ "com.waze",
+ "com.waze.MainActivity",
+ "DragonWazeMode",
+ None,
+ "DragonRunWaze",
+ App.TYPE_FULLSCREEN,
+ [
+ "android.permission.ACCESS_FINE_LOCATION",
+ "android.permission.ACCESS_COARSE_LOCATION",
+ "android.permission.READ_EXTERNAL_STORAGE",
+ "android.permission.WRITE_EXTERNAL_STORAGE",
+ "android.permission.RECORD_AUDIO",
+ ],
+ [],
+ ))
+
+def main():
+ apps = []
+
+ # enable hotspot on boot
+ if params.get("DragonBootHotspot", encoding='utf8') == "1":
+ system(f"service call wifi 37 i32 0 i32 1")
+ # system(f"settings put system accelerometer_rotation 0")
+ # system(f"settings put system user_rotation 1")
+ # system(f"pm enable com.android.settings")
+ # system(f"am start -n com.android.settings/.TetherSettings")
+ # time.sleep(1)
+ # system(f"LD_LIBRARY_PATH= input tap 995 160")
+ # system(f"pkill com.android.settings")
+
+ last_started = False
+ thermal_sock = messaging.sub_sock('thermal')
+
+ frame = 0
+ start_delay = None
+ stop_delay = None
+ allow_auto_run = True
+ last_thermal_status = None
+ thermal_status = None
+ start_ts = sec_since_boot()
+ init_done = False
+ last_modified = None
+
+ while 1: #has_enabled_apps:
+ if not init_done:
+ if sec_since_boot() - start_ts >= 10:
+ init_apps(apps)
+ init_done = True
+ else:
+ enabled_apps = []
+ has_fullscreen_apps = False
+ modified = get_last_modified()
+ for app in apps:
+ # read params loop
+ if last_modified != modified:
+ app.read_params()
+ if app.last_is_enabled and not app.is_enabled and app.is_running:
+ app.kill(True)
+
+ if app.is_enabled:
+ if not has_fullscreen_apps and app.app_type == App.TYPE_FULLSCREEN:
+ has_fullscreen_apps = True
+
+ # process manual ctrl apps
+ if app.manual_ctrl_status != App.MANUAL_IDLE:
+ app.run(True) if app.manual_ctrl_status == App.MANUAL_ON else app.kill(True)
+
+ enabled_apps.append(app)
+ last_modified = modified
+ msg = messaging.recv_sock(thermal_sock, wait=True)
+ started = msg.thermal.started
+ # when car is running
+ if started:
+ stop_delay = None
+ # apps start 5 secs later
+ if start_delay is None:
+ start_delay = frame + 5
+
+ thermal_status = msg.thermal.thermalStatus
+ if thermal_status <= ThermalStatus.yellow:
+ allow_auto_run = True
+ # when temp reduce from red to yellow, we add start up delay as well
+ # so apps will not start up immediately
+ if last_thermal_status == ThermalStatus.red:
+ start_delay = frame + 60
+ elif thermal_status >= ThermalStatus.red:
+ allow_auto_run = False
+
+ last_thermal_status = thermal_status
+
+ # we run service apps and kill all util apps
+ # only run once
+ if last_started != started:
+ for app in enabled_apps:
+ if app.app_type in [App.TYPE_SERVICE, App.TYPE_GPS_SERVICE]:
+ app.run()
+ elif app.app_type == App.TYPE_UTIL:
+ app.kill()
+
+ # only run apps that's not manually ctrled
+ for app in enabled_apps:
+ if not app.manually_ctrled:
+ if has_fullscreen_apps:
+ if app.app_type == App.TYPE_FULLSCREEN:
+ app.run()
+ elif app.app_type in [App.TYPE_GPS, App.TYPE_UTIL]:
+ app.kill()
+ else:
+ if not allow_auto_run:
+ app.kill()
+ else:
+ if frame >= start_delay and app.is_auto_runnable and app.app_type == App.TYPE_GPS:
+ app.run()
+ # when car is stopped
+ else:
+ start_delay = None
+ # set delay to 30 seconds
+ if stop_delay is None:
+ stop_delay = frame + 30
+
+ for app in enabled_apps:
+ if app.is_running and not app.manually_ctrled:
+ if has_fullscreen_apps or frame >= stop_delay:
+ app.kill()
+
+ if last_started != started:
+ for app in enabled_apps:
+ app.manually_ctrled = False
+
+ last_started = started
+ frame += 3
+ time.sleep(3)
+
+def system(cmd):
+ try:
+ cloudlog.info("running %s" % cmd)
+ subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
+ except subprocess.CalledProcessError as e:
+ cloudlog.event("running failed",
+ cmd=e.cmd,
+ output=e.output[-1024:],
+ returncode=e.returncode)
+
+if __name__ == "__main__":
+ main()
diff --git a/selfdrive/dragonpilot/dashcamd/dashcamd.py b/selfdrive/dragonpilot/dashcamd/dashcamd.py
new file mode 100644
index 000000000..d1a1ecf55
--- /dev/null
+++ b/selfdrive/dragonpilot/dashcamd/dashcamd.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3.7
+#
+# courtesy of pjlao307 (https://github.com/pjlao307/)
+# this is just his original implementation but
+# in openpilot service form so it's always on
+#
+# with the highest bit rates, the video is approx. 0.5MB per second
+# the default value is set to 2.56Mbps = 0.32MB per second
+#
+import os
+import time
+import datetime
+import cereal.messaging as messaging
+import subprocess
+from selfdrive.swaglog import cloudlog
+from common.params import Params, put_nonblocking
+params = Params()
+from common.realtime import sec_since_boot, DT_TRML
+from common.dp import get_last_modified
+import collections
+import math
+
+dashcam_videos_path = '/sdcard/dashcam/'
+dashcam_duration = 60 # max is 180
+bit_rates = 2560000 # max is 4000000
+max_size_per_file = bit_rates/8*dashcam_duration # 2.56Mbps / 8 * 60 = 19.2MB per 60 seconds
+freespace_limit = 0.15 # we start cleaning up footage when freespace is below 15%
+shock_duration = 60
+
+TYPE_DRIVING = 'driving'
+TYPE_SHOCK = 'shock'
+
+def main(gctx=None):
+ retry = 0
+ folder_exists = False
+ dashcam_allowed = True
+ # make sure dashcam folder exists
+ while not folder_exists:
+ try:
+ if not os.path.exists(dashcam_videos_path):
+ os.makedirs(dashcam_videos_path)
+ else:
+ folder_exists = True
+ break
+ except OSError:
+ pass
+ if retry >= 5:
+ folder_exists = True
+ dashcam_allowed = False
+
+ retry += 1
+ time.sleep(5)
+
+ idlecam_enabled = False
+ health_timeout = int(1000 * 2.5 * DT_TRML) # 2.5x the expected health frequency
+ health_sock = messaging.sub_sock('health', timeout=health_timeout)
+ sensor_sock = messaging.sub_sock('sensorEvents')
+ samples = collections.deque([])
+ start_ts = None
+ last_started = False
+
+
+ dragon_dashcam_hours = 24. * 60 * 60
+ max_storage = (max_size_per_file/dashcam_duration) * dragon_dashcam_hours
+ dashcam_enabled = False
+ last_ts = 0.
+ last_modified = None
+ sleep = 5
+
+ thermal_sock = messaging.sub_sock('thermal')
+ params.put("DragonDashcamImpactDetectStarted", "0")
+ while dashcam_allowed:
+ type = TYPE_DRIVING
+ duration = dashcam_duration
+ ts = sec_since_boot()
+ if ts - last_ts >= 5.:
+ modified = get_last_modified()
+ if last_modified != modified:
+ dashcam_enabled = True if params.get("DragonEnableDashcam", encoding='utf8') == "1" else False
+ if dashcam_enabled:
+ idlecam_enabled = True if params.get("DragonDashcamImpactDetect", encoding='utf8') == "1" else False
+ else:
+ idlecam_enabled = False
+ try:
+ dragon_dashcam_hours = float(params.get("DragonDashcamHours", encoding='utf8')) * 60 * 60
+ except (TypeError, ValueError):
+ dragon_dashcam_hours = 24. * 60 * 60
+ max_storage = (max_size_per_file/dashcam_duration) * dragon_dashcam_hours
+
+ last_modified = modified
+ last_ts = ts
+
+ health = messaging.recv_sock(health_sock, wait=False)
+ started = True if health is not None and (health.health.ignitionLine or health.health.ignitionCan) else False
+ record_started = False
+
+ if last_started != started:
+ params.put("DragonDashcamImpactDetectStarted", "0")
+ samples.clear()
+
+ if started:
+ sleep = 5
+ if dashcam_enabled:
+ record_started = True
+ else:
+ if idlecam_enabled:
+ sleep = 0.02
+ sensor = messaging.recv_sock(sensor_sock, wait=False)
+ if sensor is not None:
+ for event in sensor.sensorEvents:
+ # accelerometer
+ if event.type == 1:
+ acc_x = event.acceleration.v[0]
+ acc_y = event.acceleration.v[1]
+ acc_z = event.acceleration.v[2]
+ g = math.sqrt(acc_x*acc_x+acc_y*acc_y+acc_z*acc_z)
+ val = round(9.8-g,2)
+ if len(samples) >= 250:
+ avg_sample = round(sum(samples)/len(samples),2)
+ if start_ts is None and abs(val - avg_sample) >= 0.3:
+ duration = shock_duration
+ type = TYPE_SHOCK
+ start_ts = ts
+ record_started = True
+ params.put("DragonDashcamImpactDetectStarted", "1")
+ samples.pop()
+ samples.appendleft(val)
+ if start_ts is not None and ts - start_ts >= shock_duration-1:
+ start_ts = None
+ record_started = False
+ params.put("DragonDashcamImpactDetectStarted", "0")
+
+ last_started = started
+
+ if record_started:
+ now = datetime.datetime.now()
+ file_name = now.strftime("%Y-%m-%d_%H-%M-%S")
+ postfix = '_impact' if type == TYPE_SHOCK else ''
+ os.system("screenrecord --bit-rate %s --time-limit %s %s%s%s.mp4 &" % (bit_rates, duration, dashcam_videos_path, file_name, postfix))
+ start_time = time.time()
+ try:
+ used_spaces = get_used_spaces()
+ last_used_spaces = used_spaces
+
+ # we should clean up files here if use too much spaces
+ # when used spaces greater than max available storage
+ # or when free space is less than 10%
+ # get health of board, log this in "thermal"
+ msg = messaging.recv_sock(thermal_sock, wait=True)
+ if used_spaces >= max_storage or (msg is not None and msg.thermal.freeSpace < freespace_limit):
+ # get all the files in the dashcam_videos_path path
+ files = [f for f in sorted(os.listdir(dashcam_videos_path)) if os.path.isfile(dashcam_videos_path + f)]
+ for file in files:
+ msg = messaging.recv_sock(thermal_sock, wait=True)
+ # delete file one by one and once it has enough space for 1 video, we stop deleting
+ if used_spaces - last_used_spaces < max_size_per_file or msg.thermal.freeSpace < freespace_limit:
+ system("rm -fr %s" % (dashcam_videos_path + file))
+ last_used_spaces = get_used_spaces()
+ else:
+ break
+ except os.error as e:
+ pass
+ time_diff = time.time()-start_time
+ # we start the process 1 second before screenrecord ended
+ # to make sure there are no missing footage
+ sleep_time = duration-1-time_diff
+ if sleep_time >= 0.:
+ time.sleep(sleep_time)
+ else:
+ time.sleep(sleep)
+
+def get_used_spaces():
+ return sum(os.path.getsize(dashcam_videos_path + f) for f in os.listdir(dashcam_videos_path) if os.path.isfile(dashcam_videos_path + f))
+
+def system(cmd):
+ try:
+ # cloudlog.info("running %s" % cmd)
+ subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
+ except subprocess.CalledProcessError as e:
+ cloudlog.event("running failed",
+ cmd=e.cmd,
+ output=e.output[-1024:],
+ returncode=e.returncode)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/selfdrive/dragonpilot/dragonconf/__init__.py b/selfdrive/dragonpilot/dragonconf/__init__.py
new file mode 100644
index 000000000..b5ee2828d
--- /dev/null
+++ b/selfdrive/dragonpilot/dragonconf/__init__.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python3.7
+from common.params import Params, put_nonblocking
+import time
+from math import floor
+import os
+import json
+
+default_conf = {
+ 'DragonEnableDashcam': '0',
+ 'DragonEnableAutoShutdown': '1',
+ 'DragonAutoShutdownAt': '0', # in minute
+ 'DragonEnableSteeringOnSignal': '0',
+ 'DragonEnableLogger': '1',
+ 'DragonEnableUploader': '1',
+ 'DragonNoctuaMode': '0',
+ 'DragonAllowGas': '0',
+ 'DragonToyotaStockDSU': '0',
+ 'DragonLatCtrl': '1',
+ 'DragonUISpeed': '1',
+ 'DragonUIEvent': '1',
+ 'DragonUIMaxSpeed': '1',
+ 'DragonUIFace': '1',
+ 'DragonUIDev': '0',
+ 'DragonUIDevMini': '0',
+ # 3rd party app
+ 'DragonEnableTomTom': '0',
+ 'DragonBootTomTom': '0',
+ 'DragonRunTomTom': '0',
+ 'DragonEnableAutonavi': '0',
+ 'DragonBootAutonavi': '0',
+ 'DragonRunAutonavi': '0',
+ 'DragonEnableAegis': '0',
+ 'DragonBootAegis': '0',
+ 'DragonRunAegis': '0',
+ 'DragonEnableMixplorer': '0',
+ 'DragonRunMixplorer': '0',
+ 'DragonSteeringMonitorTimer': '3', # 180 secs
+ 'DragonCameraOffset': '6',
+ 'DragonUIVolumeBoost': '0',
+ 'DragonGreyPandaMode': '0',
+ 'DragonDrivingUI': '1',
+ 'DragonDisplaySteeringLimitAlert': '1',
+ 'DragonChargingCtrl': '0',
+ 'DragonCharging': '70',
+ 'DragonDisCharging': '60',
+ 'DragonToyotaLaneDepartureWarning': '1',
+ 'DragonUILane': '1',
+ 'DragonUILead': '1',
+ 'DragonUIPath': '1',
+ 'DragonUIBlinker': '0',
+ 'DragonUIDMView': '0',
+ 'DragonEnableDriverMonitoring': '1',
+ 'DragonCarModel': '',
+ 'DragonEnableSlowOnCurve': '1',
+ 'DragonEnableLeadCarMovingAlert': '0',
+ 'DragonToyotaSnGMod': '0',
+ 'DragonWazeMode': '0',
+ 'DragonRunWaze': '0',
+ 'DragonEnableAutoLC': '0',
+ 'DragonAssistedLCMinMPH': '45',
+ 'DragonAutoLCMinMPH': '60',
+ 'DragonAutoLCDelay': '2',
+ 'DragonBTG': '0',
+ 'DragonBootHotspot': '0',
+ 'DragonAccelProfile': '0', # OFF = 0, ECO = 1, NORMAL = 2, SPORT = 3
+ 'DragonLastModified': str(floor(time.time())),
+ 'DragonEnableRegistration': '1',
+ 'DragonDynamicFollow': '0', # OFF = 0, LONG = 1, NORMAL = 2, SHORT = 3
+ 'DragonEnableGearCheck': '1',
+ 'DragonEnableTempMonitor': '1',
+ 'DragonAppAutoUpdate': '1',
+ 'DragonUpdating': '0',
+ 'DragonToyotaSngResponse': '0.0',
+ 'DragonCustomModel': '',
+ 'DragonLocale': 'en-US',
+ 'DragonUIScreenOffReversing': '0',
+ 'DragonEnableSRLearner': '1',
+ 'DragonEnableSteerBoost': '0',
+ 'DragonSteerBoostMin': '10', # percentage
+ 'DragonSteerBoostMax': '30', # percentage
+ 'DragonSteerBoostMinAt': '7.0',
+ 'DragonSteerBoostMaxAt': '15.0',
+ 'DragonDashcamHours': '24.0',
+ 'DragonUIScreenOffDriving': '0',
+ 'DragonUIBrightness': '0',
+ 'DragonDashcamImpactDetect': '0',
+ 'DragonDashcamImpactDetectStarted': '0',
+}
+
+deprecated_conf = {
+}
+
+deprecated_conf_invert = {
+ # 'DragonDisableDriverSafetyCheck': True,
+ # 'DragonTempDisableSteerOnSignal': False,
+ # 'DragonDisableLogger': True,
+ # 'DragonDisableUploader': True,
+ # 'DragonBBUI': False
+}
+
+def dp_get_last_modified():
+ return Params().get('DragonLastModified', encoding='utf-8').rstrip('\x00')
+
+def dragonpilot_set_params(params):
+ # # remove deprecated params
+ # for old, new in deprecated_conf.items():
+ # if params.get(old) is not None:
+ # if new is not None:
+ # old_val = str(params.get(old))
+ # new_val = old_val
+ # # invert the value if true
+ # if old in deprecated_conf_invert and deprecated_conf_invert[old] is True:
+ # new_val = "1" if old_val == "0" else "0"
+ # put_nonblocking(new, new_val)
+ # params.delete(old)
+
+ # set params
+ for key, val in default_conf.items():
+ if params.get(key) is None and key not in deprecated_conf:
+ put_nonblocking(key, str(val))
+ put_nonblocking('DragonSupportedCars', get_support_car_list())
+
+def get_support_car_list():
+ attrs = ['FINGERPRINTS', 'FW_VERSIONS']
+ cars = dict()
+ for car_folder in [x[0] for x in os.walk('/data/openpilot/selfdrive/car')]:
+ try:
+ car_name = car_folder.split('/')[-1]
+ if car_name != "mock":
+ names = []
+ for attr in attrs:
+ values = __import__('selfdrive.car.%s.values' % car_name, fromlist=[attr])
+ if hasattr(values, attr):
+ attr_values = getattr(values, attr)
+ else:
+ continue
+
+ if isinstance(attr_values, dict):
+ for f, v in attr_values.items():
+ if f not in names:
+ names.append(f)
+ names.sort()
+ cars[car_name] = names
+ except (ImportError, IOError, ValueError):
+ pass
+ return json.dumps(cars)
+
+if __name__ == "__main__":
+ params = Params()
+ params.manager_start()
+ dragonpilot_set_params(params)
diff --git a/selfdrive/dragonpilot/shutdownd/shutdownd.py b/selfdrive/dragonpilot/shutdownd/shutdownd.py
new file mode 100644
index 000000000..232d064ae
--- /dev/null
+++ b/selfdrive/dragonpilot/shutdownd/shutdownd.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3.7
+import os
+import time
+from common.params import Params
+params = Params()
+import cereal.messaging as messaging
+from common.realtime import sec_since_boot
+from common.dp import get_last_modified
+
+def main():
+ thermal_sock = messaging.sub_sock('thermal')
+ secs = 0
+ last_secs = None
+ shutdown_at = 0
+ started = False
+ usb_online = False
+ enabled = False
+ last_enabled = None
+ dp_last_modified = None
+ while 1:
+ cur_time = sec_since_boot()
+
+ modified = get_last_modified()
+ if dp_last_modified != modified:
+ enabled = True if params.get("DragonEnableAutoShutdown", encoding='utf8') == '1' else False
+ if enabled:
+ try:
+ secs = int(params.get("DragonAutoShutdownAt", encoding='utf8')) * 60
+ except (TypeError, ValueError):
+ secs = 0
+ dp_last_modified = modified
+
+ if last_enabled != enabled or last_secs != secs or started or usb_online:
+ shutdown_at = cur_time + secs
+
+ if enabled:
+ msg = messaging.recv_sock(thermal_sock, wait=True)
+ started = msg.thermal.started
+ usb_online = msg.thermal.usbOnline
+
+ if not started and not usb_online and secs > 0 and cur_time >= shutdown_at:
+ os.system('LD_LIBRARY_PATH="" svc power shutdown')
+
+ last_enabled = enabled
+ last_secs = secs
+
+ time.sleep(10)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/selfdrive/locationd/paramsd.cc b/selfdrive/locationd/paramsd.cc
index 8c60bc12e..a45694670 100644
--- a/selfdrive/locationd/paramsd.cc
+++ b/selfdrive/locationd/paramsd.cc
@@ -103,6 +103,18 @@ int main(int argc, char *argv[]) {
// Main loop
int save_counter = 0;
+
+ // dp, sr learner
+ char* enable_sr_learner_val = NULL;
+ read_db_value("DragonEnableSRLearner", &enable_sr_learner_val, NULL);
+ bool enable_sr_learner = true;
+ if (enable_sr_learner_val && strlen(enable_sr_learner_val) && enable_sr_learner_val[0] == '1') {
+ enable_sr_learner = true;
+ } else {
+ enable_sr_learner = false;
+ learner.sR = sR;
+ }
+
while (true){
for (auto s : poller->poll(100)){
Message * msg = s->receive();
@@ -128,7 +140,10 @@ int main(int argc, char *argv[]) {
double yaw_rate = -localizer.x[0];
bool valid = learner.update(yaw_rate, localizer.car_speed, localizer.steering_angle);
-
+ // dp - reset sR to json val;
+ if (!enable_sr_learner) {
+ learner.sR = sR;
+ }
// TODO: Fix in replay
double sensor_data_age = localizer.controls_state_time - localizer.sensor_data_time;
double camera_odometry_age = localizer.controls_state_time - localizer.camera_odometry_time;
diff --git a/selfdrive/manager.py b/selfdrive/manager.py
index c2db75823..5423c1116 100755
--- a/selfdrive/manager.py
+++ b/selfdrive/manager.py
@@ -10,6 +10,7 @@ import subprocess
import datetime
import textwrap
from selfdrive.swaglog import cloudlog, add_logentries_handler
+from selfdrive.dragonpilot.dragonconf import dragonpilot_set_params
from common.basedir import BASEDIR, PARAMS
from common.android import ANDROID
@@ -188,6 +189,10 @@ managed_processes = {
"dmonitoringmodeld": ("selfdrive/modeld", ["./dmonitoringmodeld"]),
"modeld": ("selfdrive/modeld", ["./modeld"]),
"driverview": "selfdrive.controls.lib.driverview",
+ # dp
+ "dashcamd": "selfdrive.dragonpilot.dashcamd.dashcamd",
+ "shutdownd": "selfdrive.dragonpilot.shutdownd.shutdownd",
+ "appd": "selfdrive.dragonpilot.appd.appd",
}
daemon_processes = {
@@ -222,6 +227,8 @@ if ANDROID:
'logcatd',
'tombstoned',
'updated',
+ 'shutdownd',
+ 'appd',
]
car_started_processes = [
@@ -426,11 +433,19 @@ def manager_thread():
cloudlog.info("manager start")
cloudlog.info({"environ": os.environ})
- # save boot log
- subprocess.call(["./loggerd", "--bootlog"], cwd=os.path.join(BASEDIR, "selfdrive/loggerd"))
-
params = Params()
+ # dp
+ # save boot log
+ if params.get("DragonEnableLogger", encoding='utf8') == "1":
+ subprocess.call(["./loggerd", "--bootlog"], cwd=os.path.join(BASEDIR, "selfdrive/loggerd"))
+
+ if params.get("DragonEnableDashcam", encoding='utf8') == "1":
+ persistent_processes.append('dashcamd')
+ if params.get("DragonDashcamImpactDetect", encoding='utf8') == "1":
+ car_started_processes.remove('sensord')
+ persistent_processes.append('sensord')
+
# start daemon processes
for p in daemon_processes:
start_daemon_process(p)
@@ -567,6 +582,9 @@ def main():
if params.get(k) is None:
params.put(k, v)
+ # dp
+ dragonpilot_set_params(params)
+
# is this chffrplus?
if os.getenv("PASSIVE") is not None:
params.put("Passive", str(int(os.getenv("PASSIVE"))))
@@ -574,15 +592,30 @@ def main():
if params.get("Passive") is None:
raise Exception("Passive must be set to continue")
+ reg = False if params.get("DragonEnableRegistration", encoding='utf8') == "0" else True
+
if ANDROID:
update_apks()
- manager_init()
+ manager_init(reg)
manager_prepare(spinner)
spinner.close()
if os.getenv("PREPAREONLY") is not None:
return
+ # dp
+ del managed_processes['tombstoned']
+ if params.get("DragonEnableLogger", encoding='utf8') == "0":
+ del managed_processes['loggerd']
+ del managed_processes['logmessaged']
+ del managed_processes['proclogd']
+ del managed_processes['logcatd']
+
+ if params.get("DragonEnableUploader", encoding='utf8') == "0":
+ del managed_processes['uploader']
+ if params.get("DragonEnableAutoUpdate", encoding='utf8') == "0":
+ del managed_processes['updated']
+
# SystemExit on sigterm
signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit(1))
diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py
index 1d69547cd..9f3280770 100755
--- a/selfdrive/thermald/thermald.py
+++ b/selfdrive/thermald/thermald.py
@@ -17,7 +17,11 @@ from selfdrive.swaglog import cloudlog
import cereal.messaging as messaging
from selfdrive.loggerd.config import get_available_percent
from selfdrive.pandad import get_expected_signature
-from selfdrive.thermald.power_monitoring import PowerMonitoring, get_battery_capacity, get_battery_status, get_battery_current, get_battery_voltage, get_usb_present
+from selfdrive.thermald.power_monitoring import PowerMonitoring, get_battery_capacity, get_battery_status, get_battery_current, get_battery_voltage, get_usb_present, set_battery_charging, get_battery_charging
+from common.dp import get_last_modified
+import re
+import subprocess
+params = Params()
FW_SIGNATURE = get_expected_signature()
@@ -113,10 +117,14 @@ def set_eon_fan(val):
_TEMP_THRS_H = [50., 65., 80., 10000]
# temp thresholds to control fan speed - low hysteresis
_TEMP_THRS_L = [42.5, 57.5, 72.5, 10000]
-# fan speed options
-_FAN_SPEEDS = [0, 16384, 32768, 65535]
-# max fan speed only allowed if battery is hot
-_BAT_TEMP_THERSHOLD = 45.
+if params.get('DragonNoctuaMode', encoding='utf8') == "1":
+ _FAN_SPEEDS = [65535, 65535, 65535, 65535]
+ _BAT_TEMP_THERSHOLD = 0.
+else:
+ # fan speed options
+ _FAN_SPEEDS = [0, 16384, 32768, 65535]
+ # max fan speed only allowed if battery is hot
+ _BAT_TEMP_THERSHOLD = 45.
def handle_fan_eon(max_cpu_temp, bat_temp, fan_speed, ignition):
@@ -184,16 +192,55 @@ def thermald_thread():
handle_fan = None
is_uno = False
- params = Params()
pm = PowerMonitoring()
no_panda_cnt = 0
+ # dp
+ ts_last_ip = 0
+ ts_last_update_vars = 0
+ ts_last_charging_ctrl = None
+ dp_last_modified = None
+
+ ip_addr = '255.255.255.255'
+ dragon_charging_ctrl = False
+ dragon_charging_ctrl_prev = False
+ dragon_to_discharge = 70
+ dragon_to_charge = 60
+ dp_temp_monitor = True
+
while 1:
+ # dp
+ ts = sec_since_boot()
+ # update variable status every 10 secs
+ if ts - ts_last_update_vars >= 10.:
+ modified = get_last_modified()
+ if dp_last_modified != modified:
+ dp_temp_monitor = False if params.get('DragonEnableTempMonitor', encoding='utf8') == "0" else True
+ if not is_uno:
+ dragon_charging_ctrl = True if params.get('DragonChargingCtrl', encoding='utf8') == "1" else False
+ if dragon_charging_ctrl:
+ try:
+ dragon_to_discharge = int(params.get('DragonCharging', encoding='utf8'))
+ except (TypeError, ValueError):
+ dragon_to_discharge = 70
+ try:
+ dragon_to_charge = int(params.get('DragonDisCharging', encoding='utf8'))
+ except (TypeError, ValueError):
+ dragon_to_charge = 60
+ else:
+ dragon_charging_ctrl = False
+ dp_last_modified = modified
+ ts_last_update_vars = ts
+
health = messaging.recv_sock(health_sock, wait=True)
location = messaging.recv_sock(location_sock)
location = location.gpsLocation if location else None
msg = read_thermal()
+ if params.get('DragonNoctuaMode', encoding='utf8') == "1":
+ setup_eon_fan()
+ handle_fan = handle_fan_eon
+
if health is not None:
usb_power = health.health.usbPowerMode != log.HealthData.UsbPowerMode.client
@@ -227,6 +274,9 @@ def thermald_thread():
params.panda_disconnect()
health_prev = health
+ if not ignition and params.get("DragonDashcamImpactDetectStarted", encoding='utf8') == "1":
+ ignition = True
+
# get_network_type is an expensive call. update every 10s
if (count % int(10. / DT_TRML)) == 0:
try:
@@ -251,6 +301,18 @@ def thermald_thread():
msg.thermal.batteryPercent = 100
msg.thermal.batteryStatus = "Charging"
+ # dp
+ # update ip every 10 seconds
+ ts = sec_since_boot()
+ if ts - ts_last_ip >= 10.:
+ try:
+ result = subprocess.check_output(["ifconfig", "wlan0"], encoding='utf8') # pylint: disable=unexpected-keyword-arg
+ ip_addr = re.findall(r"inet addr:((\d+\.){3}\d+)", result)[0][0]
+ except:
+ ip_addr = 'N/A'
+ ts_last_ip = ts
+ msg.thermal.ipAddr = ip_addr
+
current_filter.update(msg.thermal.batteryCurrent / 1e6)
# TODO: add car battery voltage check
@@ -287,46 +349,49 @@ def thermald_thread():
# all good
thermal_status = ThermalStatus.green
+ if not dp_temp_monitor:
+ thermal_status = ThermalStatus.green
+
# **** starting logic ****
-
+ time_valid = True
# Check for last update time and display alerts if needed
- now = datetime.datetime.utcnow()
-
- # show invalid date/time alert
- time_valid = now.year >= 2019
- if time_valid and not time_valid_prev:
- params.delete("Offroad_InvalidTime")
- if not time_valid and time_valid_prev:
- put_nonblocking("Offroad_InvalidTime", json.dumps(OFFROAD_ALERTS["Offroad_InvalidTime"]))
- time_valid_prev = time_valid
-
- # Show update prompt
- try:
- last_update = datetime.datetime.fromisoformat(params.get("LastUpdateTime", encoding='utf8'))
- except (TypeError, ValueError):
- last_update = now
- dt = now - last_update
-
- update_failed_count = params.get("UpdateFailedCount")
- update_failed_count = 0 if update_failed_count is None else int(update_failed_count)
-
- if dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
- if current_connectivity_alert != "expired":
- current_connectivity_alert = "expired"
- params.delete("Offroad_ConnectivityNeededPrompt")
- put_nonblocking("Offroad_ConnectivityNeeded", json.dumps(OFFROAD_ALERTS["Offroad_ConnectivityNeeded"]))
- elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
- remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
- if current_connectivity_alert != "prompt" + remaining_time:
- current_connectivity_alert = "prompt" + remaining_time
- alert_connectivity_prompt = copy.copy(OFFROAD_ALERTS["Offroad_ConnectivityNeededPrompt"])
- alert_connectivity_prompt["text"] += remaining_time + " days."
- params.delete("Offroad_ConnectivityNeeded")
- put_nonblocking("Offroad_ConnectivityNeededPrompt", json.dumps(alert_connectivity_prompt))
- elif current_connectivity_alert is not None:
- current_connectivity_alert = None
- params.delete("Offroad_ConnectivityNeeded")
- params.delete("Offroad_ConnectivityNeededPrompt")
+ # now = datetime.datetime.utcnow()
+ #
+ # # show invalid date/time alert
+ # time_valid = now.year >= 2019
+ # if time_valid and not time_valid_prev:
+ # params.delete("Offroad_InvalidTime")
+ # if not time_valid and time_valid_prev:
+ # put_nonblocking("Offroad_InvalidTime", json.dumps(OFFROAD_ALERTS["Offroad_InvalidTime"]))
+ # time_valid_prev = time_valid
+ #
+ # # Show update prompt
+ # try:
+ # last_update = datetime.datetime.fromisoformat(params.get("LastUpdateTime", encoding='utf8'))
+ # except (TypeError, ValueError):
+ # last_update = now
+ # dt = now - last_update
+ #
+ # update_failed_count = params.get("UpdateFailedCount")
+ # update_failed_count = 0 if update_failed_count is None else int(update_failed_count)
+ #
+ # if dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
+ # if current_connectivity_alert != "expired":
+ # current_connectivity_alert = "expired"
+ # params.delete("Offroad_ConnectivityNeededPrompt")
+ # put_nonblocking("Offroad_ConnectivityNeeded", json.dumps(OFFROAD_ALERTS["Offroad_ConnectivityNeeded"]))
+ # elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
+ # remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
+ # if current_connectivity_alert != "prompt" + remaining_time:
+ # current_connectivity_alert = "prompt" + remaining_time
+ # alert_connectivity_prompt = copy.copy(OFFROAD_ALERTS["Offroad_ConnectivityNeededPrompt"])
+ # alert_connectivity_prompt["text"] += remaining_time + " days."
+ # params.delete("Offroad_ConnectivityNeeded")
+ # put_nonblocking("Offroad_ConnectivityNeededPrompt", json.dumps(alert_connectivity_prompt))
+ # elif current_connectivity_alert is not None:
+ # current_connectivity_alert = None
+ # params.delete("Offroad_ConnectivityNeeded")
+ # params.delete("Offroad_ConnectivityNeededPrompt")
do_uninstall = params.get("DoUninstall") == b"1"
accepted_terms = params.get("HasAcceptedTerms") == terms_version
@@ -415,6 +480,19 @@ def thermald_thread():
fw_version_match_prev = fw_version_match
should_start_prev = should_start
+ if dragon_charging_ctrl != dragon_charging_ctrl_prev:
+ set_battery_charging(True)
+
+ if dragon_charging_ctrl:
+ if ts_last_charging_ctrl is None or ts - ts_last_charging_ctrl >= 60.:
+ if msg.thermal.batteryPercent >= dragon_to_discharge and get_battery_charging():
+ set_battery_charging(False)
+ elif msg.thermal.batteryPercent <= dragon_to_charge and not get_battery_charging():
+ set_battery_charging(True)
+ ts_last_charging_ctrl = ts
+
+ dragon_charging_ctrl_prev = dragon_charging_ctrl
+
# report to server once per minute
if (count % int(60. / DT_TRML)) == 0:
cloudlog.event("STATUS_PACKET",
diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc
index 4cb7966a1..e8a2d43ca 100644
--- a/selfdrive/ui/paint.cc
+++ b/selfdrive/ui/paint.cc
@@ -254,6 +254,30 @@ static void draw_steering(UIState *s, float curvature) {
// ui_draw_lane_edge(s, points, 0.0, nvgRGBA(0, 0, 255, 128), 5);
}
+static void draw_front_frame(UIState *s) {
+ const UIScene *scene = &s->scene;
+
+ float x1, x2, y1, y2;
+ glBindVertexArray(s->frame_vao[1]);
+
+ mat4 *out_mat;
+ out_mat = &s->front_frame_mat;
+ glActiveTexture(GL_TEXTURE0);
+ if (s->cur_vision_front_idx >= 0) {
+ glBindTexture(GL_TEXTURE_2D, s->frame_front_texs[s->cur_vision_front_idx]);
+ }
+
+ glUseProgram(s->frame_program);
+ glUniform1i(s->frame_texture_loc, 0);
+ glUniformMatrix4fv(s->frame_transform_loc, 1, GL_TRUE, out_mat->v);
+
+ assert(glGetError() == GL_NO_ERROR);
+ glEnableVertexAttribArray(0);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (const void*)0);
+ glDisableVertexAttribArray(0);
+ glBindVertexArray(0);
+}
+
static void draw_frame(UIState *s) {
const UIScene *scene = &s->scene;
@@ -344,27 +368,31 @@ static void ui_draw_vision_lanes(UIState *s) {
update_all_lane_lines_data(s, scene->model.right_lane, pvd + MODEL_LANE_PATH_CNT);
s->model_changed = false;
}
- // Draw left lane edge
- ui_draw_lane(
- s, &scene->model.left_lane,
- pvd,
- nvgRGBAf(1.0, 1.0, 1.0, scene->model.left_lane.prob));
+ if (s->dragon_ui_lane) {
+ // Draw left lane edge
+ ui_draw_lane(
+ s, &scene->model.left_lane,
+ pvd,
+ nvgRGBAf(1.0, 1.0, 1.0, scene->model.left_lane.prob));
- // Draw right lane edge
- ui_draw_lane(
- s, &scene->model.right_lane,
- pvd + MODEL_LANE_PATH_CNT,
- nvgRGBAf(1.0, 1.0, 1.0, scene->model.right_lane.prob));
+ // Draw right lane edge
+ ui_draw_lane(
+ s, &scene->model.right_lane,
+ pvd + MODEL_LANE_PATH_CNT,
+ nvgRGBAf(1.0, 1.0, 1.0, scene->model.right_lane.prob));
+ }
if(s->livempc_or_radarstate_changed) {
update_all_track_data(s);
s->livempc_or_radarstate_changed = false;
}
- // Draw vision path
- ui_draw_track(s, false, &s->track_vertices[0]);
- if (scene->engaged) {
- // Draw MPC path when engaged
- ui_draw_track(s, true, &s->track_vertices[1]);
+ if (s->dragon_ui_path) {
+ // Draw vision path
+ ui_draw_track(s, false, &s->track_vertices[0]);
+ if (scene->engaged) {
+ // Draw MPC path when engaged
+ ui_draw_track(s, true, &s->track_vertices[1]);
+ }
}
}
@@ -393,11 +421,13 @@ static void ui_draw_world(UIState *s) {
// Draw lane edges and vision/mpc tracks
ui_draw_vision_lanes(s);
- if (scene->lead_status) {
- draw_lead(s, scene->lead_d_rel, scene->lead_v_rel, scene->lead_y_rel);
- }
- if ((scene->lead_status2) && (fabs(scene->lead_d_rel - scene->lead_d_rel2) > 3.0)) {
- draw_lead(s, scene->lead_d_rel2, scene->lead_v_rel2, scene->lead_y_rel2);
+ if (s->dragon_ui_lead) {
+ if (scene->lead_status) {
+ draw_lead(s, scene->lead_d_rel, scene->lead_v_rel, scene->lead_y_rel);
+ }
+ if ((scene->lead_status2) && (fabs(scene->lead_d_rel - scene->lead_d_rel2) > 3.0)) {
+ draw_lead(s, scene->lead_d_rel2, scene->lead_v_rel2, scene->lead_y_rel2);
+ }
}
nvgRestore(s->vg);
}
@@ -452,13 +482,13 @@ static void ui_draw_vision_maxspeed(UIState *s) {
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE);
const int text_x = viz_maxspeed_x + (viz_maxspeed_xo / 2) + (viz_maxspeed_w / 2);
- ui_draw_text(s->vg, text_x, 148, "MAX", 26 * 2.5, COLOR_WHITE_ALPHA(is_cruise_set ? 200 : 100), s->font_sans_regular);
+ ui_draw_text(s->vg, text_x, 148, (strcmp(s->dragon_locale, "zh-TW") == 0? "最高速限" : strcmp(s->dragon_locale, "zh-CN") == 0? "最高速限" : "MAX"), 26 * 2.5, COLOR_WHITE_ALPHA(is_cruise_set ? 200 : 100), s->font_sans_regular);
if (is_cruise_set) {
snprintf(maxspeed_str, sizeof(maxspeed_str), "%d", maxspeed_calc);
ui_draw_text(s->vg, text_x, 242, maxspeed_str, 48 * 2.5, COLOR_WHITE, s->font_sans_bold);
} else {
- ui_draw_text(s->vg, text_x, 242, "N/A", 42 * 2.5, COLOR_WHITE_ALPHA(100), s->font_sans_semibold);
+ ui_draw_text(s->vg, text_x, 242, (strcmp(s->dragon_locale, "zh-TW") == 0? "未設" : strcmp(s->dragon_locale, "zh-CN") == 0? "未设" : "N/A"), 42 * 2.5, COLOR_WHITE_ALPHA(100), s->font_sans_semibold);
}
}
@@ -506,8 +536,8 @@ static void ui_draw_vision_speedlimit(UIState *s) {
// Draw "Speed Limit" Text
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE);
color = is_speedlim_valid && s->is_ego_over_limit ? COLOR_WHITE : COLOR_BLACK;
- ui_draw_text(s->vg, text_x + (is_speedlim_valid ? 6 : 0), text_y, "SMART", 50, color, s->font_sans_semibold);
- ui_draw_text(s->vg, text_x + (is_speedlim_valid ? 6 : 0), text_y + 40, "SPEED", 50, color, s->font_sans_semibold);
+ ui_draw_text(s->vg, text_x + (is_speedlim_valid ? 6 : 0), text_y, (strcmp(s->dragon_locale, "zh-TW") == 0? "智能" : strcmp(s->dragon_locale, "zh-CN") == 0? "智能" : "SMART"), 50, color, s->font_sans_semibold);
+ ui_draw_text(s->vg, text_x + (is_speedlim_valid ? 6 : 0), text_y + 40, (strcmp(s->dragon_locale, "zh-TW") == 0? "速度" : strcmp(s->dragon_locale, "zh-CN") == 0? "速度" : "DESIR STEER"), 50, color, s->font_sans_semibold);
// Draw Speed Text
color = s->is_ego_over_limit ? COLOR_WHITE : COLOR_BLACK;
@@ -515,7 +545,7 @@ static void ui_draw_vision_speedlimit(UIState *s) {
snprintf(speedlim_str, sizeof(speedlim_str), "%d", speedlim_calc);
ui_draw_text(s->vg, text_x, viz_speedlim_y + (is_speedlim_valid ? 170 : 165), speedlim_str, 48*2.5, color, s->font_sans_bold);
} else {
- ui_draw_text(s->vg, text_x, viz_speedlim_y + (is_speedlim_valid ? 170 : 165), "N/A", 42*2.5, color, s->font_sans_semibold);
+ ui_draw_text(s->vg, text_x, viz_speedlim_y + (is_speedlim_valid ? 170 : 165), (strcmp(s->dragon_locale, "zh-TW") == 0? "未設" : strcmp(s->dragon_locale, "zh-CN") == 0? "未设" : "N/A"), 42*2.5, color, s->font_sans_semibold);
}
}
@@ -529,13 +559,43 @@ static void ui_draw_vision_speed(UIState *s) {
const int viz_speed_x = scene->ui_viz_rx+((scene->ui_viz_rw/2)-(viz_speed_w/2));
char speed_str[32];
- nvgBeginPath(s->vg);
- nvgRect(s->vg, viz_speed_x, box_y, viz_speed_w, header_h);
- nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE);
+ if (s->dragon_ui_speed) {
+ nvgBeginPath(s->vg);
+ nvgRect(s->vg, viz_speed_x, box_y, viz_speed_w, header_h);
+ nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE);
- snprintf(speed_str, sizeof(speed_str), "%d", (int)speed);
- ui_draw_text(s->vg, viz_speed_x + viz_speed_w / 2, 240, speed_str, 96*2.5, COLOR_WHITE, s->font_sans_bold);
- ui_draw_text(s->vg, viz_speed_x + viz_speed_w / 2, 320, s->is_metric?"kph":"mph", 36*2.5, COLOR_WHITE_ALPHA(200), s->font_sans_regular);
+ snprintf(speed_str, sizeof(speed_str), "%d", (int)speed);
+ ui_draw_text(s->vg, viz_speed_x + viz_speed_w / 2, 240, speed_str, 96*2.5, COLOR_WHITE, s->font_sans_bold);
+ ui_draw_text(s->vg, viz_speed_x + viz_speed_w / 2, 320, s->is_metric?"km/h":"mph", 36*2.5, COLOR_WHITE_ALPHA(200), s->font_sans_regular);
+ }
+
+ // dp blinker, from kegman
+ if (s->dragon_ui_blinker) {
+ if(s->scene.leftBlinker) {
+ nvgBeginPath(s->vg);
+ nvgMoveTo(s->vg, viz_speed_x, box_y + header_h/4);
+ nvgLineTo(s->vg, viz_speed_x - viz_speed_w/2, box_y + header_h/4 + header_h/4);
+ nvgLineTo(s->vg, viz_speed_x, box_y + header_h/2 + header_h/4);
+ nvgClosePath(s->vg);
+ nvgFillColor(s->vg, nvgRGBA(23,134,68,s->scene.blinker_blinkingrate>=50?210:60));
+ nvgFill(s->vg);
+ }
+
+ if(s->scene.rightBlinker) {
+ nvgBeginPath(s->vg);
+ nvgMoveTo(s->vg, viz_speed_x+viz_speed_w, box_y + header_h/4);
+ nvgLineTo(s->vg, viz_speed_x+viz_speed_w + viz_speed_w/2, box_y + header_h/4 + header_h/4);
+ nvgLineTo(s->vg, viz_speed_x+viz_speed_w, box_y + header_h/2 + header_h/4);
+ nvgClosePath(s->vg);
+ nvgFillColor(s->vg, nvgRGBA(23,134,68,s->scene.blinker_blinkingrate>=50?210:60));
+ nvgFill(s->vg);
+ }
+
+ if(s->scene.leftBlinker || s->scene.rightBlinker) {
+ s->scene.blinker_blinkingrate -= 3;
+ if(s->scene.blinker_blinkingrate<0) s->scene.blinker_blinkingrate = 120;
+ }
+ }
}
static void ui_draw_vision_event(UIState *s) {
@@ -577,6 +637,61 @@ static void ui_draw_vision_face(UIState *s) {
ui_draw_circle_image(s->vg, face_x, face_y, face_size, s->img_face, s->scene.monitoring_active);
}
+static void ui_draw_df_button(UIState *s) {
+ nvgBeginPath(s->vg);
+ nvgRoundedRect(s->vg, df_btn_x, df_btn_y, df_btn_w, df_btn_h, 20);
+ nvgStrokeColor(s->vg, COLOR_WHITE_ALPHA(80));
+ nvgStrokeWidth(s->vg, 6);
+ nvgStroke(s->vg);
+
+ nvgFontFaceId(s->vg, s->font_sans_regular);
+ nvgFillColor(s->vg, COLOR_WHITE_ALPHA(200));
+ nvgFontSize(s->vg, (strcmp(s->dragon_locale, "zh-TW") == 0? 96 : strcmp(s->dragon_locale, "zh-CN") == 0? 96 : 48));
+ nvgTextAlign(s->vg, NVG_ALIGN_CENTER);
+ int val = s->dragon_df_mode;
+
+ nvgText(s->vg, df_btn_x + df_btn_w / 2, df_btn_y + df_btn_h / 2,
+ val == 1? (strcmp(s->dragon_locale, "zh-TW") == 0? "長距" : strcmp(s->dragon_locale, "zh-CN") == 0? "长距" : "LONG") :
+ val == 2? (strcmp(s->dragon_locale, "zh-TW") == 0? "正常" : strcmp(s->dragon_locale, "zh-CN") == 0? "正常" : "NORMAL") :
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "短距" : strcmp(s->dragon_locale, "zh-CN") == 0? "短距" : "SHORT"),
+ NULL);
+
+ nvgFontFaceId(s->vg, s->font_sans_regular);
+ nvgFillColor(s->vg, COLOR_WHITE_ALPHA(200));
+ nvgFontSize(s->vg, 37.5);
+ nvgTextAlign(s->vg, NVG_ALIGN_CENTER);
+ nvgText(s->vg, df_btn_x + df_btn_w / 2, df_btn_y + df_btn_h - 10,
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "車距" : strcmp(s->dragon_locale, "zh-CN") == 0? "车距" : "FOLLOW"),
+ NULL);
+}
+
+static void ui_draw_ap_button(UIState *s) {
+ nvgBeginPath(s->vg);
+ nvgRoundedRect(s->vg, ap_btn_x, ap_btn_y, ap_btn_w, ap_btn_h, 20);
+ nvgStrokeColor(s->vg, COLOR_WHITE_ALPHA(80));
+ nvgStrokeWidth(s->vg, 6);
+ nvgStroke(s->vg);
+
+ nvgFontFaceId(s->vg, s->font_sans_regular);
+ nvgFillColor(s->vg, COLOR_WHITE_ALPHA(200));
+ nvgFontSize(s->vg, (strcmp(s->dragon_locale, "zh-TW") == 0? 96 : strcmp(s->dragon_locale, "zh-CN") == 0? 96 : 48));
+ nvgTextAlign(s->vg, NVG_ALIGN_CENTER);
+ int val = s->dragon_ap_mode;
+ nvgText(s->vg, ap_btn_x + ap_btn_w / 2, ap_btn_y + ap_btn_h / 2,
+ val == 1? (strcmp(s->dragon_locale, "zh-TW") == 0? "節能" : strcmp(s->dragon_locale, "zh-CN") == 0? "节能" : "ECO") :
+ val == 2? (strcmp(s->dragon_locale, "zh-TW") == 0? "正常" : strcmp(s->dragon_locale, "zh-CN") == 0? "正常" : "NORMAL") :
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "運動" : strcmp(s->dragon_locale, "zh-CN") == 0? "运动" : "SPORT"),
+ NULL);
+
+ nvgFontFaceId(s->vg, s->font_sans_regular);
+ nvgFillColor(s->vg, COLOR_WHITE_ALPHA(200));
+ nvgFontSize(s->vg, 37.5);
+ nvgTextAlign(s->vg, NVG_ALIGN_CENTER);
+ nvgText(s->vg, ap_btn_x + ap_btn_w / 2, ap_btn_y + ap_btn_h - 10,
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "加速" : strcmp(s->dragon_locale, "zh-CN") == 0? "加速" : "ACCEL"),
+ NULL);
+}
+
static void ui_draw_driver_view(UIState *s) {
const UIScene *scene = &s->scene;
s->scene.uilayout_sidebarcollapsed = true;
@@ -637,26 +752,332 @@ static void ui_draw_vision_header(UIState *s) {
int ui_viz_rx = scene->ui_viz_rx;
int ui_viz_rw = scene->ui_viz_rw;
- NVGpaint gradient = nvgLinearGradient(s->vg, ui_viz_rx,
- (box_y+(header_h-(header_h/2.5))),
- ui_viz_rx, box_y+header_h,
- nvgRGBAf(0,0,0,0.45), nvgRGBAf(0,0,0,0));
- ui_draw_rect(s->vg, ui_viz_rx, box_y, ui_viz_rw, header_h, gradient);
-
- ui_draw_vision_maxspeed(s);
-
+ if (s->dragon_driving_ui) {
+ NVGpaint gradient = nvgLinearGradient(s->vg, ui_viz_rx,
+ (box_y+(header_h-(header_h/2.5))),
+ ui_viz_rx, box_y+header_h,
+ nvgRGBAf(0,0,0,0.45), nvgRGBAf(0,0,0,0));
+ ui_draw_rect(s->vg, ui_viz_rx, box_y, ui_viz_rw, header_h, gradient);
+ }
+ if (s->dragon_ui_maxspeed) {
+ ui_draw_vision_maxspeed(s);
+ }
#ifdef SHOW_SPEEDLIMIT
ui_draw_vision_speedlimit(s);
#endif
ui_draw_vision_speed(s);
- ui_draw_vision_event(s);
+ if (s->dragon_ui_event) {
+ ui_draw_vision_event(s);
+ }
+}
+
+static void ui_draw_infobar(UIState *s) {
+ const UIScene *scene = &s->scene;
+ int ui_viz_rx = scene->ui_viz_rx;
+ bool hasSidebar = !s->scene.uilayout_sidebarcollapsed;
+ int rect_w = vwp_w - ui_viz_rx - bdr_s;
+ int rect_h = 80;
+ int rect_x = (hasSidebar? (bdr_s+sbr_w) : ui_viz_rx);
+ int rect_y = vwp_h - bdr_s - rect_h;
+ int text_x = rect_w / 2 + ui_viz_rx;
+ int text_y = rect_y + 55;
+
+ char infobar[100];
+ // create time string
+ char date_time[20];
+ time_t rawtime = time(NULL);
+ struct tm timeinfo;
+ localtime_r(&rawtime, &timeinfo);
+ strftime(date_time, sizeof(date_time),"%D %T", &timeinfo);
+
+ // Create temp string
+ char temp[6];
+ snprintf(temp, sizeof(temp), "%02d°C", s->scene.paTemp);
+
+ // create battery percentage string
+ char battery[5];
+ snprintf(battery, sizeof(battery), "%02d%%", s->scene.batteryPercent);
+
+ if (s->dragon_ui_dev_mini) {
+ char rel_steer[9];
+ snprintf(rel_steer, sizeof(rel_steer), "%s%05.1f°", s->scene.angleSteers < 0? "-" : "+", fabs(s->scene.angleSteers));
+
+ char des_steer[9];
+ if (s->scene.engaged) {
+ snprintf(des_steer, sizeof(des_steer), "%s%05.1f°", s->scene.angleSteersDes < 0? "-" : "+", fabs(s->scene.angleSteersDes));
+ } else {
+ snprintf(des_steer, sizeof(des_steer), "%7s", "-");
+ }
+
+ char lead_dist[8];
+ if (s->scene.lead_status) {
+ snprintf(lead_dist, sizeof(lead_dist), "%06.2fm", s->scene.lead_d_rel);
+ } else {
+ snprintf(lead_dist, sizeof(lead_dist), "%7s", "-");
+ }
+
+ snprintf(
+ infobar,
+ sizeof(infobar),
+ "%s /TMP: %s /BAT: %s /REL: %s /DES: %s /DIS: %s",
+ date_time,
+ temp,
+ battery,
+ rel_steer,
+ des_steer,
+ lead_dist
+ );
+ } else {
+ snprintf(
+ infobar,
+ sizeof(infobar),
+ "%s /TMP: %s /BAT: %s",
+ date_time,
+ temp,
+ battery
+ );
+ }
+
+ nvgBeginPath(s->vg);
+ nvgRect(s->vg, rect_x, rect_y, rect_w, rect_h);
+ nvgFillColor(s->vg, COLOR_BLACK_ALPHA(100));
+ nvgFill(s->vg);
+
+ nvgFontSize(s->vg, hasSidebar? 35:42);
+ nvgFontFaceId(s->vg, s->font_courbd);
+ nvgFillColor(s->vg, COLOR_WHITE_ALPHA(200));
+ nvgTextAlign(s->vg, NVG_ALIGN_CENTER);
+ nvgText(s->vg, text_x, text_y, infobar, NULL);
+}
+
+//BB START: functions added for the display of various items
+static int bb_ui_draw_measure(UIState *s, const char* bb_value, const char* bb_uom, const char* bb_label,
+ int bb_x, int bb_y, int bb_uom_dx,
+ NVGcolor bb_valueColor, NVGcolor bb_labelColor, NVGcolor bb_uomColor,
+ int bb_valueFontSize, int bb_labelFontSize, int bb_uomFontSize ) {
+ const UIScene *scene = &s->scene;
+ nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE);
+ int dx = 0;
+ if (strlen(bb_uom) > 0) {
+ dx = (int)(bb_uomFontSize*2.5/2);
+ }
+ //print value
+ nvgFontFaceId(s->vg, s->font_sans_bold);
+ nvgFontSize(s->vg, bb_valueFontSize*2.5);
+ nvgFillColor(s->vg, bb_valueColor);
+ nvgText(s->vg, bb_x-dx/2, bb_y+ (int)(bb_valueFontSize*2.5)+5, bb_value, NULL);
+ //print label
+ nvgFontFaceId(s->vg, s->font_sans_regular);
+ nvgFontSize(s->vg, bb_labelFontSize*2.5);
+ nvgFillColor(s->vg, bb_labelColor);
+ nvgText(s->vg, bb_x, bb_y + (int)(bb_valueFontSize*2.5)+5 + (int)(bb_labelFontSize*2.5)+5, bb_label, NULL);
+ //print uom
+ if (strlen(bb_uom) > 0) {
+ nvgSave(s->vg);
+ int rx =bb_x + bb_uom_dx + bb_valueFontSize -3;
+ int ry = bb_y + (int)(bb_valueFontSize*2.5/2)+25;
+ nvgTranslate(s->vg,rx,ry);
+ nvgRotate(s->vg, -1.5708); //-90deg in radians
+ nvgFontFaceId(s->vg, s->font_sans_regular);
+ nvgFontSize(s->vg, (int)(bb_uomFontSize*2.5));
+ nvgFillColor(s->vg, bb_uomColor);
+ nvgText(s->vg, 0, 0, bb_uom, NULL);
+ nvgRestore(s->vg);
+ }
+ return (int)((bb_valueFontSize + bb_labelFontSize)*2.5) + 5;
+}
+
+static void bb_ui_draw_measures_left(UIState *s, int bb_x, int bb_y, int bb_w ) {
+ const UIScene *scene = &s->scene;
+ int bb_rx = bb_x + (int)(bb_w/2);
+ int bb_ry = bb_y;
+ int bb_h = 5;
+ NVGcolor lab_color = COLOR_WHITE_ALPHA(200);
+ NVGcolor uom_color = COLOR_WHITE_ALPHA(200);
+ int value_fontSize=30;
+ int label_fontSize=15;
+ int uom_fontSize = 15;
+ int bb_uom_dx = (int)(bb_w /2 - uom_fontSize*2.5) ;
+
+ //add visual radar relative distance
+ if (true) {
+ char val_str[16];
+ char uom_str[6];
+ NVGcolor val_color = COLOR_WHITE_ALPHA(200);
+ if (scene->lead_status) {
+ //show RED if less than 5 meters
+ //show orange if less than 15 meters
+ if((int)(scene->lead_d_rel) < 15) {
+ val_color = nvgRGBA(255, 188, 3, 200);
+ }
+ if((int)(scene->lead_d_rel) < 5) {
+ val_color = nvgRGBA(255, 0, 0, 200);
+ }
+ // lead car relative distance is always in meters
+ snprintf(val_str, sizeof(val_str), "%d", (int)scene->lead_d_rel);
+ } else {
+ snprintf(val_str, sizeof(val_str), "-");
+ }
+ snprintf(uom_str, sizeof(uom_str), "m ");
+ bb_h +=bb_ui_draw_measure(s, val_str, uom_str,
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "真實車距" : strcmp(s->dragon_locale, "zh-CN") == 0? "真实车距" : "REL DIST"),
+ bb_rx, bb_ry, bb_uom_dx,
+ val_color, lab_color, uom_color,
+ value_fontSize, label_fontSize, uom_fontSize );
+ bb_ry = bb_y + bb_h;
+ }
+
+ //add visual radar relative speed
+ if (true) {
+ char val_str[16];
+ char uom_str[6];
+ NVGcolor val_color = COLOR_WHITE_ALPHA(200);
+ if (scene->lead_status) {
+ //show Orange if negative speed (approaching)
+ //show Orange if negative speed faster than 5mph (approaching fast)
+ if((int)(scene->lead_v_rel) < 0) {
+ val_color = nvgRGBA(255, 188, 3, 200);
+ }
+ if((int)(scene->lead_v_rel) < -5) {
+ val_color = nvgRGBA(255, 0, 0, 200);
+ }
+ // lead car relative speed is always in meters
+ if (s->is_metric) {
+ snprintf(val_str, sizeof(val_str), "%d", (int)(scene->lead_v_rel * 3.6 + 0.5));
+ } else {
+ snprintf(val_str, sizeof(val_str), "%d", (int)(scene->lead_v_rel * 2.2374144 + 0.5));
+ }
+ } else {
+ snprintf(val_str, sizeof(val_str), "-");
+ }
+ if (s->is_metric) {
+ snprintf(uom_str, sizeof(uom_str), "km/h");;
+ } else {
+ snprintf(uom_str, sizeof(uom_str), "mph");
+ }
+ bb_h +=bb_ui_draw_measure(s, val_str, uom_str,
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "相對速度" : strcmp(s->dragon_locale, "zh-CN") == 0? "相对速度" : "REAL SPEED"),
+ bb_rx, bb_ry, bb_uom_dx,
+ val_color, lab_color, uom_color,
+ value_fontSize, label_fontSize, uom_fontSize );
+ bb_ry = bb_y + bb_h;
+ }
+
+ //finally draw the frame
+ bb_h += 20;
+ nvgBeginPath(s->vg);
+ nvgRoundedRect(s->vg, bb_x, bb_y, bb_w, bb_h, 20);
+ nvgStrokeColor(s->vg, COLOR_WHITE_ALPHA(80));
+ nvgStrokeWidth(s->vg, 6);
+ nvgStroke(s->vg);
+}
+
+static void bb_ui_draw_measures_right(UIState *s, int bb_x, int bb_y, int bb_w ) {
+ const UIScene *scene = &s->scene;
+ int bb_rx = bb_x + (int)(bb_w/2);
+ int bb_ry = bb_y;
+ int bb_h = 5;
+ NVGcolor lab_color = COLOR_WHITE_ALPHA(200);
+ NVGcolor uom_color = COLOR_WHITE_ALPHA(200);
+ int value_fontSize=30;
+ int label_fontSize=15;
+ int uom_fontSize = 15;
+ int bb_uom_dx = (int)(bb_w /2 - uom_fontSize*2.5) ;
+
+ //add steering angle
+ if (true) {
+ char val_str[16];
+ char uom_str[6];
+ NVGcolor val_color = COLOR_WHITE_ALPHA(200);
+ //show Orange if more than 6 degrees
+ //show red if more than 12 degrees
+ if(((int)(scene->angleSteers) < -6) || ((int)(scene->angleSteers) > 6)) {
+ val_color = nvgRGBA(255, 188, 3, 200);
+ }
+ if(((int)(scene->angleSteers) < -12) || ((int)(scene->angleSteers) > 12)) {
+ val_color = nvgRGBA(255, 0, 0, 200);
+ }
+ // steering is in degrees
+ snprintf(val_str, sizeof(val_str), "%.1f°",(scene->angleSteers));
+
+ snprintf(uom_str, sizeof(uom_str), "");
+ bb_h +=bb_ui_draw_measure(s, val_str, uom_str,
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "實際轉角" : strcmp(s->dragon_locale, "zh-CN") == 0? "实际转角" : "REAL STEER"),
+ bb_rx, bb_ry, bb_uom_dx,
+ val_color, lab_color, uom_color,
+ value_fontSize, label_fontSize, uom_fontSize );
+ bb_ry = bb_y + bb_h;
+ }
+
+ //add desired steering angle
+ if (true) {
+ char val_str[16];
+ char uom_str[6];
+ NVGcolor val_color = COLOR_WHITE_ALPHA(200);
+ //show Orange if more than 6 degrees
+ //show red if more than 12 degrees
+ if(((int)(scene->angleSteersDes) < -6) || ((int)(scene->angleSteersDes) > 6)) {
+ val_color = nvgRGBA(255, 188, 3, 200);
+ }
+ if(((int)(scene->angleSteersDes) < -12) || ((int)(scene->angleSteersDes) > 12)) {
+ val_color = nvgRGBA(255, 0, 0, 200);
+ }
+ // steering is in degrees
+ snprintf(val_str, sizeof(val_str), "%.1f°",(scene->angleSteersDes));
+
+ snprintf(uom_str, sizeof(uom_str), "");
+ bb_h +=bb_ui_draw_measure(s, val_str, uom_str,
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "預測轉角" : strcmp(s->dragon_locale, "zh-CN") == 0? "预测转角" : "DESIR STEER"),
+ bb_rx, bb_ry, bb_uom_dx,
+ val_color, lab_color, uom_color,
+ value_fontSize, label_fontSize, uom_fontSize );
+ bb_ry = bb_y + bb_h;
+ }
+
+ //finally draw the frame
+ bb_h += 20;
+ nvgBeginPath(s->vg);
+ nvgRoundedRect(s->vg, bb_x, bb_y, bb_w, bb_h, 20);
+ nvgStrokeColor(s->vg, COLOR_WHITE_ALPHA(80));
+ nvgStrokeWidth(s->vg, 6);
+ nvgStroke(s->vg);
+}
+
+static void ui_draw_bbui(UIState *s) {
+ const UIScene *scene = &s->scene;
+ const int bb_dml_w = 180;
+ const int bb_dml_x = (scene->ui_viz_rx + (bdr_s * 2));
+ const int bb_dml_y = (box_y + (bdr_s * 1.5)) + 220;
+
+ const int bb_dmr_w = 180;
+ const int bb_dmr_x = scene->ui_viz_rx + scene->ui_viz_rw - bb_dmr_w - (bdr_s * 2);
+ const int bb_dmr_y = (box_y + (bdr_s * 1.5)) + 220;
+
+ bb_ui_draw_measures_right(s, bb_dml_x, bb_dml_y, bb_dml_w);
+ bb_ui_draw_measures_left(s, bb_dmr_x, bb_dmr_y, bb_dmr_w);
}
static void ui_draw_vision_footer(UIState *s) {
nvgBeginPath(s->vg);
nvgRect(s->vg, s->scene.ui_viz_rx, footer_y, s->scene.ui_viz_rw, footer_h);
- ui_draw_vision_face(s);
+ if (s->dragon_ui_face) {
+ ui_draw_vision_face(s);
+ }
+ if (!s->dragon_waze_mode) {
+ if ((int)s->dragon_df_mode > 0) {
+ ui_draw_df_button(s);
+ }
+ if ((int)s->dragon_ap_mode > 0) {
+ ui_draw_ap_button(s);
+ }
+ }
+ if (s->dragon_ui_dev) {
+ ui_draw_bbui(s);
+ }
+ if (s->dragon_ui_dev_mini || s->dragon_enable_dashcam || s->dragon_waze_mode) {
+ ui_draw_infobar(s);
+ }
#ifdef SHOW_SPEEDLIMIT
// ui_draw_vision_map(s);
@@ -717,13 +1138,20 @@ static void ui_draw_vision(UIState *s) {
glEnable(GL_SCISSOR_TEST);
glViewport(scene->ui_viz_rx+scene->ui_viz_ro, s->fb_h-(box_y+box_h), viz_w, box_h);
glScissor(scene->ui_viz_rx, s->fb_h-(box_y+box_h), scene->ui_viz_rw, box_h);
- draw_frame(s);
+ if (s->dragon_driving_ui) {
+ draw_frame(s);
+ }
+ if (s->dragon_ui_dm_view) {
+ glViewport(1240, 110, viz_w*0.4, box_h*0.4);
+ draw_front_frame(s);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ }
glDisable(GL_SCISSOR_TEST);
glViewport(0, 0, s->fb_w, s->fb_h);
// Draw augmented elements
- if (!scene->frontview && !scene->fullview) {
+ if (s->dragon_driving_ui && !scene->frontview && !scene->fullview) {
ui_draw_world(s);
}
@@ -865,11 +1293,11 @@ void ui_nvg_init(UIState *s) {
s->font_courbd = nvgCreateFont(s->vg, "courbd", "../assets/fonts/courbd.ttf");
assert(s->font_courbd >= 0);
- s->font_sans_regular = nvgCreateFont(s->vg, "sans-regular", "../assets/fonts/opensans_regular.ttf");
+ s->font_sans_regular = nvgCreateFont(s->vg, "sans-regular", "../../dragonpilot/cjk-fonts/NotoSansCJKtc-Regular.otf");
assert(s->font_sans_regular >= 0);
- s->font_sans_semibold = nvgCreateFont(s->vg, "sans-semibold", "../assets/fonts/opensans_semibold.ttf");
+ s->font_sans_semibold = nvgCreateFont(s->vg, "sans-semibold", "../../dragonpilot/cjk-fonts/NotoSansCJKtc-Medium.otf");
assert(s->font_sans_semibold >= 0);
- s->font_sans_bold = nvgCreateFont(s->vg, "sans-bold", "../assets/fonts/opensans_bold.ttf");
+ s->font_sans_bold = nvgCreateFont(s->vg, "sans-bold", "../../dragonpilot/cjk-fonts/NotoSansCJKtc-Bold.otf");
assert(s->font_sans_bold >= 0);
s->img_wheel = nvgCreateImage(s->vg, "../assets/img_chffr_wheel.png", 1);
diff --git a/selfdrive/ui/sidebar.cc b/selfdrive/ui/sidebar.cc
index 3b30ac757..3af0dc82c 100644
--- a/selfdrive/ui/sidebar.cc
+++ b/selfdrive/ui/sidebar.cc
@@ -21,6 +21,27 @@ static void ui_draw_sidebar_home_button(UIState *s) {
const int home_btn_xr = !s->scene.uilayout_sidebarcollapsed ? home_btn_x : -(sbr_w);
ui_draw_image(s->vg, home_btn_xr, home_btn_y, home_btn_w, home_btn_h, s->img_button_home, homeActive ? 1.0f : 0.65f);
+
+ if (s->dragon_updating) {
+ nvgBeginPath(s->vg);
+ nvgCircle(s->vg, home_btn_xr + home_btn_w/2, home_btn_y + home_btn_h/2, 90);
+ nvgFillColor(s->vg, nvgRGBA(255, 255, 255, s->scene.alert_rate));
+ nvgFill(s->vg);
+
+ nvgFillColor(s->vg, nvgRGBA(0, 0, 0, s->scene.alert_rate));
+ nvgFontSize(s->vg, (strcmp(s->dragon_locale, "zh-TW") == 0? 60 : strcmp(s->dragon_locale, "zh-CN") == 0? 60 : 46));
+ nvgFontFaceId(s->vg, s->font_sans_bold);
+ nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
+ nvgTextBox(s->vg, home_btn_xr, home_btn_y + home_btn_h/2, home_btn_w,
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "更新中" : strcmp(s->dragon_locale, "zh-CN") == 0? "更新中" : "UPDATING"),
+ NULL);
+
+ s->scene.alert_rate += 5*s->scene.alert_type;
+
+ if (s->scene.alert_rate == 0 || s->scene.alert_rate == 255) {
+ s->scene.alert_type *= -1;
+ }
+ }
}
static void ui_draw_sidebar_network_strength(UIState *s) {
@@ -38,6 +59,35 @@ static void ui_draw_sidebar_network_strength(UIState *s) {
ui_draw_image(s->vg, network_img_x, network_img_y, network_img_w, network_img_h, s->img_network[img_idx], 1.0f);
}
+static void ui_draw_sidebar_ip_addr(UIState *s) {
+ const int network_ip_w = 176;
+ const int network_ip_x = !s->scene.uilayout_sidebarcollapsed ? 54 : -(sbr_w);
+ const int network_ip_y = 255;
+
+ char network_ip_str[15];
+ snprintf(network_ip_str, sizeof(network_ip_str), "%s", s->scene.ipAddr);
+ nvgFillColor(s->vg, COLOR_WHITE);
+ nvgFontSize(s->vg, 34);
+ nvgFontFaceId(s->vg, s->font_sans_regular);
+ nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
+ nvgTextBox(s->vg, network_ip_x, network_ip_y, network_ip_w, network_ip_str, NULL);
+}
+
+static void ui_draw_sidebar_battery_text(UIState *s) {
+ const int battery_img_h = 36;
+ const int battery_img_w = 96;
+ const int battery_img_x = !s->scene.uilayout_sidebarcollapsed ? 150 : -(sbr_w);
+ const int battery_img_y = 305;
+
+ char battery_str[7];
+ snprintf(battery_str, sizeof(battery_str), "%d%%%s", s->scene.batteryPercent, s->scene.batteryCharging ? "+" : "-");
+ nvgFillColor(s->vg, COLOR_WHITE);
+ nvgFontSize(s->vg, 44);
+ nvgFontFaceId(s->vg, s->font_sans_regular);
+ nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
+ nvgTextBox(s->vg, battery_img_x, battery_img_y, battery_img_w, battery_str, NULL);
+}
+
static void ui_draw_sidebar_battery_icon(UIState *s) {
const int battery_img_h = 36;
const int battery_img_w = 76;
@@ -61,7 +111,7 @@ static void ui_draw_sidebar_network_type(UIState *s) {
{cereal::ThermalData::NetworkType::CELL4_G, "4G"},
{cereal::ThermalData::NetworkType::CELL5_G, "5G"}};
const int network_x = !s->scene.uilayout_sidebarcollapsed ? 50 : -(sbr_w);
- const int network_y = 273;
+ const int network_y = 303;
const int network_w = 100;
const int network_h = 100;
const char *network_type = network_type_map[s->scene.networkType];
@@ -104,13 +154,13 @@ static void ui_draw_sidebar_metric(UIState *s, const char* label_str, const char
nvgTextBox(s->vg, metric_x + 50, metric_y + 50, metric_w - 60, value_str, NULL);
nvgFillColor(s->vg, COLOR_WHITE);
- nvgFontSize(s->vg, 48);
+ nvgFontSize(s->vg, 46);
nvgFontFaceId(s->vg, s->font_sans_regular);
nvgTextAlign(s->vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
nvgTextBox(s->vg, metric_x + 50, metric_y + 50 + 66, metric_w - 60, label_str, NULL);
} else {
nvgFillColor(s->vg, COLOR_WHITE);
- nvgFontSize(s->vg, 48);
+ nvgFontSize(s->vg, 46);
nvgFontFaceId(s->vg, s->font_sans_bold);
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
nvgTextBox(s->vg, metric_x + 35, metric_y + (strchr(message_str, '\n') ? 40 : 50), metric_w - 50, message_str, NULL);
@@ -129,7 +179,8 @@ static void ui_draw_sidebar_temp_metric(UIState *s) {
const int temp_y_offset = 0;
snprintf(temp_value_str, sizeof(temp_value_str), "%d", s->scene.paTemp);
snprintf(temp_value_unit, sizeof(temp_value_unit), "%s", "°C");
- snprintf(temp_label_str, sizeof(temp_label_str), "%s", "TEMP");
+ snprintf(temp_label_str, sizeof(temp_label_str), "%s",
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "溫度" : strcmp(s->dragon_locale, "zh-CN") == 0? "温度" : "TEMP"));
strcat(temp_value_str, temp_value_unit);
ui_draw_sidebar_metric(s, temp_label_str, temp_value_str, temp_severity_map[s->scene.thermalStatus], temp_y_offset, NULL);
@@ -147,10 +198,10 @@ static void ui_draw_sidebar_panda_metric(UIState *s) {
if (s->started){
if (s->scene.satelliteCount < 6) {
panda_severity = 1;
- snprintf(panda_message_str, sizeof(panda_message_str), "%s", "VEHICLE\nNO GPS");
+ snprintf(panda_message_str, sizeof(panda_message_str), "%s %d", "VEHICLE\nGPS:", s->scene.satelliteCount);
} else if (s->scene.satelliteCount >= 6) {
panda_severity = 0;
- snprintf(panda_message_str, sizeof(panda_message_str), "%s", "VEHICLE\nGOOD GPS");
+ snprintf(panda_message_str, sizeof(panda_message_str), "%s %d", "VEHICLE\nGPS:", s->scene.satelliteCount);
}
} else {
panda_severity = 0;
@@ -160,14 +211,16 @@ static void ui_draw_sidebar_panda_metric(UIState *s) {
ui_draw_sidebar_metric(s, NULL, NULL, panda_severity, panda_y_offset, panda_message_str);
}
-
static void ui_draw_sidebar_connectivity(UIState *s) {
if (s->scene.athenaStatus == NET_DISCONNECTED) {
- ui_draw_sidebar_metric(s, NULL, NULL, 1, 180+158, "CONNECT\nOFFLINE");
+ ui_draw_sidebar_metric(s, NULL, NULL, 1, 180+158,
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "CONNECT\n已離線" : strcmp(s->dragon_locale, "zh-CN") == 0? "CONNECT\n已离线" : "CONNECT\nOFFLINE"));
} else if (s->scene.athenaStatus == NET_CONNECTED) {
- ui_draw_sidebar_metric(s, NULL, NULL, 0, 180+158, "CONNECT\nONLINE");
+ ui_draw_sidebar_metric(s, NULL, NULL, 0, 180+158,
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "CONNECT\n已連線" : strcmp(s->dragon_locale, "zh-CN") == 0? "CONNECT\n已连线" : "CONNECT\nONLINE"));
} else {
- ui_draw_sidebar_metric(s, NULL, NULL, 2, 180+158, "CONNECT\nERROR");
+ ui_draw_sidebar_metric(s, NULL, NULL, 2, 180+158,
+ (strcmp(s->dragon_locale, "zh-TW") == 0? "CONNECT\n錯誤" : strcmp(s->dragon_locale, "zh-CN") == 0? "CONNECT\n错误" : "CONNECT\nERROR"));
}
}
@@ -179,7 +232,8 @@ void ui_draw_sidebar(UIState *s) {
ui_draw_sidebar_settings_button(s);
ui_draw_sidebar_home_button(s);
ui_draw_sidebar_network_strength(s);
- ui_draw_sidebar_battery_icon(s);
+ ui_draw_sidebar_ip_addr(s);
+ ui_draw_sidebar_battery_text(s);
ui_draw_sidebar_network_type(s);
ui_draw_sidebar_temp_metric(s);
ui_draw_sidebar_panda_metric(s);
diff --git a/selfdrive/ui/spinner/spinner b/selfdrive/ui/spinner/spinner
index c8f8e68ec..c313a0f81 100755
Binary files a/selfdrive/ui/spinner/spinner and b/selfdrive/ui/spinner/spinner differ
diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc
index c700dad0c..a5556934a 100644
--- a/selfdrive/ui/ui.cc
+++ b/selfdrive/ui/ui.cc
@@ -16,6 +16,7 @@
#include "common/params.h"
static int last_brightness = -1;
+char last_modified[20];
static void set_brightness(UIState *s, int brightness) {
if (last_brightness != brightness && (s->awake || brightness == 0)) {
FILE *f = fopen("/sys/class/leds/lcd-backlight/brightness", "wb");
@@ -42,7 +43,7 @@ static void set_awake(UIState *s, bool awake) {
#ifdef QCOM
if (awake) {
// 30 second timeout at 30 fps
- s->awake_timeout = 30*30;
+ s->awake_timeout = s->dragon_dashcam_impact_detect_started? 60*30 : (s->dragon_ui_screen_off_driving && s->started)? 10*30 : 30*30;
}
if (s->awake != awake) {
s->awake = awake;
@@ -121,6 +122,46 @@ static void handle_driver_view_touch(UIState *s, int touch_x, int touch_y) {
int err = write_db_value("IsDriverViewEnabled", "0", 1);
}
+static bool handle_dp_btn_touch(UIState *s, int touch_x, int touch_y) {
+ //dfButton manager // code below thanks to kumar: https://github.com/arne182/openpilot/commit/71d5aac9f8a3f5942e89634b20cbabf3e19e3e78
+ if (s->started && s->active_app != cereal::UiLayoutState::App::SETTINGS) {
+ if ((int)s->dragon_df_mode > 0 && touch_x >= df_btn_x && touch_x <= (df_btn_x + df_btn_w) && touch_y >= df_btn_y && touch_y <= (df_btn_y + df_btn_h)) {
+ s->scene.uilayout_sidebarcollapsed = true; // collapse sidebar when tapping df button
+ int val = s->dragon_df_mode;
+ val++;
+ if (val >= 4) {
+ val = 1;
+ }
+ s->dragon_df_mode = val;
+ char str[1];
+ sprintf(str, "%d", val);
+ write_db_value("DragonDynamicFollow", str, 1);
+
+ char time_str[11];
+ snprintf(time_str, 11, "%lu", time(NULL));
+ write_db_value("DragonLastModified", time_str, 11);
+ return true;
+ } else if ((int)s->dragon_ap_mode > 0 && touch_x >= ap_btn_x && touch_x <= (ap_btn_x + ap_btn_w) && touch_y >= ap_btn_y && touch_y <= (ap_btn_y + ap_btn_h)) {
+ s->scene.uilayout_sidebarcollapsed = true; // collapse sidebar when tapping ap button
+ int val = s->dragon_ap_mode;
+ val++;
+ if (val >= 4) {
+ val = 1;
+ }
+ s->dragon_ap_mode = val;
+ char str[1];
+ sprintf(str, "%d", val);
+ write_db_value("DragonAccelProfile", str, 1);
+
+ char time_str[11];
+ snprintf(time_str, 11, "%lu", time(NULL));
+ write_db_value("DragonLastModified", time_str, 11);
+ return true;
+ }
+ }
+ return false;
+}
+
static void handle_vision_touch(UIState *s, int touch_x, int touch_y) {
if (s->started && (touch_x >= s->scene.ui_viz_rx - bdr_s)
&& (s->active_app != cereal::UiLayoutState::App::SETTINGS)) {
@@ -167,6 +208,15 @@ static int read_param_uint64(uint64_t* dest, const char* param_name, bool persis
return result;
}
+static void read_param_string(char* param, const char* param_name, bool persistent_param = false) {
+ char *s;
+ const int result = read_db_value(param_name, &s, NULL);
+ if (result == 0) {
+ snprintf(param, 128, "%s", s);
+ free(s);
+ }
+}
+
static void read_param_bool_timeout(bool* param, const char* param_name, int* timeout, bool persistent_param = false) {
if (*timeout > 0){
(*timeout)--;
@@ -201,6 +251,15 @@ static int write_param_float(float param, const char* param_name, bool persisten
return write_db_value(param_name, s, MIN(size, sizeof(s)), persistent_param);
}
+static void read_param_string_timeout(char* param, const char* param_name, int* timeout, bool persistent_param = false) {
+ if (*timeout > 0){
+ (*timeout)--;
+ } else {
+ read_param_string(param, param_name, persistent_param);
+ *timeout = 2 * UI_FREQ; // 0.5Hz
+ }
+}
+
static void update_offroad_layout_timeout(UIState *s, int* timeout) {
if (*timeout > 0) {
(*timeout)--;
@@ -227,6 +286,7 @@ static void ui_init(UIState *s) {
s->driverstate_sock = SubSocket::create(s->ctx, "driverState");
s->dmonitoring_sock = SubSocket::create(s->ctx, "dMonitoringState");
s->offroad_sock = PubSocket::create(s->ctx, "offroadLayout");
+ s->carstate_sock = SubSocket::create(s->ctx, "carState");
assert(s->model_sock != NULL);
assert(s->controlsstate_sock != NULL);
@@ -239,6 +299,7 @@ static void ui_init(UIState *s) {
assert(s->driverstate_sock != NULL);
assert(s->dmonitoring_sock != NULL);
assert(s->offroad_sock != NULL);
+ assert(s->carstate_sock != NULL);
s->poller = Poller::create({
s->model_sock,
@@ -250,7 +311,8 @@ static void ui_init(UIState *s) {
s->health_sock,
s->ubloxgnss_sock,
s->driverstate_sock,
- s->dmonitoring_sock
+ s->dmonitoring_sock,
+ s->carstate_sock
});
#ifdef SHOW_SPEEDLIMIT
@@ -323,10 +385,65 @@ static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs,
read_param_bool(&s->longitudinal_control, "LongitudinalControl");
read_param_bool(&s->limit_set_speed, "LimitSetSpeed");
+ // dp
+ read_param_string(s->dragon_last_modified, "DragonLastModified");
+ strncpy(last_modified, s->dragon_last_modified, sizeof(last_modified));
+
+ read_param_string(s->dragon_locale, "DragonLocale");
+ read_param_float(&s->dragon_ui_volume_boost, "DragonUIVolumeBoost");
+ read_param_bool(&s->dragon_waze_mode, "DragonWazeMode");
+ read_param_bool(&s->dragon_updating, "DragonUpdating");
+ read_param_uint64(&s->dragon_df_mode, "DragonDynamicFollow");
+ read_param_uint64(&s->dragon_ap_mode, "DragonAccelProfile");
+ read_param_bool(&s->dragon_ui_screen_off_reversing, "DragonUIScreenOffReversing");
+ read_param_bool(&s->dragon_ui_screen_off_driving, "DragonUIScreenOffDriving");
+ read_param_uint64(&s->dragon_ui_brightness, "DragonUIBrightness");
+ read_param_bool(&s->dragon_dashcam_impact_detect_started, "DragonDashcamImpactDetectStarted");
+
+ if (s->dragon_waze_mode) {
+ s->dragon_ui_speed = false;
+ s->dragon_ui_event = false;
+ s->dragon_ui_maxspeed = false;
+ s->dragon_ui_face = false;
+ s->dragon_ui_dev = false;
+ s->dragon_ui_dev_mini = false;
+ s->dragon_enable_dashcam = false;
+ s->dragon_driving_ui = false;
+ s->dragon_ui_lane = false;
+ s->dragon_ui_lead = false;
+ s->dragon_ui_path = false;
+ s->dragon_ui_blinker = false;
+ s->dragon_ui_dm_view = false;
+ } else {
+ read_param_bool(&s->dragon_enable_dm, "DragonEnableDriverMonitoring");
+ if (!s->dragon_enable_dm) {
+ s->dragon_ui_face = false;
+ } else {
+ read_param_bool(&s->dragon_ui_face, "DragonUIFace");
+ }
+ read_param_bool(&s->dragon_ui_speed, "DragonUISpeed");
+ read_param_bool(&s->dragon_ui_event, "DragonUIEvent");
+ read_param_bool(&s->dragon_ui_maxspeed, "DragonUIMaxSpeed");
+ read_param_bool(&s->dragon_ui_dev, "DragonUIDev");
+ read_param_bool(&s->dragon_ui_dev_mini, "DragonUIDevMini");
+ read_param_bool(&s->dragon_enable_dashcam, "DragonEnableDashcam");
+ read_param_bool(&s->dragon_driving_ui, "DragonDrivingUI");
+ read_param_bool(&s->dragon_ui_lane, "DragonUILane");
+ read_param_bool(&s->dragon_ui_lead, "DragonUILead");
+ read_param_bool(&s->dragon_ui_path, "DragonUIPath");
+ read_param_bool(&s->dragon_ui_blinker, "DragonUIBlinker");
+ read_param_bool(&s->dragon_ui_dm_view, "DragonUIDMView");
+ }
+
// Set offsets so params don't get read at the same time
s->longitudinal_control_timeout = UI_FREQ / 3;
s->is_metric_timeout = UI_FREQ / 2;
s->limit_set_speed_timeout = UI_FREQ;
+
+ // dp
+ s->dragon_last_modified_timeout = UI_FREQ / 4;
+ s->dragon_updating_timeout = UI_FREQ / 5;
+ s->dragon_dashcam_impact_detect_started_timeout = UI_FREQ / 6;
}
static PathData read_path(cereal::ModelData::PathData::Reader pathp) {
@@ -395,6 +512,10 @@ void handle_message(UIState *s, Message* msg) {
scene.gps_planner_active = data.getGpsPlannerActive();
scene.monitoring_active = data.getDriverMonitoringOn();
+ // dp - steer data
+ s->scene.angleSteers = data.getAngleSteers();
+ s->scene.angleSteersDes = data.getAngleSteersDes();
+
scene.decel_for_model = data.getDecelForModel();
auto alert_sound = data.getAlertSound();
const auto sound_none = cereal::CarControl::HUDControl::AudibleAlert::NONE;
@@ -405,6 +526,9 @@ void handle_message(UIState *s, Message* msg) {
if (alert_sound != sound_none){
play_alert_sound(alert_sound);
s->alert_type = data.getAlertType();
+ if (s->dragon_ui_screen_off_driving) {
+ set_awake(s, true);
+ }
}
s->alert_sound = alert_sound;
}
@@ -492,7 +616,7 @@ void handle_message(UIState *s, Message* msg) {
scene.freeSpace = data.getFreeSpace();
scene.thermalStatus = data.getThermalStatus();
scene.paTemp = data.getPa0();
-
+ snprintf(scene.ipAddr, sizeof(scene.ipAddr), "%s", data.getIpAddr().cStr());
s->thermal_started = data.getStarted();
} else if (which == cereal::Event::UBLOX_GNSS) {
auto data = event.getUbloxGnss();
@@ -513,6 +637,16 @@ void handle_message(UIState *s, Message* msg) {
scene.is_rhd = data.getIsRHD();
scene.awareness_status = data.getAwarenessStatus();
s->preview_started = data.getIsPreview();
+ } else if (which == cereal::Event::CAR_STATE) {
+ auto data = event.getCarState();
+
+ if(scene.leftBlinker!=data.getLeftBlinker() || scene.rightBlinker!=data.getRightBlinker()) {
+ scene.blinker_blinkingrate = 100;
+ }
+ scene.leftBlinker = data.getLeftBlinker();
+ scene.rightBlinker = data.getRightBlinker();
+ scene.brakeLights = data.getBrakeLights();
+ scene.isReversing = data.getGearShifter() == cereal::CarState::GearShifter::REVERSE;
}
s->started = s->thermal_started || s->preview_started ;
@@ -915,7 +1049,13 @@ int main(int argc, char* argv[]) {
s->scene.satelliteCount = -1;
s->started = false;
s->vision_seen = false;
-
+ // dp
+ s->scene.alert_rate = 0;
+ s->scene.alert_type = 1;
+ char locale[10];
+ if (s->dragon_ui_screen_off_driving) {
+ set_awake(s, true);
+ }
while (!do_exit) {
bool should_swap = false;
if (!s->started) {
@@ -927,11 +1067,15 @@ int main(int argc, char* argv[]) {
double u1 = millis_since_boot();
// light sensor is only exposed on EONs
- float clipped_brightness = (s->light_sensor*brightness_m) + brightness_b;
- if (clipped_brightness > 512) clipped_brightness = 512;
- smooth_brightness = clipped_brightness * 0.01 + smooth_brightness * 0.99;
- if (smooth_brightness > 255) smooth_brightness = 255;
- set_brightness(s, (int)smooth_brightness);
+ if (s->dragon_ui_brightness == 0) {
+ float clipped_brightness = (s->light_sensor*brightness_m) + brightness_b;
+ if (clipped_brightness > 512) clipped_brightness = 512;
+ smooth_brightness = clipped_brightness * 0.01 + smooth_brightness * 0.99;
+ if (smooth_brightness > 255) smooth_brightness = 255;
+ set_brightness(s, (int)smooth_brightness);
+ } else {
+ set_brightness(s, (int)(255*s->dragon_ui_brightness*0.01));
+ }
// resize vision for collapsing sidebar
const bool hasSidebar = !s->scene.uilayout_sidebarcollapsed;
@@ -939,20 +1083,37 @@ int main(int argc, char* argv[]) {
s->scene.ui_viz_rw = hasSidebar ? box_w : (box_w + sbr_w - (bdr_s * 2));
s->scene.ui_viz_ro = hasSidebar ? -(sbr_w - 6 * bdr_s) : 0;
- // poll for touch events
- int touch_x = -1, touch_y = -1;
- int touched = touch_poll(&touch, &touch_x, &touch_y, 0);
- if (touched == 1) {
- set_awake(s, true);
- handle_sidebar_touch(s, touch_x, touch_y);
- handle_vision_touch(s, touch_x, touch_y);
+ if (s->vision_connected && s->dragon_waze_mode) {
+ // always collapsed sidebar when vision is connect and in waze mode
+ s->scene.uilayout_sidebarcollapsed = true;
+ } else {
+ // poll for touch events
+ int touch_x = -1, touch_y = -1;
+ int touched = touch_poll(&touch, &touch_x, &touch_y, 0);
+ if (touched == 1) {
+ if (s->dragon_ui_screen_off_driving && s->awake_timeout == 0) {
+ set_awake(s, true);
+ } else {
+ set_awake(s, true);
+ if (!handle_dp_btn_touch(s, touch_x, touch_y)) {
+ handle_sidebar_touch(s, touch_x, touch_y);
+ handle_vision_touch(s, touch_x, touch_y);
+ }
+ }
+ }
}
if (!s->started) {
// always process events offroad
check_messages(s);
} else {
- set_awake(s, true);
+ if (s->dragon_ui_screen_off_driving) {
+ // do nothing
+ } else if (s->scene.isReversing && s->dragon_ui_screen_off_reversing) {
+ set_awake(s, false);
+ } else {
+ set_awake(s, true);
+ }
// Car started, fetch a new rgb image from ipc
if (s->vision_connected){
ui_update(s);
@@ -995,6 +1156,10 @@ int main(int argc, char* argv[]) {
s->volume_timeout--;
} else {
int volume = fmin(MAX_VOLUME, MIN_VOLUME + s->scene.v_ego / 5); // up one notch every 5 m/s
+ if (s->dragon_ui_volume_boost > 0 || s->dragon_ui_volume_boost < 0) {
+ volume = volume * (1 + s->dragon_ui_volume_boost /100);
+ volume = volume > MAX_VOLUME? MAX_VOLUME : volume;
+ }
set_volume(volume);
s->volume_timeout = 5 * UI_FREQ;
}
@@ -1043,6 +1208,59 @@ int main(int argc, char* argv[]) {
}
update_offroad_layout_timeout(s, &s->offroad_layout_timeout);
+ // dp
+ read_param_bool_timeout(&s->dragon_updating, "DragonUpdating", &s->dragon_updating_timeout);
+ read_param_string_timeout(s->dragon_last_modified, "DragonLastModified", &s->dragon_last_modified_timeout);
+ read_param_bool_timeout(&s->dragon_dashcam_impact_detect_started, "DragonDashcamImpactDetectStarted", &s->dragon_dashcam_impact_detect_started_timeout);
+ if (strcmp(last_modified, s->dragon_last_modified) != 0) {
+ strncpy(last_modified, s->dragon_last_modified, sizeof(last_modified));
+
+ read_param_string(s->dragon_locale, "DragonLocale");
+ read_param_bool(&s->dragon_waze_mode, "DragonWazeMode");
+
+ read_param_float(&s->dragon_ui_volume_boost, "DragonUIVolumeBoost");
+ read_param_uint64(&s->dragon_df_mode, "DragonDynamicFollow");
+ read_param_uint64(&s->dragon_ap_mode, "DragonAccelProfile");
+ read_param_bool(&s->dragon_ui_screen_off_reversing, "DragonUIScreenOffReversing");
+ read_param_bool(&s->dragon_ui_screen_off_driving, "DragonUIScreenOffDriving");
+ read_param_uint64(&s->dragon_ui_brightness, "DragonUIBrightness");
+
+ if (s->dragon_waze_mode) {
+ s->dragon_ui_speed = false;
+ s->dragon_ui_event = false;
+ s->dragon_ui_maxspeed = false;
+ s->dragon_ui_face = false;
+ s->dragon_ui_dev = false;
+ s->dragon_ui_dev_mini = false;
+ s->dragon_enable_dashcam = false;
+ s->dragon_driving_ui = false;
+ s->dragon_ui_lane = false;
+ s->dragon_ui_lead = false;
+ s->dragon_ui_path = false;
+ s->dragon_ui_blinker = false;
+ s->dragon_ui_dm_view = false;
+ } else {
+ read_param_bool(&s->dragon_enable_dm, "DragonEnableDriverMonitoring");
+ if (!s->dragon_enable_dm) {
+ s->dragon_ui_face = false;
+ } else {
+ read_param_bool(&s->dragon_ui_face, "DragonUIFace");
+ }
+ read_param_bool(&s->dragon_ui_speed, "DragonUISpeed");
+ read_param_bool(&s->dragon_ui_event, "DragonUIEvent");
+ read_param_bool(&s->dragon_ui_maxspeed, "DragonUIMaxSpeed");
+ read_param_bool(&s->dragon_ui_dev, "DragonUIDev");
+ read_param_bool(&s->dragon_ui_dev_mini, "DragonUIDevMini");
+ read_param_bool(&s->dragon_enable_dashcam, "DragonEnableDashcam");
+ read_param_bool(&s->dragon_driving_ui, "DragonDrivingUI");
+ read_param_bool(&s->dragon_ui_lane, "DragonUILane");
+ read_param_bool(&s->dragon_ui_lead, "DragonUILead");
+ read_param_bool(&s->dragon_ui_path, "DragonUIPath");
+ read_param_bool(&s->dragon_ui_blinker, "DragonUIBlinker");
+ read_param_bool(&s->dragon_ui_dm_view, "DragonUIDMView");
+ }
+ }
+
pthread_mutex_unlock(&s->lock);
// the bg thread needs to be scheduled, so the main thread needs time without the lock
diff --git a/selfdrive/ui/ui.hpp b/selfdrive/ui/ui.hpp
index 771b5501c..0a8df9c3c 100644
--- a/selfdrive/ui/ui.hpp
+++ b/selfdrive/ui/ui.hpp
@@ -74,6 +74,18 @@ const int home_btn_w = 180;
const int home_btn_x = 60;
const int home_btn_y = vwp_h - home_btn_h - 40;
+// dp
+// dynamic follow btn
+const int df_btn_h = 180;
+const int df_btn_w = 180;
+const int df_btn_x = 1650;
+const int df_btn_y = 750;
+// accel profile btn
+const int ap_btn_h = 180;
+const int ap_btn_w = 180;
+const int ap_btn_x = 1450;
+const int ap_btn_y = 750;
+
const int UI_FREQ = 30; // Hz
const int MODEL_PATH_MAX_VERTICES_CNT = 98;
@@ -160,6 +172,23 @@ typedef struct UIScene {
cereal::HealthData::HwType hwType;
int satelliteCount;
uint8_t athenaStatus;
+
+ // dp
+ // for minimal UI
+ float angleSteersDes;
+ float angleSteers;
+ char ipAddr[20];
+ int alert_rate;
+ int alert_type;
+ // for black screen on reversing
+ bool isReversing;
+
+ // for blinker, from kegman
+ bool leftBlinker;
+ bool rightBlinker;
+ bool brakeLights;
+ int blinker_blinkingrate;
+
} UIScene;
typedef struct {
@@ -296,6 +325,38 @@ typedef struct UIState {
model_path_vertices_data model_path_vertices[MODEL_LANE_PATH_CNT * 2];
track_vertices_data track_vertices[2];
+
+ // dp
+ SubSocket *carstate_sock;
+ int dragon_updating_timeout;
+ int dragon_last_modified_timeout;
+ int dragon_dashcam_impact_detect_started_timeout;
+
+ bool dragon_ui_speed;
+ bool dragon_ui_event;
+ bool dragon_ui_maxspeed;
+ bool dragon_ui_face;
+ bool dragon_ui_dev;
+ bool dragon_ui_dev_mini;
+ bool dragon_enable_dashcam;
+ float dragon_ui_volume_boost;
+ bool dragon_driving_ui;
+ bool dragon_ui_lane;
+ bool dragon_ui_lead;
+ bool dragon_ui_path;
+ bool dragon_ui_blinker;
+ bool dragon_waze_mode;
+ bool dragon_ui_dm_view;
+ bool dragon_updating;
+ uint64_t dragon_df_mode;
+ uint64_t dragon_ap_mode;
+ bool dragon_enable_dm;
+ char dragon_locale[20];
+ bool dragon_ui_screen_off_reversing;
+ char dragon_last_modified[20];
+ bool dragon_ui_screen_off_driving;
+ uint64_t dragon_ui_brightness;
+ bool dragon_dashcam_impact_detect_started;
} UIState;
// API
diff --git a/selfdrive/updated.py b/selfdrive/updated.py
index c31ab9560..cf175a29a 100755
--- a/selfdrive/updated.py
+++ b/selfdrive/updated.py
@@ -33,6 +33,7 @@ from pathlib import Path
import fcntl
import threading
from cffi import FFI
+from common.dp import is_online
from common.basedir import BASEDIR
from common.params import Params
@@ -116,8 +117,15 @@ def set_update_available_params(new_version=False):
params.put("LastUpdateTime", t.encode('utf8'))
if new_version:
+ branch_name = run(["git", "rev-parse", "--abbrev-ref", "HEAD"], OVERLAY_MERGED).rstrip()
+ if branch_name == "testing":
+ postfix = ''
+ elif branch_name == "devel-i18n":
+ postfix = '-DEV'
+ else:
+ postfix = '-REL'
try:
- with open(os.path.join(FINALIZED, "RELEASES.md"), "rb") as f:
+ with open(os.path.join(FINALIZED, f"CHANGELOGS{postfix}.md"), "rb") as f:
r = f.read()
r = r[:r.find(b'\n\n')] # Slice latest release notes
params.put("ReleaseNotes", r + b"\n")
diff --git a/selfdrive/version.py b/selfdrive/version.py
index b45fe384b..8cb428ff9 100644
--- a/selfdrive/version.py
+++ b/selfdrive/version.py
@@ -64,7 +64,8 @@ try:
dirty = dirty or (subprocess.call(["git", "diff-index", "--quiet", branch, "--"]) != 0)
if dirty:
- dirty_files = subprocess.check_output(["git", "diff-index", branch, "--"], encoding='utf8')
+ #dirty_files = subprocess.check_output(["git", "diff-index", branch, "--"], encoding='utf8')
+ dirty_files = ""
commit = subprocess.check_output(["git", "rev-parse", "--verify", "HEAD"], encoding='utf8').rstrip()
origin_commit = subprocess.check_output(["git", "rev-parse", "--verify", branch], encoding='utf8').rstrip()
cloudlog.event("dirty comma branch", version=version, dirty=dirty, origin=origin, branch=branch, dirty_files=dirty_files, commit=commit, origin_commit=origin_commit)