diff --git a/.gitignore b/.gitignore index f4932ed4f..ec8f37fdc 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,7 @@ selfdrive/boardd/boardd selfdrive/logcatd/logcatd selfdrive/mapd/default_speeds_by_region.json selfdrive/proclogd/proclogd -selfdrive/ui/_ui + selfdrive/test/longitudinal_maneuvers/out selfdrive/visiond/visiond selfdrive/loggerd/loggerd diff --git a/CHANGELOGS-DEV.md b/CHANGELOGS-DEV.md new file mode 100644 index 000000000..480ec4c87 --- /dev/null +++ b/CHANGELOGS-DEV.md @@ -0,0 +1,664 @@ +dragonpilot 0.8.5-4 +======================== +* Added multiple toggles. +* Code clean up. +* Android app support. (see selfdrive/dragonpilot/HOWTO-APPD.md) +* Better support for VW MPQ (Thanks to @Saber) + +dragonpilot 0.8.5-3 +======================== +* Added Jetson support toggle. +* Added Steering Ratio controller. +* Reduce Following Profile to 3 modes only. (1.8s / 1.5s / 1.2s) +* Bug fixes. + +dragonpilot 0.8.5-2 +======================== +* Added black panda simulation toggle. +* Added No GPS toggle. +* Added No Battery Toggle. +* Bug fixes. + +dragonpilot 0.8.5-1 +======================== +* Based on openpilot 0.8.5 devel. +* 基於 openpilot 0.8.5 devel. +* Support 1+3t / C2 / Jetson Xavier NX. +* 支持 1+3t / C2 / Jetson Xavier NX. +* No White/Grey Panda Support. +* 不支持白灰熊. + +dragonpilot 0.8.4-3 +======================== +* 簡化 1+3t 安裝方法. (請查閱 HOWTO-ONEPLUS.md) +* Simplied 1+3t installation. (See HOWTO-ONEPLUS.md) +* 加回舊 ssh 登錄. +* Good old ssh key. +* 修復本田錯誤. (感謝 @loveloveses) +* Fixed Honda bug. (Thanks to @loveloveses) + +dragonpilot 0.8.4-2 +======================== +* 加回可調整加速/跟車設定. +* Added back Accel/Following Profile. +* 支持 Headless Jetson Xavier NX (https://github.com/efinilan/xnxpilot.git) +* Support Headless Jetson Xavier NX (https://github.com/efinilan/xnxpilot.git) +* 支持 1+3t (需額外安裝手續) +* Support 1+3t (Require additional install procedure) +* 支持白/灰熊 +* Support White/Grey Panda. + +dragonpilot 0.8.4-1 +======================== +* 基於 openpilot 0.8.4 devel. +* Based on openpilot 0.8.4 devel. + +dragonpilot 0.8.1 +======================== +* 基於最新 openpilot 0.8.1 devel. +* Based on latest openpilot 0.8.1 devel. +* 加入行車記錄按鈕。(感謝 @toyboxZ 提供) +* Added REC screen button. (Thanks to @toyboxZ) + +dragonpilot 0.8.0 +======================== +* 基於最新 openpilot 0.8.0 devel. +* Based on latest openpilot 0.8.0 devel. +* 加入 git 錯誤修正。(感謝 @toyboxZ 提供) +* Added git error fix. (Thanks to @toyboxZ) + +dragonpilot 0.7.10.1 +======================== +* HYUNDAI_GENESIS 使用 INDI 控制器。(感謝 @donfyffe 提供) +* HYUNDAI_GENESIS uses INDI controller. (Thanks to @donfyffe) +* HYUNDAI_GENESIS 加入 Cruise 按紐 和 lkMode 支援。(感謝 @donfyffe 建議) +* HYUNDAI_GENESIS added Cruise button event and lkMode feature. (Thanks to @donfyffe) +* 支援台灣版 2018 Huyndai IONIQ + smart MDPS (dp_hkg_smart_mdps) (感謝 @andy741217 提供) +* Support 2018 Taiwan Hyundai IONIQ + smart MDPS (dp_hkg_smart_mdps) (Thanks to @andy741217) +* 使用 openpilot v0.8 的模型。(感謝 @eisenheim) +* Use openpilot v0.8 model. (Thanks to @eisenheim) +* 加入 0.8 測試版的部分優化。 +* Added optimizations from pre-0.8. +* 加入 dp_honda_eps_mod 設定來使用更高的扭力 (需 eps mod)。(感謝 @Wuxl_369 提供) +* Added dp_honda_eps_mod setting to enable higher torque (eps mod required). (Thanks to @Wuxl_369) +* 修正 VW 對白/灰熊的支援 (感謝 @lirudy 提供) +* Fixed issue with white/grey panda support for VW (Thanks to @lirudy) +* GENESIS_G70 優化 (感謝 @sebastian4k 提供) +* GENESIS_G70 Optimisation (Thanks to @sebastian4k) +* HYUNDAI_GENESIS 優化 (感謝 @donfyffe 提供) +* HYUNDAI_GENESIS Optimisation (Thanks to @donfyffe) +* 加入 Dynamic gas Lite。(感謝 @toyboxZ 提供) +* Added Dynamic Gas Lite. (Thanks to @toyboxZ) +* 加入來自 afa 的 Honda inspire, accord, crv SnG 優化。(感謝 @menwenliang 提供) +* Added Honda inspire, accord, crv SnG optimisation from afa fork. (Thanks to @menwenliang) +* 加入 dp_toyota_lowest_cruise_override_vego。(感謝 @toyboxZ 提供) +* Added dp_toyota_lowest_cruise_override_vego. (Thanks to @toyboxZ) + +dragonpilot 0.7.10.0 +======================== +* 基於最新 openpilot 0.7.10 devel. +* Based on latest openpilot 0.7.10 devel. +* 修正 Prius 特定情況下無法操控方向盤的問題。 +* Fixed unable to regain Prius steering control under certain condition. +* 更新 VW MQB 的支援。(需執行 scripts/vw.sh 腳本) +* Updated support of VW MQB. (scripts/vw.sh script required) +* 新增 2018 China Toyota CHR 指紋v2。(感謝 @xiaohongcheung 提供) +* Added 2018 China Toyota CHR FPv2. (Thanks to @xiaohongcheung) +* 加入 Headunit Reloaded Android Auto App 支援。(感謝 @Ninjaa 提供) +* Added Headunit Reloaded Android Auto App Support. (Thanks to @Ninjaa) +* 優化 nanovg。(感謝 @piggy 提供) +* Optomized nanovg. (Thanks to @piggy) +* 加入 complete_setup.sh (感謝 @深鲸希西 提供) +* Added complete_setup.sh (Thanks to @深鲸希西) +* Based on latest openpilot 0.7.10 devel. +* 修正 EON 接 PC/USB 充電器時仍會自動關機的錯誤。(感謝 @小愛 回報) +* Fixed auto shutdown issue when EON connect to PC/USB Charger. (Thanks to @LOVEChen) +* HYUNDAI_GENESIS 使用 INDI 控制器。(感謝 @donfyffe 提供) +* HYUNDAI_GENESIS uses INDI controller. (Thanks to @donfyffe) + +dragonpilot 0.7.8.3 +======================== +* VW 加入 6 分鐘時間方向盤控制限制輔助方案。(特別感謝 @actuallylemoncurd 提供代碼) +* VW added 6 minutes timebomb assist. (dp_timebomb_assist, special thanks to @actuallylemoncurd) + +dragonpilot 0.7.8.2 +======================== +* 修正在沒網路的情況下,開機超過五分鐘的問題。 +* Fixed 5+ minutes boot time issue when there is no internet connection. +* 錯誤回傳改使用 dp 的主機。 +* Used dp server for error reporting. +* 更新服務改使用 gitee 的 IP 檢查連線狀態。 +* updated service uses gitee IP address instead. + +dragonpilot 0.7.8.1 +======================== +* 加入 ko-KR 翻譯。 +* Added ko-KR translation. +* 加入 Honda Jade 支援。(感謝 @李俊灝) +* Added Honda Jade support. (Thanks to @lijunhao731) +* 修正 ui.cc 內存越界的問題。(感謝 @piggy 提供) +* Fixed ui.cc memory out of bound issue. (Thanks to @piggy) +* gpxd 記錄改自動存成 zip 格式。 +* gpxd now store in zip format. +* 強制關閉 panda 檢查 DOS 硬體。 +* Force disabled DOS hardware check in panda. + +dragonpilot 0.7.8.0 +======================== +* 基於最新 openpilot 0.7.8 devel. +* Based on latest openpilot 0.7.8 devel. +* 加入重置 DP 設定按鈕。(感謝 @LOVEChen 建議) +* Added "Reset DP Settings" button. (Thanks to @LOVEChen) +* 將警示訊息更改為類似於概念 UI 的設計。 +* Alert messages changed to concept UI alike design. +* 當 manager 出現錯誤後,按 Exit 按鈕會執行 reset_update 腳本。 +* Added ability to execute reset_update.sh when press "Exit" button once manager returned errors. + +dragonpilot 0.7.7.3 +======================== +* 修正方向盤監控。 +* Fixed steering monitor timer param. +* 修正行駛時關閉畫面導致當機的錯誤。(感謝 @salmankhan, @stevej99, @bobbydough 回報) +* Fixed screen frozen issue when "screen off while driving" toggle is enabled. (Thanks to @salmankhan, @stevej99, @bobbydough) +* 加回 Dev Mini UI 開關。(感謝 @Ninjaa 建議) +* Re-added Dev Mini UI. (Thanks to @Ninjaa) +* 新增 (dp_reset_live_parameters_on_start) 每次發車重設 LiveParameters 值。(感謝 @eisenheim) +* Added ability (dp_reset_live_param_on_start) to reset LiveParameters on each start. (Thanks @eisenheim) +* 修正同時開啟 dp_toyota_zss 和 dp_lqr 產生的錯誤。(感謝 @bobbydough) +* Fixed error cuased by enabling both dp_toyota_zss and dp_lqr at the same time. (Thanks to @bobbydough) +* 新增 (dp_gpxd) 將 GPS 軌跡導出至 GPX 格式 (/sdcard/gpx_logs/)的功能。 (感謝 @mageymoo1) +* Added ability (dp_gpxd) to export GPS track into GPX files (/sdcard/gpx_logs/). (Thanks to @mageymoo1) +* 使用德國的車道寬度估算值。 (感謝 @arne182) +* Used lane width estimate value from Germany. (Thanks to @arne182) + +dragonpilot 0.7.7.2 +======================== +* 加入 d_poly offset。 (感謝 @ShaneSmiskol) +* Added d_poly offset. (Thanks to @ShaneSmiskol) +* 加入 ZSS 支援。(感謝 @bobbydough, @WilliamPrius 建議, @bobbydough 測試) +* Added ZSS support. (Thanks to @bobbydough, @WilliamPrius for recommendation, @bobbydough for testing) +* 加入錯誤記錄至 /sdcard/crash_logs/ (感謝 @ShaneSmiskol 提供代碼) +* Added error logs to /sdcard/crash_logs/ (Special Thanks to @ShaneSmiskol) +* 加入 LQR 控制器開關進設定畫面。 +* Added LQR Controller toggle to settings. + +dragonpilot 0.7.7.1 +======================== +* 加入 C2 風扇靜音模式。(感謝 @dingliangxue) +* Added C2 quiet fan mode. (Thanks to @dingliangxue) +* 加入「輔助換道最低啟動速度」、「自動換道最低啟動速度」設定。 +* Added "Assisted Lane Change Min Engage Speed" and "Auto Lane Change Min Engage Speed" settings. +* 加入回調校介面。(感謝 @Kent) +* Re-added Dev UI. (Thanks to @Kent) +* 加入 "dp_lqr" 設定來強制使用 RAV4 的 lqr 調校。(感謝 @eisenheim) +* Added "dp_lqr" setting to force enable lqr tuning from RAV4. (Thanks to eisenheim) + +dragonpilot 0.7.7.0 +======================== +* 基於最新 openpilot 0.7.7 devel. +* Based on latest openpilot 0.7.7 devel. +* 當 Manager 出現錯誤時,顯示 IP 位置。(感謝 @dingliangxue) +* When Manager failed, display IP address. (Thanks to @dingliangxue) +* 加回 sr learner 開關。 +* Re-added sr learner toggle. +* 加回 加速模式 開關。 +* Re-added Accel Profile toggle. +* Toyota 加入改寫最低巡航速度功能。(感謝 @Mojo) +* Added Toyota to override lowerest cruise speed. (Thanks to @Mojo) +* 介面加入盲點偵測顯示。(感謝 @wabes) +* Added BSM indicator to UI. (Thanks to @wabes) +* 加回彎道減速功能。(感謝 @Mojo) +* re-added Slow On Curve functionality. (Thanks to @Mojo) + +dragonpilot 0.7.6.2 +======================== +* 修正無法正確關閉駕駛監控的問題。 +* Fixed unable to properly turn off driver monitor issue. + +dragonpilot 0.7.6.1 +======================== +* 基於最新 openpilot 0.7.6.1 devel. +* Based on latest openpilot 0.7.6.1 devel. +* 優化並整合 dp 服務。 (所有的設定檔已改名,請重新設定所有的功能) +* Optimized and integrated several dp services. (Settings have been renamed, please re-config all settings) +* 完全關閉 steer ratio learner。 +* Completely disabled steer ratio learner. +* 移除「加速模式」。 +* Removed Accel Profile. +* 加入本田皓影混電版指紋v1。(感謝 @劉駿) +* Added Honda Breeze Hybrid FPv1. (Thanks to @劉駿) +* 加入台灣版 Toyota Prius 4.5 指紋v1。(感謝 @jeekid) +* Added Taiwan Toyota Prius 4.5 FPv1. (Thanks to @jeekid) + +dragonpilot 0.7.5.4 +======================== +* Dynamic Follow 更新模型。(感謝 @ShaneSmiskol 提供代碼、 @cgw1968 測試) +* Updated Dynamic Follow model. (Special Thanks to @ShaneSmiskol for the feature and @cgw1968 for testing) + +dragonpilot 0.7.5.3 +======================== +* Dynamic Follow 更新至 ShaneSmiskol:stock_additions 0.7.5 版。(感謝 @ShaneSmiskol 提供代碼、 @Wei 測試) +* Updated Dynamic Follow to ShaneSmiskol:stock_additions 0.7.5. (Special Thanks to @ShaneSmiskol for the feature and @Wei for testing) +* 優化 Lexus GSH 轉向。(感謝 @簡銘佑 測試) +* Optimize Lexus GSH steering. (Thanks to @簡銘佑) +* C2 支援自動關機「DragonAutoShutdownAt」參數。(感謝 @cgw1968 建議) +* C2 to support auto shutdown "DragonAutoShutDownAt" param. (Thanks to @cgw1968) +* 修正出現「pedalPressed」的錯誤。(感謝 @Wei 回報) +* Fixed issue showing "pedalPressed" error. (Thanks to @Wei) +* 將剎車狀熊顯示於 dp 資訊欄。 +* Added brake indicator to dp infobar. +* 修正「溫度監控」燈示。 +* Fixed "Temp monitor" indicator. +* 加入「方向燈取消控制」延遲控制設。(感謝 @wabes 建議) +* Added delay config to "Disable Lat Control on Blinker". (Thanks to @wabes) +* 加入巴西版 2020 Corolla Hybrid 指紋v2。(感謝 @berno22 提供) +* Added Brazil 2020 Corolla Hybrid FPv2. (Thanks to @berno22) + +dragonpilot 0.7.5.2 +======================== +* 加入對 VW MQB/PQ 的支援。(感謝 @dingliangxue 移植) +* Added support to VW MQB/PQ platform. (Thanks to @dingliangxue) +* 修改成 3 小時後停止供電。(感謝 @Wei 建議) +* Updated to stop charging after 3 hrs. (Thanks to @Wei) +* 移除行車記錄下的「碰撞偵測」功能。 +* Removed Impact Detection in Dashcam. +* 修正開啟「Noctua 風扇」模式導致的錯誤。(感謝 @阿濤 回報) +* Fixed a bug caused by enabling "Noctua Mod". (Thanks to @阿濤) +* 修正「位智模式」無法顯示警示的問題。(感謝 @axandres 回報) +* Fixed alert issue in waze mode. (Thanks to @axandres) +* 修正無法顯示更新中圖示的問題。 +* Fixed unable to display "UPDATING" icon issue. +* 加入「允許多次自動換道」功能。(感謝 @阿濤 建議) +* Added "Allow Continuous Auto Lane Change" Toggle. (Thanks to @阿濤) +* 修正開機後設定頁面有時會錯誤的問題。(感謝 @salmankhan、@Wei 回報) +* Fixed setting page crash issue. (Thanks to @salmankhan, @Wei) +* 修正熄火後一直出現更新訊息的錯誤。(感謝 @Sky Chang 回報) +* Fixed issue that keep showing update prompt. (Thanks to @Sky Chang) + +dragonpilot 0.7.5.1 +======================== +* 修正因同時使用「社群功能」和「自定車型」造成的加減速問題。(特別感謝 @Wei、@Sky Chang、@Han9365、@鄧育林 的測試以及回報。) +* Fixed acceleration issue caused by used of both "Community Maintain Feature" and "Custom Car Model". (Special Thanks to @Wei, @Sky Chang, @Han9365, @鄧育林) +* 新增 DragonMaxSpeedLimit 設定值 (mph),當如果車速高於此值 op 將會停止操控。(感謝 @Anthony 建議) +* Added DragonMaxSpeedLimit parameter (mph), op will stop controlling when car speed is high than the value. (Thanks to @Anthony) +* 更新 appd 使用 cnpmjs 來下載 APKs。 +* Updated appd to use cnpmjs to download APKs. +* 修正更新服務。(感謝 @Wei) +* Fixed Update Service. (Thanks to @Wei) +* 新增加拿大版 2018 Toyota Sienna LTD 指紋(v2)。(感謝 明峰 提供) +* Added Canada 2018 Toyota Sienna LTD fingerprint (v2). (Thanks to 明峰) +* 新增「通過移動網路上傳」開關 +* Added Upload Over Mobile Network toggle. +* 新增「通過熱點上傳」開關 +* Added Upload Over Hotspot toggle. +* 新增加拿大版 2018 Toyota Sienna LTD 指紋(v1)。(感謝 明峰 提供) +* Added Canada 2018 Toyota Sienna LTD fingerprint (v1). (Thanks to 明峰) +* 新增大陸版 Volkswagen Golf GTI 指紋 (v1)。(感謝 easyeiji 提供) +* Added China Volkswagen Golf GTI fingerprint (v1). (Thanks to easyeiji) + +dragonpilot 0.7.5.0 +======================== +* 基於最新 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/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 000000000..60b32fba4 --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,28 @@ +# CONTRIBUTORS + +Due to the way we manage the source code, it is not possible to see all the contributors info, hence we create a list here. + +If you have contributed to DP project before and your name is not listed here, feel free to send us a PR to update this! + +name | github | contribution +------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ +andy741217 | [andy741217](https://github.com/andy741217) | New features, bug fixes +Arne Schwarck | [arne182](https://github.com/arne182) | New features, bug fixes +berno22 | [berno22](https://github.com/berno22) | New car fingerprint +Bobbydough | [Bobbydough](https://github.com/bobbydough) | Bug fixes +Curtis Jenkins | [actuallylemoncurd](https://github.com/actuallylemoncurd) | New Features +DFyffe | [donfyffe](https://github.com/donfyffe) | New features, bug fixes +dinglx | [dingliangxue](https://github.com/dingliangxue) | New features, bug fixes +eyezenheim | [eyezenheim](https://github.com/eyezenheim) | Tester +kegman | [kegman](https://github.com/kegman) | New features, bug fixes +kumar | [rav4kumar](https://github.com/rav4kumar) | New features, bug fixes +lijunhao731 | [lijunhao731](https://github.com/lijunhao731) | New car fingerprint +lirudy | [lirudy](https://github.com/lirudy) | Bug fixes +LOVEChen | [LOVEChen](https://github.com/LOVEChen) | Bug fixes +loveloveses | [loveloveses](https://github.com/loveloveses) | Bug fixes, DP wiki main maintainer +menwenliang | [menwenliang](https://github.com/menwenliang) | New features +Rick Lan | [efinilan](https://github.com/efinilan) | Project lead +rming | [Rming](https://github.com/rming) | Bug fixes, wiki contributor +sebastian4k | [sebastian4k](https://github.com/sebastian4k) | Bug fixes +Shane Smiskol | [sshane](https://github.com/sshane) | New features, bug fixes +toyboxZ | [toyboxZ](https://github.com/toyboxZ) | New features, bug fixes diff --git a/HOWTO-ONEPLUS.md b/HOWTO-ONEPLUS.md new file mode 100644 index 000000000..d6030bd51 --- /dev/null +++ b/HOWTO-ONEPLUS.md @@ -0,0 +1,25 @@ +How to install on Oneplus 3t? +------ +1. clone dragonpilot to /data/ and make sure it's named openpilot: + (手動安裝切換至 dragonpilot 0.8.4 branch) +``` +cd /data/ && rm -fr openpilot; && git clone https://github.com/dragonpilot-community/dragonpilot.git -b 0.8.4 +``` + +2. run command: + (在 ssh 畫面下,輸入) +``` +cd /data/openpilot/scripts/ && ./oneplus_update_neos.sh +``` + +3. Let it download and complete it update, after a couple of reboot, your screen will then stay in fastboot mode. + (等待下載並讓它重新開機,沒錯誤的話會進入 Android 機器人更新畫面,等自動重新開機) + +4. In fastboot mode, select use volume button to select to `Recovery mode` then press power button. + (在 fastboot 模式,用音量鍵上下選到 Recovery mode 再按下電源鍵) + +5. In Recovery mode, tap `apply update` -> `Choose from emulated` -> `0/` -> `update.zip` -> `Reboot system now` + (在 Recovery mode,點選 `apply update` -> `Choose from emulated` -> `0/` -> `update.zip` -> `Reboot system now`) + +6. You should be able to boot into openpilot, if touch screen is not working, try to reboot again. + (你現在應該可以進入 openpilot 畫面,如果點擊畫面沒有反應,請再重新開機一次) \ No newline at end of file diff --git a/SConstruct b/SConstruct index 6b7905bfc..fa665a5e6 100644 --- a/SConstruct +++ b/SConstruct @@ -7,6 +7,8 @@ import platform import numpy as np TICI = os.path.isfile('/TICI') +JETSON = os.path.isfile('/JETSON') + Decider('MD5-timestamp') AddOption('--test', @@ -56,6 +58,10 @@ if arch == "aarch64" and TICI: USE_WEBCAM = os.getenv("USE_WEBCAM") is not None +USE_MIPI = os.getenv("USE_MIPI") is not None +if arch == "aarch64" and JETSON: + arch = "jarch64" + lenv = { "PATH": os.environ['PATH'], } @@ -105,8 +111,19 @@ else: cflags = [] cxxflags = [] cpppath = [] + rpath = [] - if arch == "Darwin": + if arch == "jarch64": + libpath = [ + "#phonelibs/libyuv/larch64/lib", + "#selfdrive/common", + "/usr/lib", + "/usr/local/lib", + ] + cflags = ["-DXNX", "-march=armv8.2-a"] + cxxflags = ["-DXNX", "-march=armv8.2-a"] + rpath += ["/usr/local/lib"] + elif arch == "Darwin": yuv_dir = "mac" if real_arch != "arm64" else "mac_arm64" libpath = [ f"#phonelibs/libyuv/{yuv_dir}/lib", @@ -134,8 +151,9 @@ else: "/usr/local/lib", ] - rpath = [ - "phonelibs/snpe/x86_64-linux-clang", + if arch != "jarch64": + rpath += ["phonelibs/snpe/x86_64-linux-clang"] + rpath += [ "cereal", "selfdrive/common" ] @@ -302,7 +320,7 @@ else: qt_dirs += [f"/usr/include/{real_arch}-linux-gnu/qt5/Qt{m}" for m in qt_modules] qt_libs = [f"Qt5{m}" for m in qt_modules] - if arch == "larch64": + if arch == "larch64" or arch == "jarch64": qt_libs += ["GLESv2", "wayland-client"] elif arch != "Darwin": qt_libs += ["GL"] @@ -334,7 +352,8 @@ if GetOption("clazy"): qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0] qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks) -Export('env', 'qt_env', 'arch', 'real_arch', 'SHARED', 'USE_WEBCAM') +zmq = 'zmq' +Export('env', 'qt_env', 'arch', 'real_arch', 'SHARED', 'USE_WEBCAM', 'zmq', 'USE_MIPI') # cereal and messaging are shared with the system SConscript(['cereal/SConscript']) diff --git a/cereal/SConscript b/cereal/SConscript index b3c8da9ae..92ce33a64 100644 --- a/cereal/SConscript +++ b/cereal/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch') +Import('env', 'envCython', 'arch', 'zmq') import shutil @@ -8,7 +8,7 @@ messaging_dir = Dir('messaging') # Build cereal -schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp'] +schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'dp.capnp'] env.Command(["gen/c/include/c++.capnp.h", "gen/c/include/java.capnp.h"], [], "mkdir -p " + gen_dir.path + "/c/include && touch $TARGETS") env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files], schema_files, @@ -40,6 +40,13 @@ messaging_objects = env.SharedObject([ messaging_lib = env.Library('messaging', messaging_objects) Depends('messaging/impl_zmq.cc', services_h) +# note, this rebuilds the deps shared, zmq is statically linked to make APK happy +# TODO: get APK to load system zmq to remove the static link +if arch == "aarch64": + zmq_static = FindFile("libzmq.a", "/usr/lib") + shared_lib_shared_lib = [zmq_static, 'm', 'stdc++', "gnustl_shared", "kj", "capnp"] + env.SharedLibrary('messaging_shared', messaging_objects, LIBS=shared_lib_shared_lib) + env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[messaging_lib, 'zmq']) Depends('messaging/bridge.cc', services_h) diff --git a/cereal/_SConstruct b/cereal/_SConstruct new file mode 100644 index 000000000..9f95ed6da --- /dev/null +++ b/cereal/_SConstruct @@ -0,0 +1,73 @@ +import os +import platform +import subprocess +import sysconfig + +arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() +if platform.system() == "Darwin": + arch = "Darwin" + +cereal_dir = Dir('.') +messaging_dir = Dir('./messaging') + +cpppath = [ + cereal_dir, + messaging_dir, + '/usr/lib/include', + '/opt/homebrew/include', + sysconfig.get_paths()['include'], +] + +libpath = [ + '/opt/homebrew/lib', +] + +AddOption('--test', + action='store_true', + help='build test files') + +AddOption('--asan', + action='store_true', + help='turn on ASAN') + +ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"] if GetOption('asan') else [] +ldflags_asan = ["-fsanitize=address"] if GetOption('asan') else [] + +env = Environment( + ENV=os.environ, + CC='clang', + CXX='clang++', + CCFLAGS=[ + "-g", + "-fPIC", + "-O2", + "-Wunused", + "-Werror", + ] + ccflags_asan, + LDFLAGS=ldflags_asan, + LINKFLAGS=ldflags_asan, + + CFLAGS="-std=gnu11", + CXXFLAGS="-std=c++1z", + CPPPATH=cpppath, + LIBPATH=libpath, + CYTHONCFILESUFFIX=".cpp", + tools=["default", "cython"] +) + +Export('env', 'arch') + +envCython = env.Clone(LIBS=[]) +envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-deprecated-declarations"] +if arch == "Darwin": + envCython["LINKFLAGS"] = ["-bundle", "-undefined", "dynamic_lookup"] +elif arch == "aarch64": + envCython["LINKFLAGS"] = ["-shared"] + envCython["LIBS"] = [os.path.basename(sysconfig.get_paths()['include'])] +else: + envCython["LINKFLAGS"] = ["-pthread", "-shared"] + +Export('envCython') + + +SConscript(['SConscript']) diff --git a/cereal/car.capnp b/cereal/car.capnp index 999c064f0..16fa4e1a8 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -129,6 +129,18 @@ struct CarEvent @0x9b1657f34caf3ad3 { neosUpdateRequiredDEPRECATED @88; modelLagWarningDEPRECATED @93; startupOneplusDEPRECATED @82; + + #dp + preLaneChangeLeftALC @105; + preLaneChangeRightALC @106; + manualSteeringRequired @107; + manualSteeringRequiredBlinkersOn @108; + leadCarMoving @109; + + # timebomb assist + timebombWarn @110; + timebombBypassing @111; + timebombBypassed @112; } } @@ -194,6 +206,10 @@ struct CarState { leftBlindspot @33 :Bool; # Is there something blocking the left lane change rightBlindspot @34 :Bool; # Is there something blocking the right lane change + # dp + lkMode @37 :Bool; + stopSteering @38 :Bool; # timebomb - stopSteering + struct WheelSpeeds { # optional wheel speeds fl @0 :Float32; @@ -246,7 +262,7 @@ struct CarState { } errorsDEPRECATED @0 :List(CarEvent.EventName); - brakeLightsDEPRECATED @19 :Bool; + brakeLights @19 :Bool; } # ******* radar state @ 20hz ******* diff --git a/cereal/dp.capnp b/cereal/dp.capnp new file mode 100644 index 000000000..adf5e704a --- /dev/null +++ b/cereal/dp.capnp @@ -0,0 +1,57 @@ +using Cxx = import "./include/c++.capnp"; +$Cxx.namespace("cereal"); + +using Java = import "./include/java.capnp"; +$Java.package("ai.comma.openpilot.cereal"); +$Java.outerClassname("dp"); + +@0xbfa7e645486440c7; + +# dp.capnp: a home for deprecated structs + +# dp +struct DragonConf { + dpThermalStarted @0 :Bool; + dpThermalOverheat @1 :Bool; + dpAtl @2 :Bool; + dpDashcamd @3 :Bool; + dpAutoShutdown @4 :Bool; + dpAthenad @5 :Bool; + dpUploader @6 :Bool; + dpLateralMode @7 :UInt8; + dpSignalOffDelay @8 :Float32; + dpLcMinMph @9 :UInt8; + dpLcAutoCont @10 :Bool; + dpLcAutoMinMph @11 :UInt8; + dpLcAutoDelay @12 :Float32; + dpAllowGas @13 :Bool; + dpFollowingProfileCtrl @14 :Bool; + dpFollowingProfile @15 :UInt8; + dpAccelProfileCtrl @16 :Bool; + dpAccelProfile @17 :UInt8; + dpGearCheck @18 :Bool; + dpSpeedCheck @19 :Bool; + dpUiDisplayMode @20 :UInt8; + dpUiSpeed @21 :Bool; + dpUiEvent @22 :Bool; + dpUiMaxSpeed @23 :Bool; + dpUiFace @24 :Bool; + dpUiLane @25 :Bool; + dpUiLead @26 :Bool; + dpUiDev @27 :Bool; + dpUiDevMini @28 :Bool; + dpUiBlinker @29 :Bool; + dpUiBrightness @30 :UInt8; + dpUiVolume @31 :Int8; + dpToyotaLdw @32 :Bool; + dpToyotaSng @33 :Bool; + dpVwTimebombAssist @34 :Bool; + dpIpAddr @35 :Text; + dpCameraOffset @36 :Int8; + dpPathOffset @37 :Int8; + dpLocale @38 :Text; + dpSrLearner @39 :Bool; + dpSrCustom @40 :Float32; + dpAppd @41 :Bool; + dpDebug @42 :Bool; +} \ No newline at end of file diff --git a/cereal/log.capnp b/cereal/log.capnp index bd028f511..aca5cf7b4 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -7,6 +7,7 @@ $Java.outerClassname("Log"); using Car = import "car.capnp"; using Legacy = import "legacy.capnp"; +using Dp = import "dp.capnp"; @0xf3b1f17e25a4285b; @@ -49,6 +50,7 @@ struct InitData { chffrIos @3; tici @4; pc @5; + jetson @6; } struct PandaInfo { @@ -638,7 +640,7 @@ struct ControlsState @0x97ff69c53601abf1 { decelForTurnDEPRECATED @47 :Bool; decelForModelDEPRECATED @54 :Bool; awarenessStatusDEPRECATED @26 :Float32; - angleSteersDEPRECATED @13 :Float32; + angleSteers @13 :Float32; # dp vCurvatureDEPRECATED @46 :Float32; mapValidDEPRECATED @49 :Bool; jerkFactorDEPRECATED @12 :Float32; @@ -825,6 +827,9 @@ struct LateralPlan @0xe1e9318e2ae8b51e { rawCurvature @24 :Float32; rawCurvatureRate @25 :Float32; + # dp + dpALCAllowed @26 :Bool; + enum Desire { none @0; turnLeft @1; @@ -1397,5 +1402,6 @@ struct Event { kalmanOdometryDEPRECATED @65 :Legacy.KalmanOdometry; gpsLocationDEPRECATED @21 :GpsLocationData; uiLayoutStateDEPRECATED @57 :Legacy.UiLayoutState; + dragonConf @79 :Dp.DragonConf; } } diff --git a/cereal/services.py b/cereal/services.py index bd89cfa31..1202beed7 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -68,6 +68,11 @@ services = { "testModel": (False, 0.), "testLiveLocation": (False, 0.), "testJoystick": (False, 0.), + + # dp + "thermal": (True, 2., 1), + "dragonConf": (False, 2.), + } service_list = {name: Service(new_port(idx), *vals) for # type: ignore idx, (name, vals) in enumerate(services.items())} diff --git a/common/basedir.py b/common/basedir.py index 8be1cf6af..c7c312851 100644 --- a/common/basedir.py +++ b/common/basedir.py @@ -1,11 +1,11 @@ import os from pathlib import Path -from selfdrive.hardware import PC +from selfdrive.hardware import PC, JETSON BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")) -if PC: +if PC or JETSON: PERSIST = os.path.join(str(Path.home()), ".comma", "persist") else: PERSIST = "/persist" diff --git a/common/dp_common.py b/common/dp_common.py new file mode 100644 index 000000000..a36262638 --- /dev/null +++ b/common/dp_common.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3.7 +import subprocess +from cereal import car +from common.params import Params +from common.realtime import sec_since_boot +import os +params = Params() +PARAM_PATH = params.get_params_path() + '/d/' +LAST_MODIFIED = PARAM_PATH + "dp_last_modified" + +def is_online(): + try: + return not subprocess.call(["ping", "-W", "4", "-c", "1", "117.28.245.92"]) + except ProcessLookupError: + return False + +def common_controller_ctrl(enabled, dragonconf, blinker_on, steer_req, v_ego): + if enabled: + if dragonconf.dpLateralMode == 0 and blinker_on: + steer_req = 0 if isinstance(steer_req, int) else False + return steer_req + +def common_interface_atl(ret, atl): + # dp + enable_acc = ret.cruiseState.enabled + if atl 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 + return enable_acc + +def common_interface_get_params_lqr(ret): + if params.get_bool('dp_lqr'): + ret.lateralTuning.init('lqr') + ret.lateralTuning.lqr.scale = 1500.0 + ret.lateralTuning.lqr.ki = 0.05 + + ret.lateralTuning.lqr.a = [0., 1., -0.22619643, 1.21822268] + ret.lateralTuning.lqr.b = [-1.92006585e-04, 3.95603032e-05] + ret.lateralTuning.lqr.c = [1., 0.] + ret.lateralTuning.lqr.k = [-110.73572306, 451.22718255] + ret.lateralTuning.lqr.l = [0.3233671, 0.3185757] + ret.lateralTuning.lqr.dcGain = 0.002237852961363602 + return ret + + +def get_last_modified(delay, old_check, old_modified): + new_check = sec_since_boot() + if old_check is None or new_check - old_check >= delay: + return new_check, os.stat(LAST_MODIFIED).st_mtime + else: + return old_check, old_modified + +def param_get_if_updated(param, type, old_val, old_modified): + try: + modified = os.stat(PARAM_PATH + param).st_mtime + except OSError: + return old_val, old_modified + if old_modified != modified: + new_val = param_get(param, type, old_val) + new_modified = modified + else: + new_val = old_val + new_modified = old_modified + return new_val, new_modified + +def param_get(param_name, type, default): + try: + val = params.get(param_name, encoding='utf8').rstrip('\x00') + if type == 'bool': + val = val == '1' + elif type == 'int': + val = int(val) + elif type == 'float': + val = float(val) + except (TypeError, ValueError): + val = default + return val diff --git a/common/dp_conf.py b/common/dp_conf.py new file mode 100644 index 000000000..b48198856 --- /dev/null +++ b/common/dp_conf.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python3.7 +import os +import sys +import json +import time +from math import floor + +''' +* type: Bool, Int8, UInt8, UInt16, Float32 +* conf_type: param, struct +* dependencies needs to use struct and loaded prior so we don't have to read the param multiple times. +* update_once: True, False (the param will only load up once, need both param and struct defined) +''' +confs = [ + # thermald data + {'name': 'dp_thermal_started', 'default': False, 'type': 'Bool', 'conf_type': ['struct']}, + {'name': 'dp_thermal_overheat', 'default': False, 'type': 'Bool', 'conf_type': ['struct']}, + + {'name': 'dp_atl', 'default': False, 'type': 'Bool', 'conf_type': ['param', 'struct'], 'update_once': True}, + # dashcam related + {'name': 'dp_dashcamd', 'default': False, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + # auto shutdown + {'name': 'dp_auto_shutdown', 'default': False, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_auto_shutdown_in', 'default': 90, 'type': 'UInt16', 'min': 0, 'max': 600, 'depends': [{'name': 'dp_auto_shutdown', 'vals': [True]}], 'conf_type': ['param']}, + # service + {'name': 'dp_updated', 'default': True, 'type': 'Bool', 'conf_type': ['param']}, + {'name': 'dp_logger', 'default': True, 'type': 'Bool', 'conf_type': ['param']}, + {'name': 'dp_athenad', 'default': True, 'type': 'Bool', 'depends': [{'name': 'dp_atl', 'vals': [False]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_uploader', 'default': True, 'type': 'Bool', 'depends': [{'name': 'dp_atl', 'vals': [False]}], 'conf_type': ['param', 'struct']}, + # {'name': 'dp_gpxd', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + {'name': 'dp_hotspot_on_boot', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + # lat ctrl + {'name': 'dp_lateral_mode', 'default': 1, 'type': 'UInt8', 'min': 0, 'max': 2, 'conf_type': ['param', 'struct']}, + {'name': 'dp_signal_off_delay', 'default': 3., 'type': 'Float32', 'min': 0., 'max': 10., 'depends': [{'name': 'dp_lateral_mode', 'vals': [0]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_lc_min_mph', 'default': 45, 'type': 'UInt8', 'min': 0, 'max': 255, 'depends': [{'name': 'dp_lateral_mode', 'vals': [1,2]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_lc_auto_cont', 'default': False, 'type': 'Bool', 'depends': [{'name': 'dp_lateral_mode', 'vals': [2]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_lc_auto_min_mph', 'default': 60, 'type': 'UInt8', 'min': 0, 'max': 255, 'depends': [{'name': 'dp_lateral_mode', 'vals': [2]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_lc_auto_delay', 'default': 3., 'type': 'Float32', 'min': 0., 'max': 10., 'depends': [{'name': 'dp_lateral_mode', 'vals': [2]}], 'conf_type': ['param', 'struct']}, + # long ctrl + {'name': 'dp_allow_gas', 'default': False, 'type': 'Bool', 'depends': [{'name': 'dp_atl', 'vals': [False]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_following_profile_ctrl', 'default': False, 'type': 'Bool', 'depends': [{'name': 'dp_atl', 'vals': [False]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_following_profile', 'default': 0, 'type': 'UInt8', 'min': 0, 'max': 2, 'depends': [{'name': 'dp_atl', 'vals': [False]}, {'name': 'dp_following_profile_ctrl', 'vals': [True]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_accel_profile_ctrl', 'default': False, 'type': 'Bool', 'depends': [{'name': 'dp_atl', 'vals': [False]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_accel_profile', 'default': 0, 'type': 'UInt8', 'min': 0, 'max': 2, 'depends': [{'name': 'dp_atl', 'vals': [False]}, {'name': 'dp_accel_profile_ctrl', 'vals': [True]}], 'conf_type': ['param', 'struct']}, + # safety + {'name': 'dp_gear_check', 'default': True, 'type': 'Bool', 'depends': [{'name': 'dp_atl', 'vals': [False]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_speed_check', 'default': True, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_temp_monitor', 'default': True, 'type': 'Bool', 'conf_type': ['param']}, + # UIs + {'name': 'dp_ui_display_mode', 'default': 0, 'type': 'UInt8', 'min': 0, 'max': 2, 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_speed', 'default': True, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_event', 'default': True, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_max_speed', 'default': True, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_face', 'default': True, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_lane', 'default': True, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_lead', 'default': True, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_dev', 'default': False, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_dev_mini', 'default': False, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_blinker', 'default': False, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_brightness', 'default': 0, 'type': 'UInt8', 'min': 0, 'max': 100, 'conf_type': ['param', 'struct']}, + {'name': 'dp_ui_volume', 'default': -5, 'type': 'Int8', 'min': -5, 'max': 100, 'conf_type': ['param', 'struct']}, + # toyota + {'name': 'dp_toyota_ldw', 'default': True, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_toyota_sng', 'default': False, 'type': 'Bool', 'depends': [{'name': 'dp_atl', 'vals': [False]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_toyota_zss', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + {'name': 'dp_toyota_disable_relay', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + # hyundai + {'name': 'dp_hkg_smart_mdps', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + # honda + {'name': 'dp_honda_eps_mod', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + # volkswagen + {'name': 'dp_vw_panda', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + {'name': 'dp_vw_timebomb_assist', 'default': False, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + #misc + {'name': 'dp_ip_addr', 'default': '', 'type': 'Text', 'conf_type': ['struct']}, + {'name': 'dp_fan_mode', 'default': 0, 'type': 'UInt8', 'min': 0, 'max': 2, 'conf_type': ['param']}, + {'name': 'dp_last_modified', 'default': str(floor(time.time())), 'type': 'Text', 'conf_type': ['param']}, + {'name': 'dp_camera_offset', 'default': 6, 'type': 'Int8', 'min': -100, 'max': 100, 'conf_type': ['param', 'struct']}, + {'name': 'dp_path_offset', 'default': 0, 'type': 'Int8', 'min': -100, 'max': 100, 'conf_type': ['param', 'struct']}, + + {'name': 'dp_locale', 'default': 'en-US', 'type': 'Text', 'conf_type': ['param', 'struct'], 'update_once': True}, + {'name': 'dp_reg', 'default': True, 'type': 'Bool', 'conf_type': ['param']}, + # sr learner related + {'name': 'dp_sr_learner', 'default': True, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_sr_custom', 'default': 9.99, 'min': 9.99, 'max': 30., 'type': 'Float32', 'depends': [{'name': 'dp_sr_learner', 'vals': [False]}], 'conf_type': ['param', 'struct']}, + {'name': 'dp_sr_stock', 'default': 9.99, 'min': 9.99, 'max': 100., 'type': 'Float32', 'conf_type': ['param']}, + + {'name': 'dp_lqr', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + {'name': 'dp_reset_live_param_on_start', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + + {'name': 'dp_appd', 'default': False, 'type': 'Bool', 'conf_type': ['param', 'struct']}, + {'name': 'dp_jetson', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + {'name': 'dp_car_assigned', 'default': '', 'type': 'Text', 'conf_type': ['param']}, + {'name': 'dp_car_list', 'default': '', 'type': 'Text', 'conf_type': ['param']}, + {'name': 'dp_no_batt', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + {'name': 'dp_panda_fake_black', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + {'name': 'dp_panda_no_gps', 'default': False, 'type': 'Bool', 'conf_type': ['param']}, + {'name': 'dp_last_candidate', 'default': '', 'type': 'Text', 'conf_type': ['param']}, + {'name': 'dp_debug', 'default': False, 'type': 'Bool', 'conf_type': ['param', 'struct']}, +] + +def get_definition(name): + for conf in confs: + if conf['name'] == name: + return conf + return None + +def to_param_val(name, val): + conf = get_definition(name) + if conf is not None: + type = conf['type'].lower() + try: + if 'bool' in type: + val = '1' if val else '0' + elif 'int' in type: + val = int(val) + elif 'float' in type: + val = float(val) + return str(val) + except (ValueError, TypeError): + return '' + return '' + +def to_struct_val(name, val): + conf = get_definition(name) + if conf is not None: + try: + type = conf['type'].lower() + if 'bool' in type: + val = True if val == '1' else False + elif 'int' in type: + val = int(val) + elif 'float' in type: + val = float(val) + return val + except (ValueError, TypeError): + return None + return None + +''' +function to convert param name into struct name. +''' +def get_struct_name(snake_str): + components = snake_str.split('_') + # We capitalize the first letter of each component except the first one + # with the 'title' method and join them together. + return components[0] + ''.join(x.title() for x in components[1:]) + +''' +function to generate struct for log.capnp +''' +def gen_log_struct(): + count = 0 + str = "# dp\n" + str += "struct DragonConf {\n" + for conf in confs: + name = get_struct_name(conf['name']) + if 'struct' in conf['conf_type']: + str += f" {name} @{count} :{conf['type']};\n" + count += 1 + str += "}" + print(str) + +''' +function to generate support car list +''' +def get_support_car_list(): + attrs = ['FINGERPRINTS', 'FW_VERSIONS'] + cars = dict({"cars": []}) + 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() + brand_models = {"brand": car_name.upper(), "models": names } + cars["cars"].append(brand_models) + except (ImportError, IOError, ValueError): + pass + return json.dumps(cars) + +''' +function to init param value. +should add this into manager.py +''' +def init_params_vals(params): + for conf in confs: + if 'param' in conf['conf_type']: + if conf['name'] == 'dp_car_list': + params.put(conf['name'], get_support_car_list()) + elif params.get(conf['name']) is None: + params.put(conf['name'], to_param_val(conf['name'], conf['default'])) + +def gen_params_cc_keys(): + for conf in confs: + if 'param' in conf['conf_type']: + print(" {\"%s\", PERSISTENT}," % conf['name']) + + +if __name__ == "__main__": + if (len(sys.argv) > 1) and sys.argv[1] == 'cc': + gen_params_cc_keys() + else: + gen_log_struct() diff --git a/common/dp_time.py b/common/dp_time.py new file mode 100644 index 000000000..ad09255b0 --- /dev/null +++ b/common/dp_time.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3.7 + +# delay of reading last modified +LAST_MODIFIED_THERMALD = 10. +LAST_MODIFIED_SYSTEMD = 1. +LAST_MODIFIED_LANE_PLANNER = 3. +LAST_MODIFIED_UPLOADER = 10. \ No newline at end of file diff --git a/common/i18n.py b/common/i18n.py new file mode 100644 index 000000000..13e419a79 --- /dev/null +++ b/common/i18n.py @@ -0,0 +1,14 @@ +import gettext +from selfdrive.hardware import EON +from selfdrive.hardware.eon.hardware import getprop + +locale_dir = '/data/openpilot/selfdrive/assets/locales' +supported_language = ['en-US', 'zh-TW', 'zh-CN', 'ja-JP', 'ko-KR'] + +def get_locale(): + return getprop("persist.sys.locale") if EON else 'en-US' + +def events(): + i18n = gettext.translation('events', localedir=locale_dir, fallback=True, languages=[get_locale()]) + i18n.install() + return i18n.gettext \ No newline at end of file diff --git a/common/params_pxd.pxd b/common/params_pxd.pxd index 80113c339..52596150e 100644 --- a/common/params_pxd.pxd +++ b/common/params_pxd.pxd @@ -26,3 +26,5 @@ cdef extern from "selfdrive/common/params.h": int putBool(string, bool) bool checkKey(string) void clearAll(ParamKeyType) + + string get_params_path() diff --git a/common/params_pyx.pyx b/common/params_pyx.pyx index e1ebf95eb..4639417b4 100755 --- a/common/params_pyx.pyx +++ b/common/params_pyx.pyx @@ -97,6 +97,8 @@ cdef class Params: cdef string k = self.check_key(key) self.p.remove(k) + def get_params_path(self): + return self.p.get_params_path().decode("utf-8") def put_nonblocking(key, val, d=None): def f(key, val): diff --git a/common/realtime.py b/common/realtime.py index 762410f09..47ec94f67 100644 --- a/common/realtime.py +++ b/common/realtime.py @@ -6,7 +6,7 @@ import multiprocessing from typing import Optional from common.clock import sec_since_boot # pylint: disable=no-name-in-module, import-error -from selfdrive.hardware import PC, TICI +from selfdrive.hardware import PC, TICI, JETSON # time step for each process @@ -33,12 +33,12 @@ class Priority: def set_realtime_priority(level: int) -> None: - if not PC: + if JETSON or not PC: os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level)) # type: ignore[attr-defined] def set_core_affinity(core: int) -> None: - if not PC: + if JETSON or not PC: os.sched_setaffinity(0, [core,]) diff --git a/common/text_window.py b/common/text_window.py index bea3a149f..c9901754f 100755 --- a/common/text_window.py +++ b/common/text_window.py @@ -33,6 +33,7 @@ class TextWindow: if self.text_proc is not None: while True: if self.get_status() == 1: + os.system('/data/openpilot/scripts/reset_update.sh') return time.sleep(0.1) diff --git a/common/transformations/camera.py b/common/transformations/camera.py index 29ce3277d..9c365dc7e 100644 --- a/common/transformations/camera.py +++ b/common/transformations/camera.py @@ -5,12 +5,14 @@ from selfdrive.hardware import TICI ## -- hardcoded hardware params -- eon_f_focal_length = 910.0 -eon_d_focal_length = 650.0 +eon_d_focal_length = 860.0 +leon_d_focal_length = 650.0 tici_f_focal_length = 2648.0 tici_e_focal_length = tici_d_focal_length = 567.0 # probably wrong? magnification is not consistent across frame eon_f_frame_size = (1164, 874) -eon_d_frame_size = (816, 612) +eon_d_frame_size = (1152, 864) +leon_d_frame_size = (816, 612) tici_f_frame_size = tici_e_frame_size = tici_d_frame_size = (1928, 1208) # aka 'K' aka camera_frame_from_view_frame @@ -20,6 +22,11 @@ eon_fcam_intrinsics = np.array([ [0.0, 0.0, 1.0]]) eon_intrinsics = eon_fcam_intrinsics # xx +leon_dcam_intrinsics = np.array([ + [leon_d_focal_length, 0.0, float(leon_d_frame_size[0])/2], + [0.0, leon_d_focal_length, float(leon_d_frame_size[1])/2], + [0.0, 0.0, 1.0]]) + eon_dcam_intrinsics = np.array([ [eon_d_focal_length, 0.0, float(eon_d_frame_size[0])/2], [0.0, eon_d_focal_length, float(eon_d_frame_size[1])/2], diff --git a/installer/updater/oneplus.json b/installer/updater/oneplus.json new file mode 100644 index 000000000..06e66de63 --- /dev/null +++ b/installer/updater/oneplus.json @@ -0,0 +1,7 @@ +{ + "ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-c4f56c62c5603c86e2ae9d83008a8d42a91319979661d0c42fb97b85d9112266.zip", + "ota_hash": "c4f56c62c5603c86e2ae9d83008a8d42a91319979661d0c42fb97b85d9112266", + "recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-db31ffe79dfd60be966fba6d1525a5081a920062b883644dc8f5734bcc6806bb.img", + "recovery_len": 15926572, + "recovery_hash": "db31ffe79dfd60be966fba6d1525a5081a920062b883644dc8f5734bcc6806bb" +} diff --git a/installer/updater/update.zip b/installer/updater/update.zip new file mode 100644 index 000000000..69e24bcf0 Binary files /dev/null and b/installer/updater/update.zip differ diff --git a/installer/updater/updater b/installer/updater/updater index d833cb782..7b9e53936 100755 Binary files a/installer/updater/updater and b/installer/updater/updater differ diff --git a/installer/updater/updater.cc b/installer/updater/updater.cc deleted file mode 100644 index b2f9dd45b..000000000 --- a/installer/updater/updater.cc +++ /dev/null @@ -1,803 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "nanovg.h" -#define NANOVG_GLES3_IMPLEMENTATION -#include "json11.hpp" -#include "nanovg_gl.h" -#include "nanovg_gl_utils.h" - -#include "selfdrive/common/framebuffer.h" -#include "selfdrive/common/touch.h" -#include "selfdrive/common/util.h" - -#define USER_AGENT "NEOSUpdater-0.2" - -#define MANIFEST_URL_NEOS_STAGING "https://github.com/commaai/eon-neos/raw/master/update.staging.json" -#define MANIFEST_URL_NEOS_LOCAL "http://192.168.5.1:8000/neosupdate/update.local.json" -#define MANIFEST_URL_NEOS "https://github.com/commaai/eon-neos/raw/master/update.json" -const char *manifest_url = MANIFEST_URL_NEOS; - -#define RECOVERY_DEV "/dev/block/bootdevice/by-name/recovery" -#define RECOVERY_COMMAND "/cache/recovery/command" - -#define UPDATE_DIR "/data/neoupdate" - -extern const uint8_t bin_opensans_regular[] asm("_binary_opensans_regular_ttf_start"); -extern const uint8_t bin_opensans_regular_end[] asm("_binary_opensans_regular_ttf_end"); -extern const uint8_t bin_opensans_semibold[] asm("_binary_opensans_semibold_ttf_start"); -extern const uint8_t bin_opensans_semibold_end[] asm("_binary_opensans_semibold_ttf_end"); -extern const uint8_t bin_opensans_bold[] asm("_binary_opensans_bold_ttf_start"); -extern const uint8_t bin_opensans_bold_end[] asm("_binary_opensans_bold_ttf_end"); - -namespace { - -std::string sha256_file(std::string fn, size_t limit=0) { - SHA256_CTX ctx; - SHA256_Init(&ctx); - - FILE *file = fopen(fn.c_str(), "rb"); - if (!file) return ""; - - const size_t buf_size = 8192; - std::unique_ptr buffer( new char[ buf_size ] ); - - bool read_limit = (limit != 0); - while (true) { - size_t read_size = buf_size; - if (read_limit) read_size = std::min(read_size, limit); - size_t bytes_read = fread(buffer.get(), 1, read_size, file); - if (!bytes_read) break; - - SHA256_Update(&ctx, buffer.get(), bytes_read); - - if (read_limit) { - limit -= bytes_read; - if (limit == 0) break; - } - } - - uint8_t hash[SHA256_DIGEST_LENGTH]; - SHA256_Final(hash, &ctx); - - fclose(file); - - return util::tohex(hash, sizeof(hash)); -} - -size_t download_string_write(void *ptr, size_t size, size_t nmeb, void *up) { - size_t sz = size * nmeb; - ((std::string*)up)->append((char*)ptr, sz); - return sz; -} - -std::string download_string(CURL *curl, std::string url) { - std::string os; - - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 0); - curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT); - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); - curl_easy_setopt(curl, CURLOPT_RESUME_FROM, 0); - - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); - - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_string_write); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &os); - CURLcode res = curl_easy_perform(curl); - if (res != CURLE_OK) { - return ""; - } - - return os; -} - -size_t download_file_write(void *ptr, size_t size, size_t nmeb, void *up) { - return fwrite(ptr, size, nmeb, (FILE*)up); -} - -int battery_capacity() { - std::string bat_cap_s = util::read_file("/sys/class/power_supply/battery/capacity"); - return atoi(bat_cap_s.c_str()); -} - -int battery_current() { - std::string current_now_s = util::read_file("/sys/class/power_supply/battery/current_now"); - return atoi(current_now_s.c_str()); -} - -bool check_battery() { - int bat_cap = battery_capacity(); - int current_now = battery_current(); - return bat_cap > 35 || (current_now < 0 && bat_cap > 10); -} - -bool check_space() { - struct statvfs stat; - if (statvfs("/data/", &stat) != 0) { - return false; - } - size_t space = stat.f_bsize * stat.f_bavail; - return space > 2000000000ULL; // 2GB -} - -static void start_settings_activity(const char* name) { - char launch_cmd[1024]; - snprintf(launch_cmd, sizeof(launch_cmd), - "am start -W --ez :settings:show_fragment_as_subsetting true -n 'com.android.settings/.%s'", name); - system(launch_cmd); -} - -bool is_settings_active() { - FILE *fp; - char sys_output[4096]; - - fp = popen("/bin/dumpsys window windows", "r"); - if (fp == NULL) { - return false; - } - - bool active = false; - while (fgets(sys_output, sizeof(sys_output), fp) != NULL) { - if (strstr(sys_output, "mCurrentFocus=null") != NULL) { - break; - } - - if (strstr(sys_output, "mCurrentFocus=Window") != NULL) { - active = true; - break; - } - } - - pclose(fp); - - return active; -} - -struct Updater { - bool do_exit = false; - - TouchState touch; - - int fb_w, fb_h; - - std::unique_ptr fb; - NVGcontext *vg = NULL; - int font_regular; - int font_semibold; - int font_bold; - - std::thread update_thread_handle; - - std::mutex lock; - - enum UpdateState { - CONFIRMATION, - LOW_BATTERY, - RUNNING, - ERROR, - }; - UpdateState state; - - std::string progress_text; - float progress_frac; - - std::string error_text; - - std::string low_battery_text; - std::string low_battery_title; - std::string low_battery_context; - std::string battery_cap_text; - int min_battery_cap = 35; - - // button - int b_x, b_w, b_y, b_h; - int balt_x; - - // download stage writes these for the installation stage - int recovery_len; - std::string recovery_hash; - std::string recovery_fn; - std::string ota_fn; - - CURL *curl = NULL; - - void ui_init() { - touch_init(&touch); - - fb = std::make_unique("updater", 0x00001000, false, &fb_w, &fb_h); - - fb->set_power(HWC_POWER_MODE_NORMAL); - - vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG); - assert(vg); - - font_regular = nvgCreateFontMem(vg, "opensans_regular", (unsigned char*)bin_opensans_regular, (bin_opensans_regular_end - bin_opensans_regular), 0); - assert(font_regular >= 0); - - font_semibold = nvgCreateFontMem(vg, "opensans_semibold", (unsigned char*)bin_opensans_semibold, (bin_opensans_semibold_end - bin_opensans_semibold), 0); - assert(font_semibold >= 0); - - font_bold = nvgCreateFontMem(vg, "opensans_bold", (unsigned char*)bin_opensans_bold, (bin_opensans_bold_end - bin_opensans_bold), 0); - assert(font_bold >= 0); - - b_w = 640; - balt_x = 200; - b_x = fb_w-b_w-200; - b_y = 720; - b_h = 220; - - if (download_stage(true)) { - state = RUNNING; - update_thread_handle = std::thread(&Updater::run_stages, this); - } else { - state = CONFIRMATION; - } - } - - int download_file_xferinfo(curl_off_t dltotal, curl_off_t dlno, - curl_off_t ultotal, curl_off_t ulnow) { - { - std::lock_guard guard(lock); - if (dltotal != 0) { - progress_frac = (float) dlno / dltotal; - } - } - // printf("info: %ld %ld %f\n", dltotal, dlno, progress_frac); - return 0; - } - - bool download_file(std::string url, std::string out_fn) { - FILE *of = fopen(out_fn.c_str(), "ab"); - assert(of); - - CURLcode res; - long last_resume_from = 0; - - fseek(of, 0, SEEK_END); - - int tries = 4; - - bool ret = false; - - while (true) { - long resume_from = ftell(of); - - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 0); - curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT); - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); - curl_easy_setopt(curl, CURLOPT_RESUME_FROM, resume_from); - - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_file_write); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, of); - - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); - - curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this); - curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &Updater::download_file_xferinfo); - - CURLcode res = curl_easy_perform(curl); - - long response_code = 0; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); - - // double content_length = 0.0; - // curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length); - - printf("download %s res %d, code %ld, resume from %ld\n", url.c_str(), res, response_code, resume_from); - if (res == CURLE_OK) { - ret = true; - break; - } else if (res == CURLE_HTTP_RETURNED_ERROR && response_code == 416) { - // failed because the file is already complete? - ret = true; - break; - } else if (resume_from == last_resume_from) { - // failed and dind't make make forward progress. only retry a couple times - tries--; - if (tries <= 0) { - break; - } - } - last_resume_from = resume_from; - } - // printf("res %d\n", res); - - // printf("- %ld %f\n", response_code, content_length); - - fclose(of); - - return ret; - } - - void set_progress(std::string text) { - std::lock_guard guard(lock); - progress_text = text; - } - - void set_error(std::string text) { - std::lock_guard guard(lock); - error_text = text; - state = ERROR; - } - - void set_battery_low() { - std::lock_guard guard(lock); - state = LOW_BATTERY; - } - - void set_running() { - std::lock_guard guard(lock); - state = RUNNING; - } - - std::string download(std::string url, std::string hash, std::string name, bool dry_run) { - std::string out_fn = UPDATE_DIR "/" + util::base_name(url); - - std::string fn_hash = sha256_file(out_fn); - if (dry_run) { - return (hash.compare(fn_hash) != 0) ? "" : out_fn; - } - - // start or resume downloading if hash doesn't match - if (hash.compare(fn_hash) != 0) { - set_progress("Downloading " + name + "..."); - bool r = download_file(url, out_fn); - if (!r) { - set_error("failed to download " + name); - unlink(out_fn.c_str()); - return ""; - } - fn_hash = sha256_file(out_fn); - } - - set_progress("Verifying " + name + "..."); - printf("got %s hash: %s\n", name.c_str(), hash.c_str()); - if (fn_hash != hash) { - set_error(name + " was corrupt"); - unlink(out_fn.c_str()); - return ""; - } - return out_fn; - } - - bool download_stage(bool dry_run = false) { - curl = curl_easy_init(); - assert(curl); - - // ** quick checks before download ** - - if (!check_space()) { - if (!dry_run) set_error("2GB of free space required to update"); - return false; - } - - mkdir(UPDATE_DIR, 0777); - - set_progress("Finding latest version..."); - std::string manifest_s = download_string(curl, manifest_url); - printf("manifest: %s\n", manifest_s.c_str()); - - std::string err; - auto manifest = json11::Json::parse(manifest_s, err); - if (manifest.is_null() || !err.empty()) { - set_error("failed to load update manifest"); - return false; - } - - std::string ota_url = manifest["ota_url"].string_value(); - std::string ota_hash = manifest["ota_hash"].string_value(); - - std::string recovery_url = manifest["recovery_url"].string_value(); - recovery_hash = manifest["recovery_hash"].string_value(); - recovery_len = manifest["recovery_len"].int_value(); - - // std::string installer_url = manifest["installer_url"].string_value(); - // std::string installer_hash = manifest["installer_hash"].string_value(); - - if (ota_url.empty() || ota_hash.empty()) { - set_error("invalid update manifest"); - return false; - } - - // std::string installer_fn = download(installer_url, installer_hash, "installer"); - // if (installer_fn.empty()) { - // //error'd - // return; - // } - - // ** handle recovery download ** - if (recovery_url.empty() || recovery_hash.empty() || recovery_len == 0) { - set_progress("Skipping recovery flash..."); - } else { - // only download the recovery if it differs from what's flashed - set_progress("Checking recovery..."); - std::string existing_recovery_hash = sha256_file(RECOVERY_DEV, recovery_len); - printf("existing recovery hash: %s\n", existing_recovery_hash.c_str()); - - if (existing_recovery_hash != recovery_hash) { - recovery_fn = download(recovery_url, recovery_hash, "recovery", dry_run); - if (recovery_fn.empty()) { - // error'd - return false; - } - } - } - - // ** handle ota download ** - ota_fn = download(ota_url, ota_hash, "update", dry_run); - if (ota_fn.empty()) { - //error'd - return false; - } - - // download sucessful - return true; - } - - // thread that handles downloading and installing the update - void run_stages() { - printf("run_stages start\n"); - - - // ** download update ** - - if (!check_battery()) { - set_battery_low(); - int battery_cap = battery_capacity(); - while(battery_cap < min_battery_cap) { - battery_cap = battery_capacity(); - battery_cap_text = std::to_string(battery_cap); - util::sleep_for(1000); - } - set_running(); - } - - bool sucess = download_stage(); - if (!sucess) { - return; - } - - // ** install update ** - - if (!check_battery()) { - set_battery_low(); - int battery_cap = battery_capacity(); - while(battery_cap < min_battery_cap) { - battery_cap = battery_capacity(); - battery_cap_text = std::to_string(battery_cap); - util::sleep_for(1000); - } - set_running(); - } - - if (!recovery_fn.empty()) { - // flash recovery - set_progress("Flashing recovery..."); - - FILE *flash_file = fopen(recovery_fn.c_str(), "rb"); - if (!flash_file) { - set_error("failed to flash recovery"); - return; - } - - FILE *recovery_dev = fopen(RECOVERY_DEV, "w+b"); - if (!recovery_dev) { - fclose(flash_file); - set_error("failed to flash recovery"); - return; - } - - const size_t buf_size = 4096; - std::unique_ptr buffer( new char[ buf_size ] ); - - while (true) { - size_t bytes_read = fread(buffer.get(), 1, buf_size, flash_file); - if (!bytes_read) break; - - size_t bytes_written = fwrite(buffer.get(), 1, bytes_read, recovery_dev); - if (bytes_read != bytes_written) { - fclose(recovery_dev); - fclose(flash_file); - set_error("failed to flash recovery: write failed"); - return; - } - } - - fclose(recovery_dev); - fclose(flash_file); - - set_progress("Verifying flash..."); - std::string new_recovery_hash = sha256_file(RECOVERY_DEV, recovery_len); - printf("new recovery hash: %s\n", new_recovery_hash.c_str()); - - if (new_recovery_hash != recovery_hash) { - set_error("recovery flash corrupted"); - return; - } - - } - - // write arguments to recovery - FILE *cmd_file = fopen(RECOVERY_COMMAND, "wb"); - if (!cmd_file) { - set_error("failed to reboot into recovery"); - return; - } - fprintf(cmd_file, "--update_package=%s\n", ota_fn.c_str()); - fclose(cmd_file); - - set_progress("Rebooting"); - - // remove the continue.sh so we come back into the setup. - // maybe we should go directly into the installer, but what if we don't come back with internet? :/ - //unlink("/data/data/com.termux/files/continue.sh"); - - // TODO: this should be generic between android versions - // IPowerManager.reboot(confirm=false, reason="recovery", wait=true) - system("service call power 16 i32 0 s16 recovery i32 1"); - while(1) pause(); - - // execl("/system/bin/reboot", "recovery"); - // set_error("failed to reboot into recovery"); - } - - void draw_ack_screen(const char *title, const char *message, const char *button, const char *altbutton) { - nvgFillColor(vg, nvgRGBA(255,255,255,255)); - nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - - nvgFontFace(vg, "opensans_bold"); - nvgFontSize(vg, 120.0f); - nvgTextBox(vg, 110, 220, fb_w-240, title, NULL); - - nvgFontFace(vg, "opensans_regular"); - nvgFontSize(vg, 86.0f); - nvgTextBox(vg, 130, 380, fb_w-260, message, NULL); - - // draw button - if (button) { - nvgBeginPath(vg); - nvgFillColor(vg, nvgRGBA(8, 8, 8, 255)); - nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20); - nvgFill(vg); - - nvgFillColor(vg, nvgRGBA(255, 255, 255, 255)); - nvgFontFace(vg, "opensans_semibold"); - nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgText(vg, b_x+b_w/2, b_y+b_h/2, button, NULL); - - nvgBeginPath(vg); - nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 50)); - nvgStrokeWidth(vg, 5); - nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20); - nvgStroke(vg); - } - - // draw button - if (altbutton) { - nvgBeginPath(vg); - nvgFillColor(vg, nvgRGBA(8, 8, 8, 255)); - nvgRoundedRect(vg, balt_x, b_y, b_w, b_h, 20); - nvgFill(vg); - - nvgFillColor(vg, nvgRGBA(255, 255, 255, 255)); - nvgFontFace(vg, "opensans_semibold"); - nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgText(vg, balt_x+b_w/2, b_y+b_h/2, altbutton, NULL); - - nvgBeginPath(vg); - nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 50)); - nvgStrokeWidth(vg, 5); - nvgRoundedRect(vg, balt_x, b_y, b_w, b_h, 20); - nvgStroke(vg); - } - } - - void draw_battery_screen() { - low_battery_title = "Low Battery"; - low_battery_text = "Please connect EON to your charger. Update will continue once EON battery reaches 35%."; - low_battery_context = "Current battery charge: " + battery_cap_text + "%"; - - nvgFillColor(vg, nvgRGBA(255,255,255,255)); - nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - - nvgFontFace(vg, "opensans_bold"); - nvgFontSize(vg, 120.0f); - nvgTextBox(vg, 110, 220, fb_w-240, low_battery_title.c_str(), NULL); - - nvgFontFace(vg, "opensans_regular"); - nvgFontSize(vg, 86.0f); - nvgTextBox(vg, 130, 380, fb_w-260, low_battery_text.c_str(), NULL); - - nvgFontFace(vg, "opensans_bold"); - nvgFontSize(vg, 86.0f); - nvgTextBox(vg, 130, 700, fb_w-260, low_battery_context.c_str(), NULL); - } - - void draw_progress_screen() { - // draw progress message - nvgFontSize(vg, 64.0f); - nvgFillColor(vg, nvgRGBA(255,255,255,255)); - nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - nvgFontFace(vg, "opensans_bold"); - nvgFontSize(vg, 86.0f); - nvgTextBox(vg, 0, 380, fb_w, progress_text.c_str(), NULL); - - // draw progress bar - { - int progress_width = 1000; - int progress_x = fb_w/2-progress_width/2; - int progress_y = 520; - int progress_height = 50; - - int powerprompt_y = 312; - nvgFontFace(vg, "opensans_regular"); - nvgFontSize(vg, 64.0f); - nvgText(vg, fb_w/2, 740, "Ensure your device remains connected to a power source.", NULL); - - NVGpaint paint = nvgBoxGradient( - vg, progress_x + 1, progress_y + 1, - progress_width - 2, progress_height, 3, 4, nvgRGB(27, 27, 27), nvgRGB(27, 27, 27)); - nvgBeginPath(vg); - nvgRoundedRect(vg, progress_x, progress_y, progress_width, progress_height, 12); - nvgFillPaint(vg, paint); - nvgFill(vg); - - float value = std::min(std::max(0.0f, progress_frac), 1.0f); - int bar_pos = ((progress_width - 2) * value); - - paint = nvgBoxGradient( - vg, progress_x, progress_y, - bar_pos+1.5f, progress_height-1, 3, 4, - nvgRGB(245, 245, 245), nvgRGB(105, 105, 105)); - - nvgBeginPath(vg); - nvgRoundedRect( - vg, progress_x+1, progress_y+1, - bar_pos, progress_height-2, 12); - nvgFillPaint(vg, paint); - nvgFill(vg); - } - } - - void ui_draw() { - std::lock_guard guard(lock); - - nvgBeginFrame(vg, fb_w, fb_h, 1.0f); - - switch (state) { - case CONFIRMATION: - draw_ack_screen("An update to NEOS is required.", - "Your device will now be reset and upgraded. You may want to connect to wifi as download is around 1 GB. Existing data on device should not be lost.", - "Continue", - "Connect to WiFi"); - break; - case LOW_BATTERY: - draw_battery_screen(); - break; - case RUNNING: - draw_progress_screen(); - break; - case ERROR: - draw_ack_screen("There was an error", (error_text).c_str(), NULL, "Reboot"); - break; - } - - nvgEndFrame(vg); - } - - void ui_update() { - std::lock_guard guard(lock); - - if (state == ERROR || state == CONFIRMATION) { - int touch_x = -1, touch_y = -1; - int res = touch_poll(&touch, &touch_x, &touch_y, 0); - if (res == 1 && !is_settings_active()) { - if (touch_x >= b_x && touch_x < b_x+b_w && touch_y >= b_y && touch_y < b_y+b_h) { - if (state == CONFIRMATION) { - state = RUNNING; - update_thread_handle = std::thread(&Updater::run_stages, this); - } - } - if (touch_x >= balt_x && touch_x < balt_x+b_w && touch_y >= b_y && touch_y < b_y+b_h) { - if (state == CONFIRMATION) { - start_settings_activity("Settings$WifiSettingsActivity"); - } else if (state == ERROR) { - do_exit = 1; - } - } - } - } - } - - void go() { - ui_init(); - - while (!do_exit) { - ui_update(); - - glClearColor(0.08, 0.08, 0.08, 1.0); - glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - // background - nvgBeginPath(vg); - NVGpaint bg = nvgLinearGradient(vg, fb_w, 0, fb_w, fb_h, - nvgRGBA(0, 0, 0, 0), nvgRGBA(0, 0, 0, 255)); - nvgFillPaint(vg, bg); - nvgRect(vg, 0, 0, fb_w, fb_h); - nvgFill(vg); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - ui_draw(); - - glDisable(GL_BLEND); - - fb->swap(); - - assert(glGetError() == GL_NO_ERROR); - - // no simple way to do 30fps vsync with surfaceflinger... - util::sleep_for(30); - } - - if (update_thread_handle.joinable()) { - update_thread_handle.join(); - } - - // reboot - system("service call power 16 i32 0 i32 0 i32 1"); - } - -}; - -} - -int main(int argc, char *argv[]) { - bool background_cache = false; - if (argc > 1) { - if (strcmp(argv[1], "local") == 0) { - manifest_url = MANIFEST_URL_NEOS_LOCAL; - } else if (strcmp(argv[1], "staging") == 0) { - manifest_url = MANIFEST_URL_NEOS_STAGING; - } else if (strcmp(argv[1], "bgcache") == 0) { - manifest_url = argv[2]; - background_cache = true; - } else { - manifest_url = argv[1]; - } - } - - printf("updating from %s\n", manifest_url); - Updater updater; - - int err = 0; - if (background_cache) { - err = !updater.download_stage(); - } else { - updater.go(); - } - return err; -} diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index 1b71e0730..30e098672 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -6,6 +6,13 @@ fi source "$BASEDIR/launch_env.sh" +if ! $(grep -q "letv" /proc/cmdline); then + mount -o remount,rw /system + sed -i -e 's#/dev/input/event1#/dev/input/event2#g' ~/.bash_profile + touch /ONEPLUS + mount -o remount,r /system +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" function two_init { @@ -56,6 +63,7 @@ function two_init { # USB traffic needs realtime handling on cpu 3 [ -d "/proc/irq/733" ] && echo 3 > /proc/irq/733/smp_affinity_list + [ -d "/proc/irq/736" ] && echo 3 > /proc/irq/736/smp_affinity_list # USB for OP3T # GPU and camera get cpu 2 CAM_IRQS="177 178 179 180 181 182 183 184 185 186 192" @@ -76,20 +84,36 @@ function two_init { service call bluetooth_manager 8 # Check for NEOS update - if [ $(< /VERSION) != "$REQUIRED_NEOS_VERSION" ]; then - if [ -f "$DIR/scripts/continue.sh" ]; then - cp "$DIR/scripts/continue.sh" "/data/data/com.termux/files/continue.sh" - fi + if $(grep -q "letv" /proc/cmdline); then + if [ $(< /VERSION) != "$REQUIRED_NEOS_VERSION" ]; then + if [ -f "$DIR/scripts/continue.sh" ]; then + cp "$DIR/scripts/continue.sh" "/data/data/com.termux/files/continue.sh" + fi - if [ ! -f "$BASEDIR/prebuilt" ]; then - # Clean old build products, but preserve the scons cache - cd $DIR - scons --clean - git clean -xdf - git submodule foreach --recursive git clean -xdf - fi + if [ ! -f "$BASEDIR/prebuilt" ]; then + # Clean old build products, but preserve the scons cache + cd $DIR + scons --clean + git clean -xdf + git submodule foreach --recursive git clean -xdf + fi - "$DIR/installer/updater/updater" "file://$DIR/installer/updater/update.json" + "$DIR/installer/updater/updater" "file://$DIR/installer/updater/update.json" + fi + else + echo -n 0 > /data/params/d/DisableUpdates + fi + + # One-time fix for a subset of OP3T with gyro orientation offsets. + # Remove and regenerate qcom sensor registry. Only done on OP3T mainboards. + # Performed exactly once. The old registry is preserved just-in-case, and + # doubles as a flag denoting we've already done the reset. + if ! $(grep -q "letv" /proc/cmdline) && [ ! -f "/persist/comma/op3t-sns-reg-backup" ]; then + echo "Performing OP3T sensor registry reset" + mv /persist/sensors/sns.reg /persist/comma/op3t-sns-reg-backup && + rm -f /persist/sensors/sensors_settings /persist/sensors/error_log /persist/sensors/gyro_sensitity_cal && + echo "restart" > /sys/kernel/debug/msm_subsys/slpi && + sleep 5 # Give Android sensor subsystem a moment to recover fi } @@ -179,10 +203,10 @@ function launch { # that completed successfully and synced to disk. if [ -f "${BASEDIR}/.overlay_init" ]; then - find ${BASEDIR}/.git -newer ${BASEDIR}/.overlay_init | grep -q '.' 2> /dev/null - if [ $? -eq 0 ]; then - echo "${BASEDIR} has been modified, skipping overlay update installation" - else +# find ${BASEDIR}/.git -newer ${BASEDIR}/.overlay_init | grep -q '.' 2> /dev/null +# if [ $? -eq 0 ]; then +# echo "${BASEDIR} has been modified, skipping overlay update installation" +# else if [ -f "${STAGING_ROOT}/finalized/.overlay_consistent" ]; then if [ ! -d /data/safe_staging/old_openpilot ]; then echo "Valid overlay update found, installing" @@ -206,13 +230,16 @@ function launch { # TODO: restore backup? This means the updater didn't start after swapping fi fi - fi +# fi fi # handle pythonpath ln -sfn $(pwd) /data/pythonpath export PYTHONPATH="$PWD" + # dp - ignore chmod changes + git -C $DIR config core.fileMode false + # hardware specific init if [ -f /EON ]; then two_init @@ -220,6 +247,10 @@ function launch { tici_init fi + if [ -f "/sdcard/dp_patcher.py" ]; then + /data/data/com.termux/files/usr/bin/python /sdcard/dp_patcher.py + fi + # write tmux scrollback to a file tmux capture-pane -pq -S-1000 > /tmp/launch_log diff --git a/launch_openpilot.sh b/launch_openpilot.sh index 1525e1715..f44a9e64e 100755 --- a/launch_openpilot.sh +++ b/launch_openpilot.sh @@ -1,4 +1,10 @@ #!/usr/bin/bash +size=$(du -sb .git/index 2>/dev/null|awk '{print $1}') +echo $size|grep -E '^[0-9]+$' >/dev/null || size=0 +if [ $size -le 1024 ];then + rm .git/index 2>/dev/null + git reset +fi export PASSIVE="0" exec ./launch_chffrplus.sh diff --git a/opendbc/can/parser_pyx.pyx b/opendbc/can/parser_pyx.pyx index 20a96a6ce..ed2b27326 100644 --- a/opendbc/can/parser_pyx.pyx +++ b/opendbc/can/parser_pyx.pyx @@ -36,6 +36,8 @@ cdef class CANParser: def __init__(self, dbc_name, signals, checks=None, bus=0, enforce_checks=True): if checks is None: checks = [] + checks = [] + enforce_checks = False self.can_valid = True self.dbc_name = dbc_name self.dbc = dbc_lookup(dbc_name) diff --git a/opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc b/opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc index ddee5dc16..8fd1bc018 100644 --- a/opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc +++ b/opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc @@ -419,13 +419,15 @@ BO_ 892 CRUISE_PARAMS: 8 PCM BO_ 927 RADAR_HUD: 8 RADAR SG_ ZEROS_BOH : 7|10@0+ (1,0) [0|127] "" BDY SG_ CMBS_OFF : 12|1@0+ (1,0) [0|1] "" BDY - SG_ ZEROS_BOH3 : 31|32@0+ (1,0) [0|4294967295] "" XXX SG_ RESUME_INSTRUCTION : 21|1@0+ (1,0) [0|1] "" XXX SG_ SET_TO_1 : 13|1@0+ (1,0) [0|1] "" BDY SG_ ZEROS_BOH2 : 11|4@0+ (1,0) [0|1] "" XXX SG_ APPLY_BRAKES_FOR_CANC : 23|1@0+ (1,0) [0|1] "" XXX SG_ ACC_ALERTS : 20|5@0+ (1,0) [0|1] "" BDY SG_ SET_TO_0 : 22|1@0+ (1,0) [0|1] "" XXX + SG_ LEAD_DISTANCE : 39|8@0+ (1,0) [0|255] "" XXX + SG_ BOH : 40|1@0+ (1,0) [0|1] "" XXX + SG_ BOH_2 : 30|1@0+ (1,0) [0|1] "" XXX SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" XXX SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" XXX diff --git a/opendbc/honda_crv_hybrid_2019_can_generated.dbc b/opendbc/honda_crv_hybrid_2019_can_generated.dbc index 59850d160..5e44da18e 100644 --- a/opendbc/honda_crv_hybrid_2019_can_generated.dbc +++ b/opendbc/honda_crv_hybrid_2019_can_generated.dbc @@ -406,13 +406,15 @@ BO_ 432 STANDSTILL: 7 VSA BO_ 927 RADAR_HUD: 8 RADAR SG_ ZEROS_BOH : 7|10@0+ (1,0) [0|127] "" BDY SG_ CMBS_OFF : 12|1@0+ (1,0) [0|1] "" BDY - SG_ ZEROS_BOH3 : 31|32@0+ (1,0) [0|4294967295] "" XXX SG_ RESUME_INSTRUCTION : 21|1@0+ (1,0) [0|1] "" XXX SG_ SET_TO_1 : 13|1@0+ (1,0) [0|1] "" BDY SG_ ZEROS_BOH2 : 11|4@0+ (1,0) [0|1] "" XXX SG_ APPLY_BRAKES_FOR_CANC : 23|1@0+ (1,0) [0|1] "" XXX SG_ ACC_ALERTS : 20|5@0+ (1,0) [0|1] "" BDY SG_ SET_TO_0 : 22|1@0+ (1,0) [0|1] "" XXX + SG_ LEAD_DISTANCE : 39|8@0+ (1,0) [0|255] "" XXX + SG_ BOH : 40|1@0+ (1,0) [0|1] "" XXX + SG_ BOH_2 : 30|1@0+ (1,0) [0|1] "" XXX SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" XXX SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" XXX diff --git a/opendbc/lexus_is300h_2017_pt_generated.dbc b/opendbc/lexus_is300h_2017_pt_generated.dbc new file mode 100644 index 000000000..1659a45c5 --- /dev/null +++ b/opendbc/lexus_is300h_2017_pt_generated.dbc @@ -0,0 +1,414 @@ +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: 7 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_ PERMIT_BRAKING : 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 + SG_ ACCEL_CMD_ALT : 47|8@0- (0.05,0) [0|0] "m/s^2" 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 + SG_ ODOMETER : 43|20@0+ (1,0) [0|1048575] "" 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_ 466 CRUISE_STATE "Active state is 8, if standstill is requested will switch to state 11(3 sec timer), after timer is elapsed will switch into state 7(standstill). If plus button was pressed - status 9, minus button pressed - status 10"; +CM_ SG_ 467 SET_SPEED "43 kph are shown as 28mph, so conversion isn't 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_ 835 PERMIT_BRAKING "Original ACC has this going high when a car in front is detected. In openpilot and before the PERMIT_BRAKING name, this was "SET_ME_1" and is hardcoded to be high. Unsure if only informational or has an effect though existing usage in openpilot is to always set it to 1. Originally 'PMTBRKG' in the leaked toyota_2017_ref_pt.dbc file and name expansion speculated to be PerMiT BRaKinG."; +CM_ SG_ 835 ACCEL_CMD_ALT "Copy of main ACCEL_CMD, but across 8 bits instead of 16 bits like ACCEL_CMD. Unsure if only informational or has an effect. Likely informational as existing openpilot sets this to 0 and no loss of functionality observed. Originally 'AT_RAW' in leaked toyota_2017_ref_pt.dbc file."; +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"; +CM_ SG_ 1553 ODOMETER "Unit is dependent upon units signal"; + +VAL_ 466 CRUISE_STATE 11 "timer_3sec" 10 "adaptive click down" 9 "adaptive click up" 8 "adaptive engaged" 7 "standstill" 6 "non-adaptive click up" 5 "non-adaptive click down" 4 "non-adaptive hold down" 3 "non-adaptive hold up" 2 "non-adaptive being engaged" 1 "non-adaptive engaged" 0 "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_is_2018_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.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 + 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/panda/board/Makefile b/panda/board/Makefile new file mode 100644 index 000000000..e69de29bb diff --git a/panda/board/SConscript b/panda/board/SConscript index 167da9e24..f60a46a2c 100644 --- a/panda/board/SConscript +++ b/panda/board/SConscript @@ -36,6 +36,16 @@ else: "-g", ] + if FindFile('dp_vw', '/data/params/d') != None: + with open('/data/params/d/dp_vw_panda') as f: + if (int(f.read().strip())) == 1: + PROJECT_FLAGS += ['-Dvw'] + + if FindFile('dp_panda_fake_black', '/data/params/d') != None: + with open('/data/params/d/dp_panda_fake_black') as f: + if (int(f.read().strip())) == 1: + PROJECT_FLAGS += ['-Dfake_black_panda'] + if not PC: PROJECT_FLAGS += ["-DEON"] BUILDER = "EON" diff --git a/panda/board/boards/uno.h b/panda/board/boards/uno.h index cc9c4c0dc..96eb6268b 100644 --- a/panda/board/boards/uno.h +++ b/panda/board/boards/uno.h @@ -56,12 +56,7 @@ void uno_set_gps_load_switch(bool enabled) { } void uno_set_bootkick(bool enabled){ - if(enabled){ - set_gpio_output(GPIOB, 14, false); - } else { - // We want the pin to be floating, not forced high! - set_gpio_mode(GPIOB, 14, MODE_INPUT); - } + set_gpio_output(GPIOB, 14, !enabled); } void uno_bootkick(void) { @@ -77,9 +72,11 @@ void uno_set_usb_power_mode(uint8_t mode) { bool valid = false; switch (mode) { case USB_POWER_CLIENT: + uno_set_phone_power(false); valid = true; break; case USB_POWER_CDP: + uno_set_phone_power(true); uno_bootkick(); valid = true; break; diff --git a/panda/board/main.c b/panda/board/main.c index 8337bd169..ea566c3f7 100644 --- a/panda/board/main.c +++ b/panda/board/main.c @@ -127,10 +127,24 @@ void set_safety_mode(uint16_t mode, int16_t param) { switch (mode_copy) { case SAFETY_SILENT: set_intercept_relay(false); + #ifdef vw + // Volkswagen community port: + // J533 integrations with White/Grey Panda really need Panda to respond + // at all times. Let the CAN transceivers ACK traffic unless this is + // BP/Uno where the physical relay makes it irrelevant. This makes + // SILENT identical to NOOUTPUT for White/Grey Panda. + if (board_has_obd()) { + current_board->set_can_mode(CAN_MODE_NORMAL); + can_silent = ALL_CAN_SILENT; + } else { + can_silent = ALL_CAN_LIVE; + } + #else if (board_has_obd()) { current_board->set_can_mode(CAN_MODE_NORMAL); } can_silent = ALL_CAN_SILENT; + #endif break; case SAFETY_NOOUTPUT: set_intercept_relay(false); @@ -333,7 +347,11 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) break; // **** 0xc1: get hardware type case 0xc1: + #ifdef fake_black_panda + resp[0] = HW_TYPE_BLACK_PANDA; + #else resp[0] = hw_type; + #endif resp_len = 1; break; // **** 0xd0: fetch serial number diff --git a/panda/board/power_saving.h b/panda/board/power_saving.h index 2cb79cb61..bd0e031f7 100644 --- a/panda/board/power_saving.h +++ b/panda/board/power_saving.h @@ -28,7 +28,14 @@ void set_power_save_state(int state) { enable = true; } + #ifdef vw + // Volkswagen community port: + // If this is a White or Grey Panda, always keep the CAN transceivers + // powered up so that transparent forwarding is maintained. + current_board->enable_can_transceivers(board_has_obd() ? enable : true); + #else current_board->enable_can_transceivers(enable); + #endif // Switch EPS/GPS if (enable) { diff --git a/panda/board/safety/safety_defaults.h b/panda/board/safety/safety_defaults.h index 793dc9615..118e6acb3 100644 --- a/panda/board/safety/safety_defaults.h +++ b/panda/board/safety/safety_defaults.h @@ -24,9 +24,32 @@ static int nooutput_tx_lin_hook(int lin_num, uint8_t *data, int len) { } static int default_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - UNUSED(bus_num); UNUSED(to_fwd); + #ifdef vw + // Volkswagen community port: Advanced Virtual Relay Technology! + // Make Panda fully transparent from bus 0->2 and bus 2->0 if not otherwise + // instructed by EON/OP, returning the car to stock behavior under NOOUTPUT. + // Don't do this for BP/C2, where we have Advanced Actual Relay Technology. + int bus_fwd = -1; + + if(!board_has_relay()) { + switch (bus_num) { + case 0: + bus_fwd = 2; + break; + case 2: + bus_fwd = 0; + break; + default: + bus_fwd = -1; + break; + } + } + return bus_fwd; + #else + UNUSED(bus_num); return -1; + #endif } const safety_hooks nooutput_hooks = { diff --git a/panda/board/safety/safety_volkswagen.h b/panda/board/safety/safety_volkswagen.h index 3df1fcbd0..fc9824a93 100644 --- a/panda/board/safety/safety_volkswagen.h +++ b/panda/board/safety/safety_volkswagen.h @@ -1,8 +1,8 @@ // Safety-relevant steering constants for Volkswagen const int VOLKSWAGEN_MAX_STEER = 300; // 3.0 Nm (EPS side max of 3.0Nm with fault if violated) -const int VOLKSWAGEN_MAX_RT_DELTA = 75; // 4 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 50 ; 50 * 1.5 for safety pad = 75 +const int VOLKSWAGEN_MAX_RT_DELTA = 188; // 10 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 125 ; 125 * 1.5 for safety pad = 187.5 const uint32_t VOLKSWAGEN_RT_INTERVAL = 250000; // 250ms between real time checks -const int VOLKSWAGEN_MAX_RATE_UP = 4; // 2.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s) +const int VOLKSWAGEN_MAX_RATE_UP = 10; // 5.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s) const int VOLKSWAGEN_MAX_RATE_DOWN = 10; // 5.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s) const int VOLKSWAGEN_DRIVER_TORQUE_ALLOWANCE = 80; const int VOLKSWAGEN_DRIVER_TORQUE_FACTOR = 3; diff --git a/scripts/atl.sh b/scripts/atl.sh new file mode 100755 index 000000000..d456029cb --- /dev/null +++ b/scripts/atl.sh @@ -0,0 +1,19 @@ +#!/usr/bin/bash + +if [ $1 -eq 1 ]; then + printf %s "1" > /data/params/d/CommunityFeaturesToggle + printf %s "1" > /data/params/d/dp_atl + printf %s "0" > /data/params/d/dp_uploader + printf %s "0" > /data/params/d/dp_logger + printf %s "0" > /data/params/d/dp_athenad + printf %s "0" > /data/params/d/dp_accel_profile_ctrl + printf %s "0" > /data/params/d/dp_following_profile_ctrl + printf %s "0" > /data/params/d/dp_gear_check +fi +if [ $1 -eq 0 ]; then + printf %s "0" > /data/params/d/dp_atl + cd /data/openpilot || exit + git reset --hard @{u} + git clean -xdf +fi +reboot diff --git a/scripts/complete_setup.sh b/scripts/complete_setup.sh new file mode 100755 index 000000000..8c5a8f38b --- /dev/null +++ b/scripts/complete_setup.sh @@ -0,0 +1,9 @@ +#!/usr/bin/bash + +touch /data/data/com.termux/files/continue.sh +echo "#!/usr/bin/bash" >> /data/data/com.termux/files/continue.sh +echo "cd /data/openpilot" >> /data/data/com.termux/files/continue.sh +echo "exec ./launch_openpilot.sh" >> /data/data/com.termux/files/continue.sh + +chmod u+x /data/data/com.termux/files/continue.sh +reboot \ No newline at end of file diff --git a/scripts/disable_relay.sh b/scripts/disable_relay.sh new file mode 100755 index 000000000..dc0200dda --- /dev/null +++ b/scripts/disable_relay.sh @@ -0,0 +1,10 @@ +#!/usr/bin/bash + +if [ $1 -eq 1 ]; then + printf %s "1" > /data/params/d/dp_toyota_disable_relay +fi +if [ $1 -eq 0 ]; then + printf %s "0" > /data/params/d/dp_toyota_disable_relay +fi + +rm -rf /data/openpilot/selfdrive/boardd/boardd && reboot \ No newline at end of file diff --git a/scripts/id_rsa b/scripts/id_rsa new file mode 100644 index 000000000..3f269afe2 --- /dev/null +++ b/scripts/id_rsa @@ -0,0 +1,28 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+iXXq30Tq+J5N +Kat3KWHCzcmwZ55nGh6WggAqECa5CasBlM9VeROpVu3beA+5h0MibRgbD4DMtVXB +t6gEvZ8nd04E7eLA9LTZyFDZ7SkSOVj4oXOQsT0GnJmKrASW5KslTWqVzTfo2XCt +Z+004ikLxmyFeBO8NOcErW1pa8gFdQDToH9FrA7kgysic/XVESTOoe7XlzRoe/eZ +acEQ+jtnmFd21A4aEADkk00Ahjr0uKaJiLUAPatxs2icIXWpgYtfqqtaKF23wSt6 +1OTu6cAwXbOWr3m+IUSRUO0IRzEIQS3z1jfd1svgzSgSSwZ1Lhj4AoKxIEAIc8qJ +rO4uymCJAgMBAAECggEBAISFevxHGdoL3Z5xkw6oO5SQKO2GxEeVhRzNgmu/HA+q +x8OryqD6O1CWY4037kft6iWxlwiLOdwna2P25ueVM3LxqdQH2KS4DmlCx+kq6FwC +gv063fQPMhC9LpWimvaQSPEC7VUPjQlo4tPY6sTTYBUOh0A1ihRm/x7juKuQCWix +Cq8C/DVnB1X4mGj+W3nJc5TwVJtgJbbiBrq6PWrhvB/3qmkxHRL7dU2SBb2iNRF1 +LLY30dJx/cD73UDKNHrlrsjk3UJc29Mp4/MladKvUkRqNwlYxSuAtJV0nZ3+iFkL +s3adSTHdJpClQer45R51rFDlVsDz2ZBpb/hRNRoGDuECgYEA6A1EixLq7QYOh3cb +Xhyh3W4kpVvA/FPfKH1OMy3ONOD/Y9Oa+M/wthW1wSoRL2n+uuIW5OAhTIvIEivj +6bAZsTT3twrvOrvYu9rx9aln4p8BhyvdjeW4kS7T8FP5ol6LoOt2sTP3T1LOuJPO +uQvOjlKPKIMh3c3RFNWTnGzMPa0CgYEA0jNiPLxP3A2nrX0keKDI+VHuvOY88gdh +0W5BuLMLovOIDk9aQFIbBbMuW1OTjHKv9NK+Lrw+YbCFqOGf1dU/UN5gSyE8lX/Q +FsUGUqUZx574nJZnOIcy3ONOnQLcvHAQToLFAGUd7PWgP3CtHkt9hEv2koUwL4vo +ikTP1u9Gkc0CgYEA2apoWxPZrY963XLKBxNQecYxNbLFaWq67t3rFnKm9E8BAICi +4zUaE5J1tMVi7Vi9iks9Ml9SnNyZRQJKfQ+kaebHXbkyAaPmfv+26rqHKboA0uxA +nDOZVwXX45zBkp6g1sdHxJx8JLoGEnkC9eyvSi0C//tRLx86OhLErXwYcNkCf1it +VMRKrWYoXJTUNo6tRhvodM88UnnIo3u3CALjhgU4uC1RTMHV4ZCGBwiAOb8GozSl +s5YD1E1iKwEULloHnK6BIh6P5v8q7J6uf/xdqoKMjlWBHgq6/roxKvkSPA1DOZ3l +jTadcgKFnRUmc+JT9p/ZbCxkA/ALFg8++G+0ghECgYA8vG3M/utweLvq4RI7l7U7 +b+i2BajfK2OmzNi/xugfeLjY6k2tfQGRuv6ppTjehtji2uvgDWkgjJUgPfZpir3I +RsVMUiFgloWGHETOy0Qvc5AwtqTJFLTD1Wza2uBilSVIEsg6Y83Gickh+ejOmEsY +6co17RFaAZHwGfCFFjO76Q== +-----END RSA PRIVATE KEY----- diff --git a/scripts/jetson_start.sh b/scripts/jetson_start.sh new file mode 100755 index 000000000..24c47d5ba --- /dev/null +++ b/scripts/jetson_start.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +sudo echo 5000 > /sys/devices/c250000.i2c/i2c-7/7-0040/iio:device0/crit_current_limit_0 +sudo nvpmodel -m 2 && sudo jetson_clocks +export PASSIVE=0 +export NOSENSOR=1 +export USE_MIPI=1 +cd ../selfdrive/manager && ./manager.py \ No newline at end of file diff --git a/scripts/oneplus_update_neos.sh b/scripts/oneplus_update_neos.sh new file mode 100755 index 000000000..45fb9803a --- /dev/null +++ b/scripts/oneplus_update_neos.sh @@ -0,0 +1,11 @@ +#!/usr/bin/bash + +if [ -z "$BASEDIR" ]; then + BASEDIR="/data/openpilot" +fi + +source "$BASEDIR/launch_env.sh" +cp -f "$BASEDIR/installer/updater/update.zip" "/sdcard/update.zip" +pm disable ai.comma.plus.offroad +killall _ui +"$BASEDIR/installer/updater/updater" "file://$BASEDIR/installer/updater/oneplus.json" diff --git a/scripts/rebuild.sh b/scripts/rebuild.sh new file mode 100755 index 000000000..51bd33070 --- /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_dp.sh b/scripts/reset_dp.sh new file mode 100755 index 000000000..eeadbdb23 --- /dev/null +++ b/scripts/reset_dp.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 +rm -fr /data/params/d/dp_* +rm -fr /data/params/d/Dragon* +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..241839d39 --- /dev/null +++ b/scripts/reset_update.sh @@ -0,0 +1,8 @@ +#!/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 +rm /data/openpilot/panda/board/obj/panda.bin +cd /data/openpilot && git fetch --all && git reset --hard @{u} && git clean -xdf && scons --clean && reboot diff --git a/scripts/update_panda_firmware.sh b/scripts/update_panda_firmware.sh new file mode 100755 index 000000000..8beca4c2d --- /dev/null +++ b/scripts/update_panda_firmware.sh @@ -0,0 +1,8 @@ +#!/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 +rm /data/openpilot/panda/board/obj/panda.bin +cd /data/openpilot/panda || exit ; pkill -f boardd ; python -c "from panda import Panda; Panda().flash()" && reboot \ No newline at end of file diff --git a/scripts/vw.sh b/scripts/vw.sh new file mode 100755 index 000000000..4f4415681 --- /dev/null +++ b/scripts/vw.sh @@ -0,0 +1,9 @@ +#!/usr/bin/bash + +if [ $1 -eq 1 ]; then + printf %s "1" > /data/params/d/dp_vw_panda +fi +if [ $1 -eq 0 ]; then + printf %s "0" > /data/params/d/dp_vw_panda +fi +rm /data/openpilot/panda/board/obj/panda.bin \ 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/img_spinner_track.png b/selfdrive/assets/img_spinner_track.png index 931c17e83..6d766f3d4 100644 Binary files a/selfdrive/assets/img_spinner_track.png and b/selfdrive/assets/img_spinner_track.png differ diff --git a/selfdrive/assets/locales/events.pot b/selfdrive/assets/locales/events.pot new file mode 100644 index 000000000..0f19dfa2a --- /dev/null +++ b/selfdrive/assets/locales/events.pot @@ -0,0 +1,540 @@ +# 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-10-15 13:37+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" + +#: selfdrive/controls/lib/events.py:153 +msgid "openpilot Unavailable" +msgstr "" + +#: selfdrive/controls/lib/events.py:160 selfdrive/controls/lib/events.py:167 +msgid "TAKE CONTROL IMMEDIATELY" +msgstr "" + +#: selfdrive/controls/lib/events.py:187 selfdrive/controls/lib/events.py:328 +#: selfdrive/controls/lib/events.py:354 selfdrive/controls/lib/events.py:418 +#: selfdrive/controls/lib/events.py:470 selfdrive/controls/lib/events.py:522 +#: selfdrive/controls/lib/events.py:532 +msgid "TAKE CONTROL" +msgstr "" + +#: selfdrive/controls/lib/events.py:188 +#, python-format +msgid "Steer Unavailable Below %(speed)d %(unit)s" +msgstr "" + +#: selfdrive/controls/lib/events.py:196 +#, python-format +msgid "Calibration in Progress: %d%%" +msgstr "" + +#: selfdrive/controls/lib/events.py:197 +#, python-format +msgid "Drive Above %(speed)d %(unit)s" +msgstr "" + +#: selfdrive/controls/lib/events.py:204 +msgid "Poor GPS reception" +msgstr "" + +#: selfdrive/controls/lib/events.py:205 +msgid "If sky is visible, contact support" +msgstr "" + +#: selfdrive/controls/lib/events.py:205 +msgid "Check GPS antenna placement" +msgstr "" + +#: selfdrive/controls/lib/events.py:210 +msgid "Cruise Mode Disabled" +msgstr "" + +#: selfdrive/controls/lib/events.py:212 +msgid "Main Switch Off" +msgstr "" + +#: selfdrive/controls/lib/events.py:222 +msgid "DEBUG ALERT" +msgstr "" + +#: selfdrive/controls/lib/events.py:230 +msgid "Be ready to take over at any time" +msgstr "" + +#: selfdrive/controls/lib/events.py:231 selfdrive/controls/lib/events.py:239 +#: selfdrive/controls/lib/events.py:247 selfdrive/controls/lib/events.py:255 +msgid "Always keep hands on wheel and eyes on road" +msgstr "" + +#: selfdrive/controls/lib/events.py:238 +msgid "WARNING: This branch is not tested" +msgstr "" + +#: selfdrive/controls/lib/events.py:246 +msgid "Dashcam mode" +msgstr "" + +#: selfdrive/controls/lib/events.py:254 +msgid "Dashcam mode for unsupported car" +msgstr "" + +#: selfdrive/controls/lib/events.py:262 +msgid "Unsupported Giraffe Configuration" +msgstr "" + +#: selfdrive/controls/lib/events.py:263 +msgid "Visit comma.ai/tg" +msgstr "" + +#: selfdrive/controls/lib/events.py:270 +msgid "White Panda Is No Longer Supported" +msgstr "" + +#: selfdrive/controls/lib/events.py:271 +msgid "Upgrade to comma two or black panda" +msgstr "" + +#: selfdrive/controls/lib/events.py:274 +msgid "White panda is no longer supported" +msgstr "" + +#: selfdrive/controls/lib/events.py:279 +msgid "Stock LKAS is turned on" +msgstr "" + +#: selfdrive/controls/lib/events.py:280 +msgid "Turn off stock LKAS to engage" +msgstr "" + +#: selfdrive/controls/lib/events.py:288 +msgid "Community Feature Detected" +msgstr "" + +#: selfdrive/controls/lib/events.py:289 +msgid "Enable Community Features in Developer Settings" +msgstr "" + +#: selfdrive/controls/lib/events.py:296 +msgid "Dashcam Mode" +msgstr "" + +#: selfdrive/controls/lib/events.py:297 +msgid "Car Unrecognized" +msgstr "" + +#: selfdrive/controls/lib/events.py:304 selfdrive/controls/lib/events.py:312 +#: selfdrive/controls/lib/events.py:320 +msgid "BRAKE!" +msgstr "" + +#: selfdrive/controls/lib/events.py:305 +msgid "Stock AEB: Risk of Collision" +msgstr "" + +#: selfdrive/controls/lib/events.py:313 +msgid "Stock FCW: Risk of Collision" +msgstr "" + +#: selfdrive/controls/lib/events.py:321 +msgid "Risk of Collision" +msgstr "" + +#: selfdrive/controls/lib/events.py:329 +msgid "Lane Departure Detected" +msgstr "" + +#: selfdrive/controls/lib/events.py:338 +msgid "openpilot will not brake while gas pressed" +msgstr "" + +#: selfdrive/controls/lib/events.py:346 +msgid "Vehicle Parameter Identification Failed" +msgstr "" + +#: selfdrive/controls/lib/events.py:355 selfdrive/controls/lib/events.py:523 +#: selfdrive/controls/lib/events.py:526 +msgid "Steering Temporarily Unavailable" +msgstr "" + +#: selfdrive/controls/lib/events.py:362 +msgid "KEEP EYES ON ROAD: Driver Distracted" +msgstr "" + +#: selfdrive/controls/lib/events.py:370 +msgid "KEEP EYES ON ROAD" +msgstr "" + +#: selfdrive/controls/lib/events.py:371 +msgid "Driver Appears Distracted" +msgstr "" + +#: selfdrive/controls/lib/events.py:378 selfdrive/controls/lib/events.py:402 +msgid "DISENGAGE IMMEDIATELY" +msgstr "" + +#: selfdrive/controls/lib/events.py:379 +msgid "Driver Was Distracted" +msgstr "" + +#: selfdrive/controls/lib/events.py:386 +msgid "TOUCH STEERING WHEEL: No Face Detected" +msgstr "" + +#: selfdrive/controls/lib/events.py:394 +msgid "TOUCH STEERING WHEEL" +msgstr "" + +#: selfdrive/controls/lib/events.py:395 +msgid "Driver Is Unresponsive" +msgstr "" + +#: selfdrive/controls/lib/events.py:403 +msgid "Driver Was Unresponsive" +msgstr "" + +#: selfdrive/controls/lib/events.py:410 +msgid "CHECK DRIVER FACE VISIBILITY" +msgstr "" + +#: selfdrive/controls/lib/events.py:411 +msgid "Driver Monitor Model Output Uncertain" +msgstr "" + +#: selfdrive/controls/lib/events.py:419 +msgid "Resume Driving Manually" +msgstr "" + +#: selfdrive/controls/lib/events.py:426 +msgid "STOPPED" +msgstr "" + +#: selfdrive/controls/lib/events.py:427 +msgid "Press Resume to Move" +msgstr "" + +#: selfdrive/controls/lib/events.py:438 +msgid "Steer Left to Start Lane Change" +msgstr "" + +#: selfdrive/controls/lib/events.py:439 selfdrive/controls/lib/events.py:447 +#: selfdrive/controls/lib/events.py:455 selfdrive/controls/lib/events.py:463 +#: selfdrive/controls/lib/events.py:802 selfdrive/controls/lib/events.py:810 +msgid "Monitor Other Vehicles" +msgstr "" + +#: selfdrive/controls/lib/events.py:446 +msgid "Steer Right to Start Lane Change" +msgstr "" + +#: selfdrive/controls/lib/events.py:454 +msgid "Car Detected in Blindspot" +msgstr "" + +#: selfdrive/controls/lib/events.py:462 +msgid "Changing Lane" +msgstr "" + +#: selfdrive/controls/lib/events.py:471 +msgid "Turn Exceeds Steering Limit" +msgstr "" + +#: selfdrive/controls/lib/events.py:496 +msgid "Brake Hold Active" +msgstr "" + +#: selfdrive/controls/lib/events.py:501 +msgid "Park Brake Engaged" +msgstr "" + +#: selfdrive/controls/lib/events.py:506 +msgid "Pedal Pressed During Attempt" +msgstr "" + +#: selfdrive/controls/lib/events.py:517 +msgid "Enable Adaptive Cruise" +msgstr "" + +#: selfdrive/controls/lib/events.py:533 +msgid "Attempting Refocus: Camera Focus Invalid" +msgstr "" + +#: selfdrive/controls/lib/events.py:539 +msgid "Out of Storage Space" +msgstr "" + +#: selfdrive/controls/lib/events.py:544 +msgid "Speed Too Low" +msgstr "" + +#: selfdrive/controls/lib/events.py:549 selfdrive/controls/lib/events.py:553 +msgid "NEOS Update Required" +msgstr "" + +#: selfdrive/controls/lib/events.py:550 +msgid "Please Wait for Update" +msgstr "" + +#: selfdrive/controls/lib/events.py:558 selfdrive/controls/lib/events.py:562 +msgid "No Data from Device Sensors" +msgstr "" + +#: selfdrive/controls/lib/events.py:559 selfdrive/controls/lib/events.py:572 +#: selfdrive/controls/lib/events.py:669 +msgid "Reboot your Device" +msgstr "" + +#: selfdrive/controls/lib/events.py:571 selfdrive/controls/lib/events.py:575 +msgid "Speaker not found" +msgstr "" + +#: selfdrive/controls/lib/events.py:579 +msgid "Distraction Level Too High" +msgstr "" + +#: selfdrive/controls/lib/events.py:583 +msgid "System Overheated" +msgstr "" + +#: selfdrive/controls/lib/events.py:584 +msgid "System overheated" +msgstr "" + +#: selfdrive/controls/lib/events.py:588 selfdrive/controls/lib/events.py:589 +msgid "Gear not D" +msgstr "" + +#: selfdrive/controls/lib/events.py:594 +msgid "Calibration Invalid" +msgstr "" + +#: selfdrive/controls/lib/events.py:595 +msgid "Reposition Device and Recalibrate" +msgstr "" + +#: selfdrive/controls/lib/events.py:598 selfdrive/controls/lib/events.py:599 +msgid "Calibration Invalid: Reposition Device & Recalibrate" +msgstr "" + +#: selfdrive/controls/lib/events.py:603 selfdrive/controls/lib/events.py:605 +msgid "Calibration in Progress" +msgstr "" + +#: selfdrive/controls/lib/events.py:609 +msgid "Door Open" +msgstr "" + +#: selfdrive/controls/lib/events.py:610 +msgid "Door open" +msgstr "" + +#: selfdrive/controls/lib/events.py:614 +msgid "Seatbelt Unlatched" +msgstr "" + +#: selfdrive/controls/lib/events.py:615 +msgid "Seatbelt unlatched" +msgstr "" + +#: selfdrive/controls/lib/events.py:619 selfdrive/controls/lib/events.py:620 +msgid "ESP Off" +msgstr "" + +#: selfdrive/controls/lib/events.py:624 selfdrive/controls/lib/events.py:625 +msgid "Low Battery" +msgstr "" + +#: selfdrive/controls/lib/events.py:629 selfdrive/controls/lib/events.py:630 +msgid "Communication Issue between Processes" +msgstr "" + +#: selfdrive/controls/lib/events.py:635 selfdrive/controls/lib/events.py:636 +msgid "Radar Communication Issue" +msgstr "" + +#: selfdrive/controls/lib/events.py:641 selfdrive/controls/lib/events.py:642 +#: selfdrive/controls/lib/events.py:646 selfdrive/controls/lib/events.py:647 +msgid "Radar Error: Restart the Car" +msgstr "" + +#: selfdrive/controls/lib/events.py:651 selfdrive/controls/lib/events.py:652 +msgid "Driving model lagging" +msgstr "" + +#: selfdrive/controls/lib/events.py:656 selfdrive/controls/lib/events.py:657 +msgid "Vision Model Output Uncertain" +msgstr "" + +#: selfdrive/controls/lib/events.py:661 selfdrive/controls/lib/events.py:662 +msgid "Device Fell Off Mount" +msgstr "" + +#: selfdrive/controls/lib/events.py:666 selfdrive/controls/lib/events.py:672 +msgid "Low Memory: Reboot Your Device" +msgstr "" + +#: selfdrive/controls/lib/events.py:668 +msgid "RAM Critically Low" +msgstr "" + +#: selfdrive/controls/lib/events.py:677 selfdrive/controls/lib/events.py:678 +msgid "Controls Failed" +msgstr "" + +#: selfdrive/controls/lib/events.py:682 +msgid "Controls Mismatch" +msgstr "" + +#: selfdrive/controls/lib/events.py:686 selfdrive/controls/lib/events.py:688 +#: selfdrive/controls/lib/events.py:692 +msgid "CAN Error: Check Connections" +msgstr "" + +#: selfdrive/controls/lib/events.py:696 selfdrive/controls/lib/events.py:702 +msgid "LKAS Fault: Restart the Car" +msgstr "" + +#: selfdrive/controls/lib/events.py:698 +msgid "LKAS Fault: Restart the car to engage" +msgstr "" + +#: selfdrive/controls/lib/events.py:706 selfdrive/controls/lib/events.py:712 +#: selfdrive/controls/lib/events.py:795 +msgid "Cruise Fault: Restart the Car" +msgstr "" + +#: selfdrive/controls/lib/events.py:708 selfdrive/controls/lib/events.py:791 +msgid "Cruise Fault: Restart the car to engage" +msgstr "" + +#: selfdrive/controls/lib/events.py:716 +msgid "Gas Fault: Restart the Car" +msgstr "" + +#: selfdrive/controls/lib/events.py:717 +msgid "Gas Error: Restart the Car" +msgstr "" + +#: selfdrive/controls/lib/events.py:722 +msgid "" +"Reverse\n" +"Gear" +msgstr "" + +#: selfdrive/controls/lib/events.py:726 +msgid "Reverse Gear" +msgstr "" + +#: selfdrive/controls/lib/events.py:731 +msgid "Cruise Is Off" +msgstr "" + +#: selfdrive/controls/lib/events.py:735 selfdrive/controls/lib/events.py:736 +msgid "Planner Solution Error" +msgstr "" + +#: selfdrive/controls/lib/events.py:740 selfdrive/controls/lib/events.py:742 +#: selfdrive/controls/lib/events.py:746 +msgid "Harness Malfunction" +msgstr "" + +#: selfdrive/controls/lib/events.py:743 +msgid "Please Check Hardware" +msgstr "" + +#: selfdrive/controls/lib/events.py:751 selfdrive/controls/lib/events.py:760 +msgid "openpilot Canceled" +msgstr "" + +#: selfdrive/controls/lib/events.py:752 +msgid "No close lead car" +msgstr "" + +#: selfdrive/controls/lib/events.py:755 +msgid "No Close Lead Car" +msgstr "" + +#: selfdrive/controls/lib/events.py:761 +msgid "Speed too low" +msgstr "" + +#: selfdrive/controls/lib/events.py:768 selfdrive/controls/lib/events.py:773 +msgid "Speed Too High" +msgstr "" + +#: selfdrive/controls/lib/events.py:769 +msgid "Slow down to resume operation" +msgstr "" + +#: selfdrive/controls/lib/events.py:774 +msgid "Slow down to engage" +msgstr "" + +#: selfdrive/controls/lib/events.py:781 +msgid "Please connect to Internet" +msgstr "" + +#: selfdrive/controls/lib/events.py:782 +msgid "An Update Check Is Required to Engage" +msgstr "" + +#: selfdrive/controls/lib/events.py:785 +msgid "Please Connect to Internet" +msgstr "" + +#: selfdrive/controls/lib/events.py:801 +msgid "Left ALC will start in 3s" +msgstr "" + +#: selfdrive/controls/lib/events.py:809 +msgid "Right ALC will start in 3s" +msgstr "" + +#: selfdrive/controls/lib/events.py:817 +msgid "STEERING REQUIRED: Lane Keeping OFF" +msgstr "" + +#: selfdrive/controls/lib/events.py:825 +msgid "STEERING REQUIRED: Blinkers ON" +msgstr "" + +#: selfdrive/controls/lib/events.py:833 selfdrive/controls/lib/events.py:838 +msgid "Lead Car Is Moving" +msgstr "" + +#: selfdrive/controls/lib/events.py:847 +msgid "WARNING" +msgstr "" + +#: selfdrive/controls/lib/events.py:848 +msgid "Grab wheel to start bypass" +msgstr "" + +#: selfdrive/controls/lib/events.py:855 +msgid "BYPASSING" +msgstr "" + +#: selfdrive/controls/lib/events.py:856 +msgid "HOLD WHEEL" +msgstr "" + +#: selfdrive/controls/lib/events.py:863 +msgid "Bypassed!" +msgstr "" + +#: selfdrive/controls/lib/events.py:864 +msgid "Release wheel when ready" +msgstr "" diff --git a/selfdrive/assets/locales/ja-JP/LC_MESSAGES/events.mo b/selfdrive/assets/locales/ja-JP/LC_MESSAGES/events.mo new file mode 100644 index 000000000..b11f44988 Binary files /dev/null and b/selfdrive/assets/locales/ja-JP/LC_MESSAGES/events.mo differ diff --git a/selfdrive/assets/locales/ja-JP/LC_MESSAGES/events.po b/selfdrive/assets/locales/ja-JP/LC_MESSAGES/events.po new file mode 100644 index 000000000..7d095198c --- /dev/null +++ b/selfdrive/assets/locales/ja-JP/LC_MESSAGES/events.po @@ -0,0 +1,545 @@ +# 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. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-10-15 13:37+1000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: nikkurie <@nikkurie>\n" +"Language-Team: LANGUAGE \n" +"Language: ja-JP\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: selfdrive/controls/lib/events.py:153 +msgid "openpilot Unavailable" +msgstr "オープンパイロットは利用できません" + +#: selfdrive/controls/lib/events.py:160 selfdrive/controls/lib/events.py:167 +msgid "TAKE CONTROL IMMEDIATELY" +msgstr "すぐにハンドルを持って" + +#: selfdrive/controls/lib/events.py:187 selfdrive/controls/lib/events.py:328 +#: selfdrive/controls/lib/events.py:354 selfdrive/controls/lib/events.py:418 +#: selfdrive/controls/lib/events.py:470 selfdrive/controls/lib/events.py:522 +#: selfdrive/controls/lib/events.py:532 +msgid "TAKE CONTROL" +msgstr "ハンドルを持って" + +#: selfdrive/controls/lib/events.py:188 +#, fuzzy, python-format +msgid "Steer Unavailable Below %(speed)d %(unit)s" +msgstr "横の制御が無効になり速度が以下になります" + +#: selfdrive/controls/lib/events.py:196 +#, fuzzy, python-format +msgid "Calibration in Progress: %d%%" +msgstr "キャリブレーション中:" + +#: selfdrive/controls/lib/events.py:197 +#, python-format +msgid "Drive Above %(speed)d %(unit)s" +msgstr "%(speed)d %(unit)s 制限速度以上の運転をしてください" + +#: selfdrive/controls/lib/events.py:204 +msgid "Poor GPS reception" +msgstr "GPS受信不良" + +#: selfdrive/controls/lib/events.py:205 +msgid "If sky is visible, contact support" +msgstr "地下・トンネルでない場合は、カスタマーサービスに連絡ください" + +#: selfdrive/controls/lib/events.py:205 +msgid "Check GPS antenna placement" +msgstr "GPSアンテナの位置を確認してください。" + +#: selfdrive/controls/lib/events.py:210 +msgid "Cruise Mode Disabled" +msgstr "クルーズモードをオフ" + +#: selfdrive/controls/lib/events.py:212 +msgid "Main Switch Off" +msgstr "メインスイッチをオフ" + +#: selfdrive/controls/lib/events.py:222 +msgid "DEBUG ALERT" +msgstr "テストメッセージを削除" + +#: selfdrive/controls/lib/events.py:230 +msgid "Be ready to take over at any time" +msgstr "いつでも引き継げるよう準備しておいてください。" + +#: selfdrive/controls/lib/events.py:231 selfdrive/controls/lib/events.py:239 +#: selfdrive/controls/lib/events.py:247 selfdrive/controls/lib/events.py:255 +msgid "Always keep hands on wheel and eyes on road" +msgstr "常にハンドルに触れ、道路から目を離さない" + +#: selfdrive/controls/lib/events.py:238 +msgid "WARNING: This branch is not tested" +msgstr "警告: このブランチはテストされていません" + +#: selfdrive/controls/lib/events.py:246 +msgid "Dashcam mode" +msgstr "ダッシュカムモード" + +#: selfdrive/controls/lib/events.py:254 +msgid "Dashcam mode for unsupported car" +msgstr "未対応車のためダッシュカムモードのみ" + +#: selfdrive/controls/lib/events.py:262 +msgid "Unsupported Giraffe Configuration" +msgstr "サポートされていないGiraffeの設定" + +#: selfdrive/controls/lib/events.py:263 +msgid "Visit comma.ai/tg" +msgstr "comma.ai/tg を参照" + +#: selfdrive/controls/lib/events.py:270 +msgid "White Panda Is No Longer Supported" +msgstr "ホワイトパンダはサポート終了しました" + +#: selfdrive/controls/lib/events.py:271 +msgid "Upgrade to comma two or black panda" +msgstr "コンマ2やブラックパンダにアップグレード" + +#: selfdrive/controls/lib/events.py:274 +msgid "White panda is no longer supported" +msgstr "ホワイトパンダはサポート終了しました" + +#: selfdrive/controls/lib/events.py:279 +msgid "Stock LKAS is turned on" +msgstr "純正LKASがオン" + +#: selfdrive/controls/lib/events.py:280 +msgid "Turn off stock LKAS to engage" +msgstr "純正LKASをオフにしてエンゲージ" + +#: selfdrive/controls/lib/events.py:288 +msgid "Community Feature Detected" +msgstr "コミュニティ開発の機能を検出" + +#: selfdrive/controls/lib/events.py:289 +msgid "Enable Community Features in Developer Settings" +msgstr "開発者設定でコミュニティ機能を有効にする" + +#: selfdrive/controls/lib/events.py:296 +msgid "Dashcam Mode" +msgstr "ダッシュカムモード" + +#: selfdrive/controls/lib/events.py:297 +msgid "Car Unrecognized" +msgstr "認識できない車" + +#: selfdrive/controls/lib/events.py:304 selfdrive/controls/lib/events.py:312 +#: selfdrive/controls/lib/events.py:320 +msgid "BRAKE!" +msgstr "ブレーキ!" + +#: selfdrive/controls/lib/events.py:305 +msgid "Stock AEB: Risk of Collision" +msgstr "衝突の危険" + +#: selfdrive/controls/lib/events.py:313 +msgid "Stock FCW: Risk of Collision" +msgstr "衝突の危険" + +#: selfdrive/controls/lib/events.py:321 +msgid "Risk of Collision" +msgstr "衝突の危険" + +#: selfdrive/controls/lib/events.py:329 +msgid "Lane Departure Detected" +msgstr "車線逸脱を検知" + +#: selfdrive/controls/lib/events.py:338 +msgid "openpilot will not brake while gas pressed" +msgstr "アクセル中、オープンパイロットはブレーキをかけません" + +#: selfdrive/controls/lib/events.py:346 +msgid "Vehicle Parameter Identification Failed" +msgstr "車両パラメータの識別に失敗しました。" + +#: selfdrive/controls/lib/events.py:355 selfdrive/controls/lib/events.py:523 +#: selfdrive/controls/lib/events.py:526 +msgid "Steering Temporarily Unavailable" +msgstr "ステアリングは一時的に利用不可" + +#: selfdrive/controls/lib/events.py:362 +msgid "KEEP EYES ON ROAD: Driver Distracted" +msgstr "道路から目を離さないで:注意散漫です" + +#: selfdrive/controls/lib/events.py:370 +msgid "KEEP EYES ON ROAD" +msgstr "道路から目を離さないで" + +#: selfdrive/controls/lib/events.py:371 +msgid "Driver Appears Distracted" +msgstr "ドライバーは注意散漫に見えます" + +#: selfdrive/controls/lib/events.py:378 selfdrive/controls/lib/events.py:402 +msgid "DISENGAGE IMMEDIATELY" +msgstr "すぐに解除してください" + +#: selfdrive/controls/lib/events.py:379 +msgid "Driver Was Distracted" +msgstr "ドライバーは注意力散漫" + +#: selfdrive/controls/lib/events.py:386 +msgid "TOUCH STEERING WHEEL: No Face Detected" +msgstr "ハンドルに触れて:顔が検出できない" + +#: selfdrive/controls/lib/events.py:394 +msgid "TOUCH STEERING WHEEL" +msgstr "ハンドルに触れて" + +#: selfdrive/controls/lib/events.py:395 +msgid "Driver Is Unresponsive" +msgstr "ドライバーが無反応" + +#: selfdrive/controls/lib/events.py:403 +msgid "Driver Was Unresponsive" +msgstr "ドライバーが無反応でした" + +#: selfdrive/controls/lib/events.py:410 +msgid "CHECK DRIVER FACE VISIBILITY" +msgstr "ドライバーの顔の視認性を確認" + +#: selfdrive/controls/lib/events.py:411 +msgid "Driver Monitor Model Output Uncertain" +msgstr "ドライバー監視モデルが不完全" + +#: selfdrive/controls/lib/events.py:419 +msgid "Resume Driving Manually" +msgstr "手動で運転を再開" + +#: selfdrive/controls/lib/events.py:426 +msgid "STOPPED" +msgstr "停止" + +#: selfdrive/controls/lib/events.py:427 +msgid "Press Resume to Move" +msgstr "Resumeを押して移動します。" + +#: selfdrive/controls/lib/events.py:438 +msgid "Steer Left to Start Lane Change" +msgstr "左ハンドルで車線変更を開始" + +#: selfdrive/controls/lib/events.py:439 selfdrive/controls/lib/events.py:447 +#: selfdrive/controls/lib/events.py:455 selfdrive/controls/lib/events.py:463 +#: selfdrive/controls/lib/events.py:802 selfdrive/controls/lib/events.py:810 +msgid "Monitor Other Vehicles" +msgstr "他の車両を監視" + +#: selfdrive/controls/lib/events.py:446 +msgid "Steer Right to Start Lane Change" +msgstr "右ハンドルで車線変更を開始" + +#: selfdrive/controls/lib/events.py:454 +msgid "Car Detected in Blindspot" +msgstr "ブラインドスポットで車両を発見" + +#: selfdrive/controls/lib/events.py:462 +msgid "Changing Lane" +msgstr "レーンチェンジ中" + +#: selfdrive/controls/lib/events.py:471 +msgid "Turn Exceeds Steering Limit" +msgstr "ステアリングリミットを超えています" + +#: selfdrive/controls/lib/events.py:496 +msgid "Brake Hold Active" +msgstr "サイドブレーキが作動" + +#: selfdrive/controls/lib/events.py:501 +msgid "Park Brake Engaged" +msgstr "サイドブレーキ作動中" + +#: selfdrive/controls/lib/events.py:506 +msgid "Pedal Pressed During Attempt" +msgstr "ペダル/ブレーキを検出" + +#: selfdrive/controls/lib/events.py:517 +msgid "Enable Adaptive Cruise" +msgstr "ACCを有効化" + +#: selfdrive/controls/lib/events.py:533 +msgid "Attempting Refocus: Camera Focus Invalid" +msgstr "再フォーカス中です" + +#: selfdrive/controls/lib/events.py:539 +msgid "Out of Storage Space" +msgstr "空き容量不足" + +#: selfdrive/controls/lib/events.py:544 +msgid "Speed Too Low" +msgstr "速度が遅すぎます" + +#: selfdrive/controls/lib/events.py:549 selfdrive/controls/lib/events.py:553 +msgid "NEOS Update Required" +msgstr "NEOSの更新が必要" + +#: selfdrive/controls/lib/events.py:550 +msgid "Please Wait for Update" +msgstr "更新をお待ちください" + +#: selfdrive/controls/lib/events.py:558 selfdrive/controls/lib/events.py:562 +msgid "No Data from Device Sensors" +msgstr "デバイスセンサからのデータがありません" + +#: selfdrive/controls/lib/events.py:559 selfdrive/controls/lib/events.py:572 +#: selfdrive/controls/lib/events.py:669 +msgid "Reboot your Device" +msgstr "デバイスを再起動" + +#: selfdrive/controls/lib/events.py:571 selfdrive/controls/lib/events.py:575 +msgid "Speaker not found" +msgstr "スピーカーが見つかりません" + +#: selfdrive/controls/lib/events.py:579 +msgid "Distraction Level Too High" +msgstr "注意力散漫すぎます" + +#: selfdrive/controls/lib/events.py:583 +msgid "System Overheated" +msgstr "オーバーヒート" + +#: selfdrive/controls/lib/events.py:584 +msgid "System overheated" +msgstr "オーバーヒート" + +#: selfdrive/controls/lib/events.py:588 selfdrive/controls/lib/events.py:589 +msgid "Gear not D" +msgstr "Dではない" + +#: selfdrive/controls/lib/events.py:594 +#, fuzzy +msgid "Calibration Invalid" +msgstr "キャリブレーション" + +#: selfdrive/controls/lib/events.py:595 +#, fuzzy +msgid "Reposition Device and Recalibrate" +msgstr "キャリブレーションが無効です。再実行してください。" + +#: selfdrive/controls/lib/events.py:598 selfdrive/controls/lib/events.py:599 +msgid "Calibration Invalid: Reposition Device & Recalibrate" +msgstr "キャリブレーションが無効です。再実行してください。" + +#: selfdrive/controls/lib/events.py:603 selfdrive/controls/lib/events.py:605 +msgid "Calibration in Progress" +msgstr "キャリブレーション" + +#: selfdrive/controls/lib/events.py:609 +msgid "Door Open" +msgstr "ドアが開いています" + +#: selfdrive/controls/lib/events.py:610 +msgid "Door open" +msgstr "ドアが開いています" + +#: selfdrive/controls/lib/events.py:614 +msgid "Seatbelt Unlatched" +msgstr "シートベルト未着用" + +#: selfdrive/controls/lib/events.py:615 +msgid "Seatbelt unlatched" +msgstr "シートベルト未着用" + +#: selfdrive/controls/lib/events.py:619 selfdrive/controls/lib/events.py:620 +msgid "ESP Off" +msgstr "ESPオフ" + +#: selfdrive/controls/lib/events.py:624 selfdrive/controls/lib/events.py:625 +msgid "Low Battery" +msgstr "低バッテリー" + +#: selfdrive/controls/lib/events.py:629 selfdrive/controls/lib/events.py:630 +msgid "Communication Issue between Processes" +msgstr "プロセス間の通信の問題" + +#: selfdrive/controls/lib/events.py:635 selfdrive/controls/lib/events.py:636 +msgid "Radar Communication Issue" +msgstr "レーダー通信問題" + +#: selfdrive/controls/lib/events.py:641 selfdrive/controls/lib/events.py:642 +#: selfdrive/controls/lib/events.py:646 selfdrive/controls/lib/events.py:647 +msgid "Radar Error: Restart the Car" +msgstr "レーダーエラー:車を再起動" + +#: selfdrive/controls/lib/events.py:651 selfdrive/controls/lib/events.py:652 +msgid "Driving model lagging" +msgstr "制御モデルに遅延がある" + +#: selfdrive/controls/lib/events.py:656 selfdrive/controls/lib/events.py:657 +msgid "Vision Model Output Uncertain" +msgstr "映像が不明瞭です" + +#: selfdrive/controls/lib/events.py:661 selfdrive/controls/lib/events.py:662 +msgid "Device Fell Off Mount" +msgstr "" + +#: selfdrive/controls/lib/events.py:666 selfdrive/controls/lib/events.py:672 +msgid "Low Memory: Reboot Your Device" +msgstr "ローメモリ:デバイスを再起動" + +#: selfdrive/controls/lib/events.py:668 +msgid "RAM Critically Low" +msgstr "RAMが致命的に低い" + +#: selfdrive/controls/lib/events.py:677 selfdrive/controls/lib/events.py:678 +msgid "Controls Failed" +msgstr "制御失敗" + +#: selfdrive/controls/lib/events.py:682 +msgid "Controls Mismatch" +msgstr "制御不一致" + +#: selfdrive/controls/lib/events.py:686 selfdrive/controls/lib/events.py:688 +#: selfdrive/controls/lib/events.py:692 +msgid "CAN Error: Check Connections" +msgstr "CANエラー:接続を確認" + +#: selfdrive/controls/lib/events.py:696 selfdrive/controls/lib/events.py:702 +msgid "LKAS Fault: Restart the Car" +msgstr "LKASの故障:車を再起動" + +#: selfdrive/controls/lib/events.py:698 +msgid "LKAS Fault: Restart the car to engage" +msgstr "LKASの故障:車を再起動後発進" + +#: selfdrive/controls/lib/events.py:706 selfdrive/controls/lib/events.py:712 +#: selfdrive/controls/lib/events.py:795 +msgid "Cruise Fault: Restart the Car" +msgstr "クルーズ失敗:車を再起動" + +#: selfdrive/controls/lib/events.py:708 selfdrive/controls/lib/events.py:791 +msgid "Cruise Fault: Restart the car to engage" +msgstr "クルーズ失敗:車を再起動後発進" + +#: selfdrive/controls/lib/events.py:716 +msgid "Gas Fault: Restart the Car" +msgstr "アクセル故障:車を再起動" + +#: selfdrive/controls/lib/events.py:717 +msgid "Gas Error: Restart the Car" +msgstr "アクセルエラー:車を再起動" + +#: selfdrive/controls/lib/events.py:722 +#, fuzzy +msgid "" +"Reverse\n" +"Gear" +msgstr "Rに切り替え" + +#: selfdrive/controls/lib/events.py:726 +msgid "Reverse Gear" +msgstr "Rに切り替え" + +#: selfdrive/controls/lib/events.py:731 +msgid "Cruise Is Off" +msgstr "クルーズコントロールオフ" + +#: selfdrive/controls/lib/events.py:735 selfdrive/controls/lib/events.py:736 +msgid "Planner Solution Error" +msgstr "Planner Solution エラー" + +#: selfdrive/controls/lib/events.py:740 selfdrive/controls/lib/events.py:742 +#: selfdrive/controls/lib/events.py:746 +msgid "Harness Malfunction" +msgstr "ハーネスが故障" + +#: selfdrive/controls/lib/events.py:743 +msgid "Please Check Hardware" +msgstr "ハードウェアを確認して" + +#: selfdrive/controls/lib/events.py:751 selfdrive/controls/lib/events.py:760 +msgid "openpilot Canceled" +msgstr "オープンパイロットはキャンセルされました" + +#: selfdrive/controls/lib/events.py:752 +msgid "No close lead car" +msgstr "リードカー不在" + +#: selfdrive/controls/lib/events.py:755 +msgid "No Close Lead Car" +msgstr "リードカー不在" + +#: selfdrive/controls/lib/events.py:761 +msgid "Speed too low" +msgstr "速度が遅すぎる" + +#: selfdrive/controls/lib/events.py:768 selfdrive/controls/lib/events.py:773 +msgid "Speed Too High" +msgstr "速度が速すぎる" + +#: selfdrive/controls/lib/events.py:769 +msgid "Slow down to resume operation" +msgstr "速度を下げてオープンパイロットを再開" + +#: selfdrive/controls/lib/events.py:774 +msgid "Slow down to engage" +msgstr "速度を落として発進" + +#: selfdrive/controls/lib/events.py:781 +msgid "Please connect to Internet" +msgstr "インターネット接続を確認" + +#: selfdrive/controls/lib/events.py:782 +msgid "An Update Check Is Required to Engage" +msgstr "発進するには更新が必要です" + +#: selfdrive/controls/lib/events.py:785 +msgid "Please Connect to Internet" +msgstr "インターネット接続を確認" + +#: selfdrive/controls/lib/events.py:801 +msgid "Left ALC will start in 3s" +msgstr "左車線に移動します" + +#: selfdrive/controls/lib/events.py:809 +msgid "Right ALC will start in 3s" +msgstr "右車線に移動します" + +#: selfdrive/controls/lib/events.py:817 +msgid "STEERING REQUIRED: Lane Keeping OFF" +msgstr "操作が必要:レーンキープオフ" + +#: selfdrive/controls/lib/events.py:825 +msgid "STEERING REQUIRED: Blinkers ON" +msgstr "操作が必要:ウインカーオン" + +#: selfdrive/controls/lib/events.py:833 selfdrive/controls/lib/events.py:838 +msgid "Lead Car Is Moving" +msgstr "リードカーが移動しました" + +#: selfdrive/controls/lib/events.py:847 +msgid "WARNING" +msgstr "" + +#: selfdrive/controls/lib/events.py:848 +msgid "Grab wheel to start bypass" +msgstr "" + +#: selfdrive/controls/lib/events.py:855 +msgid "BYPASSING" +msgstr "" + +#: selfdrive/controls/lib/events.py:856 +msgid "HOLD WHEEL" +msgstr "" + +#: selfdrive/controls/lib/events.py:863 +msgid "Bypassed!" +msgstr "" + +#: selfdrive/controls/lib/events.py:864 +msgid "Release wheel when ready" +msgstr "" + +#~ msgid "Drive Above" +#~ msgstr "制限速度以上の運転をしてください" diff --git a/selfdrive/assets/locales/ko-KR/LC_MESSAGES/events.mo b/selfdrive/assets/locales/ko-KR/LC_MESSAGES/events.mo new file mode 100644 index 000000000..951599fff Binary files /dev/null and b/selfdrive/assets/locales/ko-KR/LC_MESSAGES/events.mo differ diff --git a/selfdrive/assets/locales/ko-KR/LC_MESSAGES/events.po b/selfdrive/assets/locales/ko-KR/LC_MESSAGES/events.po new file mode 100644 index 000000000..63d8438ec --- /dev/null +++ b/selfdrive/assets/locales/ko-KR/LC_MESSAGES/events.po @@ -0,0 +1,543 @@ +# 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-10-15 13:37+1000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: ko-KR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: selfdrive/controls/lib/events.py:153 +msgid "openpilot Unavailable" +msgstr "오픈파일럿 사용불가" + +#: selfdrive/controls/lib/events.py:160 selfdrive/controls/lib/events.py:167 +msgid "TAKE CONTROL IMMEDIATELY" +msgstr "핸들을 잡아주세요" + +#: selfdrive/controls/lib/events.py:187 selfdrive/controls/lib/events.py:328 +#: selfdrive/controls/lib/events.py:354 selfdrive/controls/lib/events.py:418 +#: selfdrive/controls/lib/events.py:470 selfdrive/controls/lib/events.py:522 +#: selfdrive/controls/lib/events.py:532 +msgid "TAKE CONTROL" +msgstr "핸들을 잡아주세요" + +#: selfdrive/controls/lib/events.py:188 +#, fuzzy, python-format +msgid "Steer Unavailable Below %(speed)d %(unit)s" +msgstr "%d %s 이하에서는 조향제어가 불가합니다" + +#: selfdrive/controls/lib/events.py:196 +#, fuzzy, python-format +msgid "Calibration in Progress: %d%%" +msgstr "캘리브레이션 진행중: %d%%" + +#: selfdrive/controls/lib/events.py:197 +#, fuzzy, python-format +msgid "Drive Above %(speed)d %(unit)s" +msgstr "%(speed)d %(unit)s 이상의 속도로 주행하세요" + +#: selfdrive/controls/lib/events.py:204 +msgid "Poor GPS reception" +msgstr "GPS 신호 약함" + +#: selfdrive/controls/lib/events.py:205 +msgid "If sky is visible, contact support" +msgstr "환경에 문제가 없을경우 서비스팀에 연락하세요" + +#: selfdrive/controls/lib/events.py:205 +msgid "Check GPS antenna placement" +msgstr "GPS안테나 위치를 점검하세요" + +#: selfdrive/controls/lib/events.py:210 +msgid "Cruise Mode Disabled" +msgstr "크루즈 모드 꺼짐" + +#: selfdrive/controls/lib/events.py:212 +msgid "Main Switch Off" +msgstr "" + +#: selfdrive/controls/lib/events.py:222 +msgid "DEBUG ALERT" +msgstr "" + +#: selfdrive/controls/lib/events.py:230 +msgid "Be ready to take over at any time" +msgstr "오픈파일럿 사용준비가 되었습니다" + +#: selfdrive/controls/lib/events.py:231 selfdrive/controls/lib/events.py:239 +#: selfdrive/controls/lib/events.py:247 selfdrive/controls/lib/events.py:255 +msgid "Always keep hands on wheel and eyes on road" +msgstr "안전운전을 위해 항상 핸들을 잡고 도로교통 상황을 주시하세요" + +#: selfdrive/controls/lib/events.py:238 +msgid "WARNING: This branch is not tested" +msgstr "경고: 이 Branch는 테스트되지 않았습니다" + +#: selfdrive/controls/lib/events.py:246 +msgid "Dashcam mode" +msgstr "대시캠 모드" + +#: selfdrive/controls/lib/events.py:254 +msgid "Dashcam mode for unsupported car" +msgstr "안전운전을 위해 항상 핸들을 잡고 도로교통 상황을 주시하세요" + +#: selfdrive/controls/lib/events.py:262 +msgid "Unsupported Giraffe Configuration" +msgstr "지원되지 않는 지라프 설정" + +#: selfdrive/controls/lib/events.py:263 +msgid "Visit comma.ai/tg" +msgstr "comma.ai/tg 방문하세요" + +#: selfdrive/controls/lib/events.py:270 +msgid "White Panda Is No Longer Supported" +msgstr "화이트판다는 더 이상 지원되지 않습니다" + +#: selfdrive/controls/lib/events.py:271 +msgid "Upgrade to comma two or black panda" +msgstr "콤마2나 블랙판다로 업그레이드 하세요" + +#: selfdrive/controls/lib/events.py:274 +msgid "White panda is no longer supported" +msgstr "화이트판다는 더 이상 지원되지 않습니다" + +#: selfdrive/controls/lib/events.py:279 +msgid "Stock LKAS is turned on" +msgstr "차량의 LKAS 기능이 켜져 있습니다" + +#: selfdrive/controls/lib/events.py:280 +msgid "Turn off stock LKAS to engage" +msgstr "오픈파일럿 사용을 위해 LKAS를 끄세요" + +#: selfdrive/controls/lib/events.py:288 +msgid "Community Feature Detected" +msgstr "커뮤니티 기능 감지됨" + +#: selfdrive/controls/lib/events.py:289 +msgid "Enable Community Features in Developer Settings" +msgstr "개발자 설정에서 커뮤니티 기능을 활성화하세요" + +#: selfdrive/controls/lib/events.py:296 +msgid "Dashcam Mode" +msgstr "대시캠 모드" + +#: selfdrive/controls/lib/events.py:297 +msgid "Car Unrecognized" +msgstr "미인식 차량" + +#: selfdrive/controls/lib/events.py:304 selfdrive/controls/lib/events.py:312 +#: selfdrive/controls/lib/events.py:320 +msgid "BRAKE!" +msgstr "브레이크!" + +#: selfdrive/controls/lib/events.py:305 +msgid "Stock AEB: Risk of Collision" +msgstr "순정 AEB: 충돌 위험" + +#: selfdrive/controls/lib/events.py:313 +msgid "Stock FCW: Risk of Collision" +msgstr "순정 FCW: 충돌 위험" + +#: selfdrive/controls/lib/events.py:321 +msgid "Risk of Collision" +msgstr "충돌 위험" + +#: selfdrive/controls/lib/events.py:329 +msgid "Lane Departure Detected" +msgstr "차선이탈이 감지되었습니다" + +#: selfdrive/controls/lib/events.py:338 +msgid "openpilot will not brake while gas pressed" +msgstr "가속중에는 오픈파일럿 브레이크 작동불가" + +#: selfdrive/controls/lib/events.py:346 +msgid "Vehicle Parameter Identification Failed" +msgstr "차량 매개 변수 식별 실패" + +#: selfdrive/controls/lib/events.py:355 selfdrive/controls/lib/events.py:523 +#: selfdrive/controls/lib/events.py:526 +msgid "Steering Temporarily Unavailable" +msgstr "조향제어가 일시적으로 비활성화 되었습니다" + +#: selfdrive/controls/lib/events.py:362 +msgid "KEEP EYES ON ROAD: Driver Distracted" +msgstr "도로상황에 주의를 기울이세요" + +#: selfdrive/controls/lib/events.py:370 +msgid "KEEP EYES ON ROAD" +msgstr "도로상황에 주의하세요" + +#: selfdrive/controls/lib/events.py:371 +msgid "Driver Appears Distracted" +msgstr "전방주시 필요" + +#: selfdrive/controls/lib/events.py:378 selfdrive/controls/lib/events.py:402 +msgid "DISENGAGE IMMEDIATELY" +msgstr "경고: 조향제어가 즉시 해제됩니다" + +#: selfdrive/controls/lib/events.py:379 +msgid "Driver Was Distracted" +msgstr "운전자 전방주시 불안" + +#: selfdrive/controls/lib/events.py:386 +msgid "TOUCH STEERING WHEEL: No Face Detected" +msgstr "핸들을 터치하세요: 모니터링 없음" + +#: selfdrive/controls/lib/events.py:394 +msgid "TOUCH STEERING WHEEL" +msgstr "핸들을 터치하세요" + +#: selfdrive/controls/lib/events.py:395 +msgid "Driver Is Unresponsive" +msgstr "운전자 모니터링 없음" + +#: selfdrive/controls/lib/events.py:403 +msgid "Driver Was Unresponsive" +msgstr "운전자 모니터링 없음" + +#: selfdrive/controls/lib/events.py:410 +msgid "CHECK DRIVER FACE VISIBILITY" +msgstr "운전자 얼굴 확인 중" + +#: selfdrive/controls/lib/events.py:411 +msgid "Driver Monitor Model Output Uncertain" +msgstr "운전자 얼굴 인식이 어렵습니다" + +#: selfdrive/controls/lib/events.py:419 +msgid "Resume Driving Manually" +msgstr "수동으로 재출발 하세요" + +#: selfdrive/controls/lib/events.py:426 +msgid "STOPPED" +msgstr "잠시멈춤" + +#: selfdrive/controls/lib/events.py:427 +msgid "Press Resume to Move" +msgstr "재출발을 위해 RES버튼을 누르세요" + +#: selfdrive/controls/lib/events.py:438 +msgid "Steer Left to Start Lane Change" +msgstr "차선 변경을 위해 핸들을 좌측으로 살짝 돌리세요" + +#: selfdrive/controls/lib/events.py:439 selfdrive/controls/lib/events.py:447 +#: selfdrive/controls/lib/events.py:455 selfdrive/controls/lib/events.py:463 +#: selfdrive/controls/lib/events.py:802 selfdrive/controls/lib/events.py:810 +msgid "Monitor Other Vehicles" +msgstr "다른 차량에 주의하세요" + +#: selfdrive/controls/lib/events.py:446 +msgid "Steer Right to Start Lane Change" +msgstr "차선 변경을 위해 핸들을 우측으로 살짝 돌리세요" + +#: selfdrive/controls/lib/events.py:454 +msgid "Car Detected in Blindspot" +msgstr "측면 차량 접근 중" + +#: selfdrive/controls/lib/events.py:462 +msgid "Changing Lane" +msgstr "차선 변경 중" + +#: selfdrive/controls/lib/events.py:471 +msgid "Turn Exceeds Steering Limit" +msgstr "" + +#: selfdrive/controls/lib/events.py:496 +msgid "Brake Hold Active" +msgstr "브레이크 홀드 중" + +#: selfdrive/controls/lib/events.py:501 +msgid "Park Brake Engaged" +msgstr "파킹브레이크 체결 됨" + +#: selfdrive/controls/lib/events.py:506 +msgid "Pedal Pressed During Attempt" +msgstr "시작 중 페달 밟음" + +#: selfdrive/controls/lib/events.py:517 +msgid "Enable Adaptive Cruise" +msgstr "어댑티브 크루즈를 활성화하세요" + +#: selfdrive/controls/lib/events.py:533 +msgid "Attempting Refocus: Camera Focus Invalid" +msgstr "카메라 포커스 조정중: 카메라 포커스 부정확" + +#: selfdrive/controls/lib/events.py:539 +msgid "Out of Storage Space" +msgstr "저장공간 부족" + +#: selfdrive/controls/lib/events.py:544 +msgid "Speed Too Low" +msgstr "차량의 속도 낮음" + +#: selfdrive/controls/lib/events.py:549 selfdrive/controls/lib/events.py:553 +msgid "NEOS Update Required" +msgstr "NEOS 업데이트 필요" + +#: selfdrive/controls/lib/events.py:550 +msgid "Please Wait for Update" +msgstr "업데이트를 위해 기다리세요" + +#: selfdrive/controls/lib/events.py:558 selfdrive/controls/lib/events.py:562 +msgid "No Data from Device Sensors" +msgstr "EON센서로부터 데이터를 받지 못했습니다" + +#: selfdrive/controls/lib/events.py:559 selfdrive/controls/lib/events.py:572 +#: selfdrive/controls/lib/events.py:669 +msgid "Reboot your Device" +msgstr "장치를 재시작 하세요" + +#: selfdrive/controls/lib/events.py:571 selfdrive/controls/lib/events.py:575 +msgid "Speaker not found" +msgstr "스피커를 찾을 수 없습니다" + +#: selfdrive/controls/lib/events.py:579 +msgid "Distraction Level Too High" +msgstr "운전자 전방주시 매우 불안" + +#: selfdrive/controls/lib/events.py:583 +msgid "System Overheated" +msgstr "시스템이 과열되었습니다" + +#: selfdrive/controls/lib/events.py:584 +msgid "System overheated" +msgstr "시스템이 과열되었습니다" + +#: selfdrive/controls/lib/events.py:588 selfdrive/controls/lib/events.py:589 +msgid "Gear not D" +msgstr "기어가 드라이브모드가 아닙니다" + +#: selfdrive/controls/lib/events.py:594 +#, fuzzy +msgid "Calibration Invalid" +msgstr "캘리브레이션 진행 중" + +#: selfdrive/controls/lib/events.py:595 +#, fuzzy +msgid "Reposition Device and Recalibrate" +msgstr "캘리브레이션 유효하지 않음: 장치 위치 조정 및 재 캘리브레이션" + +#: selfdrive/controls/lib/events.py:598 selfdrive/controls/lib/events.py:599 +msgid "Calibration Invalid: Reposition Device & Recalibrate" +msgstr "캘리브레이션 유효하지 않음: 장치 위치 조정 및 재 캘리브레이션" + +#: selfdrive/controls/lib/events.py:603 selfdrive/controls/lib/events.py:605 +msgid "Calibration in Progress" +msgstr "캘리브레이션 진행 중" + +#: selfdrive/controls/lib/events.py:609 +msgid "Door Open" +msgstr "도어가 열려있습니다" + +#: selfdrive/controls/lib/events.py:610 +msgid "Door open" +msgstr "도어가 열려있습니다" + +#: selfdrive/controls/lib/events.py:614 +msgid "Seatbelt Unlatched" +msgstr "안전벨트를 체결하세요" + +#: selfdrive/controls/lib/events.py:615 +msgid "Seatbelt unlatched" +msgstr "안전벨트를 체결하세요" + +#: selfdrive/controls/lib/events.py:619 selfdrive/controls/lib/events.py:620 +msgid "ESP Off" +msgstr "ESP 꺼짐" + +#: selfdrive/controls/lib/events.py:624 selfdrive/controls/lib/events.py:625 +msgid "Low Battery" +msgstr "배터리 부족" + +#: selfdrive/controls/lib/events.py:629 selfdrive/controls/lib/events.py:630 +msgid "Communication Issue between Processes" +msgstr "프로세스 간 통신 오류가 있습니다" + +#: selfdrive/controls/lib/events.py:635 selfdrive/controls/lib/events.py:636 +msgid "Radar Communication Issue" +msgstr "레이더 오류: 차량을 재시작하세요" + +#: selfdrive/controls/lib/events.py:641 selfdrive/controls/lib/events.py:642 +#: selfdrive/controls/lib/events.py:646 selfdrive/controls/lib/events.py:647 +msgid "Radar Error: Restart the Car" +msgstr "레이더 오류: 차량을 재시작하세요" + +#: selfdrive/controls/lib/events.py:651 selfdrive/controls/lib/events.py:652 +msgid "Driving model lagging" +msgstr "주행 모델 지연" + +#: selfdrive/controls/lib/events.py:656 selfdrive/controls/lib/events.py:657 +msgid "Vision Model Output Uncertain" +msgstr "전방 영상 인식 불안" + +#: selfdrive/controls/lib/events.py:661 selfdrive/controls/lib/events.py:662 +msgid "Device Fell Off Mount" +msgstr "" + +#: selfdrive/controls/lib/events.py:666 selfdrive/controls/lib/events.py:672 +msgid "Low Memory: Reboot Your Device" +msgstr "메모리 부족: 장치를 재시작하세요" + +#: selfdrive/controls/lib/events.py:668 +msgid "RAM Critically Low" +msgstr "메모리 부족 심각" + +#: selfdrive/controls/lib/events.py:677 selfdrive/controls/lib/events.py:678 +msgid "Controls Failed" +msgstr "차량제어 불가" + +#: selfdrive/controls/lib/events.py:682 +msgid "Controls Mismatch" +msgstr "" + +#: selfdrive/controls/lib/events.py:686 selfdrive/controls/lib/events.py:688 +#: selfdrive/controls/lib/events.py:692 +msgid "CAN Error: Check Connections" +msgstr "CAN 오류: CAN 신호를 확인하세요" + +#: selfdrive/controls/lib/events.py:696 selfdrive/controls/lib/events.py:702 +msgid "LKAS Fault: Restart the Car" +msgstr "LKAS 오류: 차량을 재시작하세요" + +#: selfdrive/controls/lib/events.py:698 +msgid "LKAS Fault: Restart the car to engage" +msgstr "LKAS 오류: 시작을 위해 차량을 재시작하세요" + +#: selfdrive/controls/lib/events.py:706 selfdrive/controls/lib/events.py:712 +#: selfdrive/controls/lib/events.py:795 +msgid "Cruise Fault: Restart the Car" +msgstr "크루즈 오류: 차량을 재시작하세요" + +#: selfdrive/controls/lib/events.py:708 selfdrive/controls/lib/events.py:791 +msgid "Cruise Fault: Restart the car to engage" +msgstr "크루즈 오류: 시작을 위해 차량을 재시작하세요" + +#: selfdrive/controls/lib/events.py:716 +msgid "Gas Fault: Restart the Car" +msgstr "가속페달 오류: 차량을 재시작하세요" + +#: selfdrive/controls/lib/events.py:717 +msgid "Gas Error: Restart the Car" +msgstr "가속페달 오류: 차량을 재시작하세요" + +#: selfdrive/controls/lib/events.py:722 +#, fuzzy +msgid "" +"Reverse\n" +"Gear" +msgstr "후진 기어" + +#: selfdrive/controls/lib/events.py:726 +msgid "Reverse Gear" +msgstr "후진 기어" + +#: selfdrive/controls/lib/events.py:731 +msgid "Cruise Is Off" +msgstr "크루즈 꺼짐" + +#: selfdrive/controls/lib/events.py:735 selfdrive/controls/lib/events.py:736 +msgid "Planner Solution Error" +msgstr "" + +#: selfdrive/controls/lib/events.py:740 selfdrive/controls/lib/events.py:742 +#: selfdrive/controls/lib/events.py:746 +msgid "Harness Malfunction" +msgstr "하네스 오작동" + +#: selfdrive/controls/lib/events.py:743 +msgid "Please Check Hardware" +msgstr "장치를 점검하세요" + +#: selfdrive/controls/lib/events.py:751 selfdrive/controls/lib/events.py:760 +msgid "openpilot Canceled" +msgstr "오픈파일럿 시작불가" + +#: selfdrive/controls/lib/events.py:752 +msgid "No close lead car" +msgstr "선행차량이 없습니다" + +#: selfdrive/controls/lib/events.py:755 +msgid "No Close Lead Car" +msgstr "선행차량이 없습니다" + +#: selfdrive/controls/lib/events.py:761 +msgid "Speed too low" +msgstr "선행차량이 없습니다" + +#: selfdrive/controls/lib/events.py:768 selfdrive/controls/lib/events.py:773 +msgid "Speed Too High" +msgstr "속도가 너무 높습니다" + +#: selfdrive/controls/lib/events.py:769 +msgid "Slow down to resume operation" +msgstr "재 작동을 위해 차량의 속도를 낮추세요" + +#: selfdrive/controls/lib/events.py:774 +msgid "Slow down to engage" +msgstr "시작을 위해 차량의 속도를 낮추세요" + +#: selfdrive/controls/lib/events.py:781 +msgid "Please connect to Internet" +msgstr "인터넷에 연결하세요" + +#: selfdrive/controls/lib/events.py:782 +msgid "An Update Check Is Required to Engage" +msgstr "시작을 위해 업데이트를 확인해야 합니다" + +#: selfdrive/controls/lib/events.py:785 +msgid "Please Connect to Internet" +msgstr "인터넷에 연결하세요" + +#: selfdrive/controls/lib/events.py:801 +msgid "Left ALC will start in 3s" +msgstr "" + +#: selfdrive/controls/lib/events.py:809 +msgid "Right ALC will start in 3s" +msgstr "" + +#: selfdrive/controls/lib/events.py:817 +msgid "STEERING REQUIRED: Lane Keeping OFF" +msgstr "" + +#: selfdrive/controls/lib/events.py:825 +msgid "STEERING REQUIRED: Blinkers ON" +msgstr "" + +#: selfdrive/controls/lib/events.py:833 selfdrive/controls/lib/events.py:838 +msgid "Lead Car Is Moving" +msgstr "" + +#: selfdrive/controls/lib/events.py:847 +msgid "WARNING" +msgstr "" + +#: selfdrive/controls/lib/events.py:848 +msgid "Grab wheel to start bypass" +msgstr "" + +#: selfdrive/controls/lib/events.py:855 +msgid "BYPASSING" +msgstr "" + +#: selfdrive/controls/lib/events.py:856 +msgid "HOLD WHEEL" +msgstr "" + +#: selfdrive/controls/lib/events.py:863 +msgid "Bypassed!" +msgstr "" + +#: selfdrive/controls/lib/events.py:864 +msgid "Release wheel when ready" +msgstr "" diff --git a/selfdrive/assets/locales/zh-CN/LC_MESSAGES/events.mo b/selfdrive/assets/locales/zh-CN/LC_MESSAGES/events.mo new file mode 100644 index 000000000..f808fbc67 Binary files /dev/null and b/selfdrive/assets/locales/zh-CN/LC_MESSAGES/events.mo differ diff --git a/selfdrive/assets/locales/zh-CN/LC_MESSAGES/events.po b/selfdrive/assets/locales/zh-CN/LC_MESSAGES/events.po new file mode 100644 index 000000000..364d30294 --- /dev/null +++ b/selfdrive/assets/locales/zh-CN/LC_MESSAGES/events.po @@ -0,0 +1,542 @@ +# 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. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-10-15 13:37+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" + +#: selfdrive/controls/lib/events.py:153 +msgid "openpilot Unavailable" +msgstr "无法使用 openpilot" + +#: selfdrive/controls/lib/events.py:160 selfdrive/controls/lib/events.py:167 +msgid "TAKE CONTROL IMMEDIATELY" +msgstr "即刻接管控制" + +#: selfdrive/controls/lib/events.py:187 selfdrive/controls/lib/events.py:328 +#: selfdrive/controls/lib/events.py:354 selfdrive/controls/lib/events.py:418 +#: selfdrive/controls/lib/events.py:470 selfdrive/controls/lib/events.py:522 +#: selfdrive/controls/lib/events.py:532 +msgid "TAKE CONTROL" +msgstr "接管控制" + +#: selfdrive/controls/lib/events.py:188 +#, fuzzy, python-format +msgid "Steer Unavailable Below %(speed)d %(unit)s" +msgstr "横向控制暂时失效,车速低于 %d %s" + +#: selfdrive/controls/lib/events.py:196 +#, fuzzy, python-format +msgid "Calibration in Progress: %d%%" +msgstr "正在校准中:%d%%" + +#: selfdrive/controls/lib/events.py:197 +#, fuzzy, python-format +msgid "Drive Above %(speed)d %(unit)s" +msgstr "车速请高于 %(speed)d %(unit)s" + +#: selfdrive/controls/lib/events.py:204 +msgid "Poor GPS reception" +msgstr "GPS 讯号不良" + +#: selfdrive/controls/lib/events.py:205 +msgid "If sky is visible, contact support" +msgstr "如果您不在地下室/隧道,请联系客服" + +#: selfdrive/controls/lib/events.py:205 +msgid "Check GPS antenna placement" +msgstr "请检查 GPS 天线位置" + +#: selfdrive/controls/lib/events.py:210 +msgid "Cruise Mode Disabled" +msgstr "巡航模式关闭" + +#: selfdrive/controls/lib/events.py:212 +msgid "Main Switch Off" +msgstr "主开关已关闭" + +#: selfdrive/controls/lib/events.py:222 +msgid "DEBUG ALERT" +msgstr "除错用警示讯息" + +#: selfdrive/controls/lib/events.py:230 +msgid "Be ready to take over at any time" +msgstr "请准备好随时接管" + +#: selfdrive/controls/lib/events.py:231 selfdrive/controls/lib/events.py:239 +#: selfdrive/controls/lib/events.py:247 selfdrive/controls/lib/events.py:255 +msgid "Always keep hands on wheel and eyes on road" +msgstr "将手放在方向盘上并持续监视路况" + +#: selfdrive/controls/lib/events.py:238 +msgid "WARNING: This branch is not tested" +msgstr "注意:这个分支未经过测试" + +#: selfdrive/controls/lib/events.py:246 +msgid "Dashcam mode" +msgstr "行车记录模式" + +#: selfdrive/controls/lib/events.py:254 +msgid "Dashcam mode for unsupported car" +msgstr "行车记录模式 (尚未支援车种)" + +#: selfdrive/controls/lib/events.py:262 +msgid "Unsupported Giraffe Configuration" +msgstr "未支援的 Giraffe 设置" + +#: selfdrive/controls/lib/events.py:263 +msgid "Visit comma.ai/tg" +msgstr "请查阅 comma.ai/tg" + +#: selfdrive/controls/lib/events.py:270 +msgid "White Panda Is No Longer Supported" +msgstr "不再支持 White Panda" + +#: selfdrive/controls/lib/events.py:271 +msgid "Upgrade to comma two or black panda" +msgstr "请升级至 comma two 或是使用 black panda" + +#: selfdrive/controls/lib/events.py:274 +msgid "White panda is no longer supported" +msgstr "不再支持 White panda" + +#: selfdrive/controls/lib/events.py:279 +msgid "Stock LKAS is turned on" +msgstr "原厂 LKAS 已开启" + +#: selfdrive/controls/lib/events.py:280 +msgid "Turn off stock LKAS to engage" +msgstr "需关闭原厂 LKAS 才能启用" + +#: selfdrive/controls/lib/events.py:288 +msgid "Community Feature Detected" +msgstr "检测到社群开发功能" + +#: selfdrive/controls/lib/events.py:289 +msgid "Enable Community Features in Developer Settings" +msgstr "请至开发人员设定裡启用社群开发功能" + +#: selfdrive/controls/lib/events.py:296 +msgid "Dashcam Mode" +msgstr "行车记录模式" + +#: selfdrive/controls/lib/events.py:297 +msgid "Car Unrecognized" +msgstr "无法辨识车款" + +#: selfdrive/controls/lib/events.py:304 selfdrive/controls/lib/events.py:312 +#: selfdrive/controls/lib/events.py:320 +msgid "BRAKE!" +msgstr "刹车!" + +#: selfdrive/controls/lib/events.py:305 +msgid "Stock AEB: Risk of Collision" +msgstr "有碰撞的风险" + +#: selfdrive/controls/lib/events.py:313 +msgid "Stock FCW: Risk of Collision" +msgstr "有碰撞的风险" + +#: selfdrive/controls/lib/events.py:321 +msgid "Risk of Collision" +msgstr "有碰撞的风险" + +#: selfdrive/controls/lib/events.py:329 +msgid "Lane Departure Detected" +msgstr "偏离车道" + +#: selfdrive/controls/lib/events.py:338 +msgid "openpilot will not brake while gas pressed" +msgstr "在您踩着油门的时候 openpilot 将不会刹车" + +#: selfdrive/controls/lib/events.py:346 +msgid "Vehicle Parameter Identification Failed" +msgstr "车子参数识别失败" + +#: selfdrive/controls/lib/events.py:355 selfdrive/controls/lib/events.py:523 +#: selfdrive/controls/lib/events.py:526 +msgid "Steering Temporarily Unavailable" +msgstr "横向控制暂时失效" + +#: selfdrive/controls/lib/events.py:362 +msgid "KEEP EYES ON ROAD: Driver Distracted" +msgstr "注意路况:驾驶分心" + +#: selfdrive/controls/lib/events.py:370 +msgid "KEEP EYES ON ROAD" +msgstr "注意路况" + +#: selfdrive/controls/lib/events.py:371 +msgid "Driver Appears Distracted" +msgstr "驾驶分心" + +#: selfdrive/controls/lib/events.py:378 selfdrive/controls/lib/events.py:402 +msgid "DISENGAGE IMMEDIATELY" +msgstr "立即解除" + +#: selfdrive/controls/lib/events.py:379 +msgid "Driver Was Distracted" +msgstr "驾驶分心" + +#: selfdrive/controls/lib/events.py:386 +msgid "TOUCH STEERING WHEEL: No Face Detected" +msgstr "请触碰方向盘:未侦测到驾驶面容" + +#: selfdrive/controls/lib/events.py:394 +msgid "TOUCH STEERING WHEEL" +msgstr "请触碰方向盘" + +#: selfdrive/controls/lib/events.py:395 +msgid "Driver Is Unresponsive" +msgstr "驾驶没有反应" + +#: selfdrive/controls/lib/events.py:403 +msgid "Driver Was Unresponsive" +msgstr "驾驶没有反应" + +#: selfdrive/controls/lib/events.py:410 +msgid "CHECK DRIVER FACE VISIBILITY" +msgstr "请检查驾驶面部的可见度" + +#: selfdrive/controls/lib/events.py:411 +msgid "Driver Monitor Model Output Uncertain" +msgstr "驾驶监控模型判断不明确" + +#: selfdrive/controls/lib/events.py:419 +msgid "Resume Driving Manually" +msgstr "请自行恢復驾驶" + +#: selfdrive/controls/lib/events.py:426 +msgid "STOPPED" +msgstr "已停止" + +#: selfdrive/controls/lib/events.py:427 +msgid "Press Resume to Move" +msgstr "请按 RES 继续" + +#: selfdrive/controls/lib/events.py:438 +msgid "Steer Left to Start Lane Change" +msgstr "请往左打方向盘切换至左车道" + +#: selfdrive/controls/lib/events.py:439 selfdrive/controls/lib/events.py:447 +#: selfdrive/controls/lib/events.py:455 selfdrive/controls/lib/events.py:463 +#: selfdrive/controls/lib/events.py:802 selfdrive/controls/lib/events.py:810 +msgid "Monitor Other Vehicles" +msgstr "请注意其它车辆" + +#: selfdrive/controls/lib/events.py:446 +msgid "Steer Right to Start Lane Change" +msgstr "请往右打方向盘切换至右车道" + +#: selfdrive/controls/lib/events.py:454 +msgid "Car Detected in Blindspot" +msgstr "盲点侦测到车辆" + +#: selfdrive/controls/lib/events.py:462 +msgid "Changing Lane" +msgstr "切换车道中" + +#: selfdrive/controls/lib/events.py:471 +msgid "Turn Exceeds Steering Limit" +msgstr "弯道超过横向操控限制" + +#: selfdrive/controls/lib/events.py:496 +msgid "Brake Hold Active" +msgstr "驻车煞车已启用" + +#: selfdrive/controls/lib/events.py:501 +msgid "Park Brake Engaged" +msgstr "电子驻车已启动" + +#: selfdrive/controls/lib/events.py:506 +msgid "Pedal Pressed During Attempt" +msgstr "启用时侦测到驾驶踩踏油门/刹车" + +#: selfdrive/controls/lib/events.py:517 +msgid "Enable Adaptive Cruise" +msgstr "启用自适应巡航" + +#: selfdrive/controls/lib/events.py:533 +msgid "Attempting Refocus: Camera Focus Invalid" +msgstr "尝试对焦:相机已失焦" + +#: selfdrive/controls/lib/events.py:539 +msgid "Out of Storage Space" +msgstr "存储空间不足" + +#: selfdrive/controls/lib/events.py:544 +msgid "Speed Too Low" +msgstr "车速过慢" + +#: selfdrive/controls/lib/events.py:549 selfdrive/controls/lib/events.py:553 +msgid "NEOS Update Required" +msgstr "NEOS 需要更新" + +#: selfdrive/controls/lib/events.py:550 +msgid "Please Wait for Update" +msgstr "更新中请稍候" + +#: selfdrive/controls/lib/events.py:558 selfdrive/controls/lib/events.py:562 +msgid "No Data from Device Sensors" +msgstr "未收到装置传感器数据" + +#: selfdrive/controls/lib/events.py:559 selfdrive/controls/lib/events.py:572 +#: selfdrive/controls/lib/events.py:669 +msgid "Reboot your Device" +msgstr "请重启装置" + +#: selfdrive/controls/lib/events.py:571 selfdrive/controls/lib/events.py:575 +msgid "Speaker not found" +msgstr "找不到音效装置" + +#: selfdrive/controls/lib/events.py:579 +msgid "Distraction Level Too High" +msgstr "驾驶分心太多次" + +#: selfdrive/controls/lib/events.py:583 +msgid "System Overheated" +msgstr "系统过热" + +#: selfdrive/controls/lib/events.py:584 +msgid "System overheated" +msgstr "系统过热" + +#: selfdrive/controls/lib/events.py:588 selfdrive/controls/lib/events.py:589 +msgid "Gear not D" +msgstr "不在 D 档位" + +#: selfdrive/controls/lib/events.py:594 +#, fuzzy +msgid "Calibration Invalid" +msgstr "正在校准中" + +#: selfdrive/controls/lib/events.py:595 +#, fuzzy +msgid "Reposition Device and Recalibrate" +msgstr "校准无效:请将装置放于新的位置并重新校准" + +#: selfdrive/controls/lib/events.py:598 selfdrive/controls/lib/events.py:599 +msgid "Calibration Invalid: Reposition Device & Recalibrate" +msgstr "校准无效:请将装置放于新的位置并重新校准" + +#: selfdrive/controls/lib/events.py:603 selfdrive/controls/lib/events.py:605 +msgid "Calibration in Progress" +msgstr "正在校准中" + +#: selfdrive/controls/lib/events.py:609 +msgid "Door Open" +msgstr "车门开启" + +#: selfdrive/controls/lib/events.py:610 +msgid "Door open" +msgstr "车门未关" + +#: selfdrive/controls/lib/events.py:614 +msgid "Seatbelt Unlatched" +msgstr "安全带未繫" + +#: selfdrive/controls/lib/events.py:615 +msgid "Seatbelt unlatched" +msgstr "安全带未繫" + +#: selfdrive/controls/lib/events.py:619 selfdrive/controls/lib/events.py:620 +msgid "ESP Off" +msgstr "ESP 关闭" + +#: selfdrive/controls/lib/events.py:624 selfdrive/controls/lib/events.py:625 +msgid "Low Battery" +msgstr "电量过低" + +#: selfdrive/controls/lib/events.py:629 selfdrive/controls/lib/events.py:630 +msgid "Communication Issue between Processes" +msgstr "行程间出现通讯问题" + +#: selfdrive/controls/lib/events.py:635 selfdrive/controls/lib/events.py:636 +msgid "Radar Communication Issue" +msgstr "雷达通讯出现问题" + +#: selfdrive/controls/lib/events.py:641 selfdrive/controls/lib/events.py:642 +#: selfdrive/controls/lib/events.py:646 selfdrive/controls/lib/events.py:647 +msgid "Radar Error: Restart the Car" +msgstr "雷达讯号错误:请重新发动车辆" + +#: selfdrive/controls/lib/events.py:651 selfdrive/controls/lib/events.py:652 +msgid "Driving model lagging" +msgstr "操控模型有延迟" + +#: selfdrive/controls/lib/events.py:656 selfdrive/controls/lib/events.py:657 +msgid "Vision Model Output Uncertain" +msgstr "视觉模型判断不明确" + +#: selfdrive/controls/lib/events.py:661 selfdrive/controls/lib/events.py:662 +msgid "Device Fell Off Mount" +msgstr "装置掉落侦测" + +#: selfdrive/controls/lib/events.py:666 selfdrive/controls/lib/events.py:672 +msgid "Low Memory: Reboot Your Device" +msgstr "记忆体不足:请重启您的装置" + +#: selfdrive/controls/lib/events.py:668 +msgid "RAM Critically Low" +msgstr "记忆体严重不足" + +#: selfdrive/controls/lib/events.py:677 selfdrive/controls/lib/events.py:678 +msgid "Controls Failed" +msgstr "控制发生错误" + +#: selfdrive/controls/lib/events.py:682 +msgid "Controls Mismatch" +msgstr "控制不匹配" + +#: selfdrive/controls/lib/events.py:686 selfdrive/controls/lib/events.py:688 +#: selfdrive/controls/lib/events.py:692 +msgid "CAN Error: Check Connections" +msgstr "CAN 讯号错误:请检查线路" + +#: selfdrive/controls/lib/events.py:696 selfdrive/controls/lib/events.py:702 +msgid "LKAS Fault: Restart the Car" +msgstr "LKAS 错误:请重新发动车辆" + +#: selfdrive/controls/lib/events.py:698 +msgid "LKAS Fault: Restart the car to engage" +msgstr "LKAS 错误:请重新发动车辆" + +#: selfdrive/controls/lib/events.py:706 selfdrive/controls/lib/events.py:712 +#: selfdrive/controls/lib/events.py:795 +msgid "Cruise Fault: Restart the Car" +msgstr "巡航系统错误:请重新发动车辆" + +#: selfdrive/controls/lib/events.py:708 selfdrive/controls/lib/events.py:791 +msgid "Cruise Fault: Restart the car to engage" +msgstr "巡航系统错误:请重新发动车辆" + +#: selfdrive/controls/lib/events.py:716 +msgid "Gas Fault: Restart the Car" +msgstr "油门错误:请重新发动车辆" + +#: selfdrive/controls/lib/events.py:717 +msgid "Gas Error: Restart the Car" +msgstr "油门错误:请重新发动车辆" + +#: selfdrive/controls/lib/events.py:722 +#, fuzzy +msgid "" +"Reverse\n" +"Gear" +msgstr "切换至倒车档" + +#: selfdrive/controls/lib/events.py:726 +msgid "Reverse Gear" +msgstr "切换至倒车档" + +#: selfdrive/controls/lib/events.py:731 +msgid "Cruise Is Off" +msgstr "巡航系统关闭" + +#: selfdrive/controls/lib/events.py:735 selfdrive/controls/lib/events.py:736 +msgid "Planner Solution Error" +msgstr "Planner Solution 错误" + +#: selfdrive/controls/lib/events.py:740 selfdrive/controls/lib/events.py:742 +#: selfdrive/controls/lib/events.py:746 +msgid "Harness Malfunction" +msgstr "Harness 故障" + +#: selfdrive/controls/lib/events.py:743 +msgid "Please Check Hardware" +msgstr "请检查硬体" + +#: selfdrive/controls/lib/events.py:751 selfdrive/controls/lib/events.py:760 +msgid "openpilot Canceled" +msgstr "openpilot 已取消" + +#: selfdrive/controls/lib/events.py:752 +msgid "No close lead car" +msgstr "前方没有车辆" + +#: selfdrive/controls/lib/events.py:755 +msgid "No Close Lead Car" +msgstr "前方没有车辆" + +#: selfdrive/controls/lib/events.py:761 +msgid "Speed too low" +msgstr "车速过慢" + +#: selfdrive/controls/lib/events.py:768 selfdrive/controls/lib/events.py:773 +msgid "Speed Too High" +msgstr "车速过快" + +#: selfdrive/controls/lib/events.py:769 +msgid "Slow down to resume operation" +msgstr "请减速后再启用" + +#: selfdrive/controls/lib/events.py:774 +msgid "Slow down to engage" +msgstr "请减速后再启用" + +#: selfdrive/controls/lib/events.py:781 +msgid "Please connect to Internet" +msgstr "请连接网路" + +#: selfdrive/controls/lib/events.py:782 +msgid "An Update Check Is Required to Engage" +msgstr "需检查更新后才能启用" + +#: selfdrive/controls/lib/events.py:785 +msgid "Please Connect to Internet" +msgstr "请连接网路" + +#: selfdrive/controls/lib/events.py:801 +msgid "Left ALC will start in 3s" +msgstr "准备自动切至左车道" + +#: selfdrive/controls/lib/events.py:809 +msgid "Right ALC will start in 3s" +msgstr "准备自动切至右车道" + +#: selfdrive/controls/lib/events.py:817 +msgid "STEERING REQUIRED: Lane Keeping OFF" +msgstr "请接管方向盘:车道维持关闭" + +#: selfdrive/controls/lib/events.py:825 +msgid "STEERING REQUIRED: Blinkers ON" +msgstr "请接管方向盘:方向灯开启" + +#: selfdrive/controls/lib/events.py:833 selfdrive/controls/lib/events.py:838 +msgid "Lead Car Is Moving" +msgstr "前方车辆车移动中" + +#: selfdrive/controls/lib/events.py:847 +msgid "WARNING" +msgstr "警告" + +#: selfdrive/controls/lib/events.py:848 +msgid "Grab wheel to start bypass" +msgstr "请握好方向盘以绕过时间限制" + +#: selfdrive/controls/lib/events.py:855 +msgid "BYPASSING" +msgstr "绕过时间限制中" + +#: selfdrive/controls/lib/events.py:856 +msgid "HOLD WHEEL" +msgstr "握好方向盘" + +#: selfdrive/controls/lib/events.py:863 +msgid "Bypassed!" +msgstr "时间限制已绕过" + +#: selfdrive/controls/lib/events.py:864 +msgid "Release wheel when ready" +msgstr "准备好后请松开放向盘" diff --git a/selfdrive/assets/locales/zh-TW/LC_MESSAGES/events.mo b/selfdrive/assets/locales/zh-TW/LC_MESSAGES/events.mo new file mode 100644 index 000000000..f1eb3638b Binary files /dev/null and b/selfdrive/assets/locales/zh-TW/LC_MESSAGES/events.mo differ diff --git a/selfdrive/assets/locales/zh-TW/LC_MESSAGES/events.po b/selfdrive/assets/locales/zh-TW/LC_MESSAGES/events.po new file mode 100644 index 000000000..e06a22ffd --- /dev/null +++ b/selfdrive/assets/locales/zh-TW/LC_MESSAGES/events.po @@ -0,0 +1,542 @@ +# 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. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-10-15 13:37+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" + +#: selfdrive/controls/lib/events.py:153 +msgid "openpilot Unavailable" +msgstr "無法使用 openpilot" + +#: selfdrive/controls/lib/events.py:160 selfdrive/controls/lib/events.py:167 +msgid "TAKE CONTROL IMMEDIATELY" +msgstr "即刻接管控制" + +#: selfdrive/controls/lib/events.py:187 selfdrive/controls/lib/events.py:328 +#: selfdrive/controls/lib/events.py:354 selfdrive/controls/lib/events.py:418 +#: selfdrive/controls/lib/events.py:470 selfdrive/controls/lib/events.py:522 +#: selfdrive/controls/lib/events.py:532 +msgid "TAKE CONTROL" +msgstr "接管控制" + +#: selfdrive/controls/lib/events.py:188 +#, fuzzy, python-format +msgid "Steer Unavailable Below %(speed)d %(unit)s" +msgstr "橫向控制暫時失效,車速低於 %d %s" + +#: selfdrive/controls/lib/events.py:196 +#, fuzzy, python-format +msgid "Calibration in Progress: %d%%" +msgstr "正在校準中:%d%%" + +#: selfdrive/controls/lib/events.py:197 +#, fuzzy, python-format +msgid "Drive Above %(speed)d %(unit)s" +msgstr "車速請高於 %(speed)d %(unit)s" + +#: selfdrive/controls/lib/events.py:204 +msgid "Poor GPS reception" +msgstr "GPS 訊號不良" + +#: selfdrive/controls/lib/events.py:205 +msgid "If sky is visible, contact support" +msgstr "如果您不在地下室/隧道,請聯系客服" + +#: selfdrive/controls/lib/events.py:205 +msgid "Check GPS antenna placement" +msgstr "請檢查 GPS 天線位置" + +#: selfdrive/controls/lib/events.py:210 +msgid "Cruise Mode Disabled" +msgstr "巡航模式關閉" + +#: selfdrive/controls/lib/events.py:212 +msgid "Main Switch Off" +msgstr "主開關已關閉" + +#: selfdrive/controls/lib/events.py:222 +msgid "DEBUG ALERT" +msgstr "除錯用警示訊息" + +#: selfdrive/controls/lib/events.py:230 +msgid "Be ready to take over at any time" +msgstr "請準備好隨時接管" + +#: selfdrive/controls/lib/events.py:231 selfdrive/controls/lib/events.py:239 +#: selfdrive/controls/lib/events.py:247 selfdrive/controls/lib/events.py:255 +msgid "Always keep hands on wheel and eyes on road" +msgstr "將手放在方向盤上並持續監視路況" + +#: selfdrive/controls/lib/events.py:238 +msgid "WARNING: This branch is not tested" +msgstr "注意:這個分支未經過測試" + +#: selfdrive/controls/lib/events.py:246 +msgid "Dashcam mode" +msgstr "行車記錄模式" + +#: selfdrive/controls/lib/events.py:254 +msgid "Dashcam mode for unsupported car" +msgstr "行車記錄模式 (尚未支援車種)" + +#: selfdrive/controls/lib/events.py:262 +msgid "Unsupported Giraffe Configuration" +msgstr "未支援的 Giraffe 設置" + +#: selfdrive/controls/lib/events.py:263 +msgid "Visit comma.ai/tg" +msgstr "請查閱 comma.ai/tg" + +#: selfdrive/controls/lib/events.py:270 +msgid "White Panda Is No Longer Supported" +msgstr "不再支援 White Panda" + +#: selfdrive/controls/lib/events.py:271 +msgid "Upgrade to comma two or black panda" +msgstr "請升級至 comma two 或是使用 black panda" + +#: selfdrive/controls/lib/events.py:274 +msgid "White panda is no longer supported" +msgstr "不再支援 White panda" + +#: selfdrive/controls/lib/events.py:279 +msgid "Stock LKAS is turned on" +msgstr "原廠 LKAS 已開啟" + +#: selfdrive/controls/lib/events.py:280 +msgid "Turn off stock LKAS to engage" +msgstr "需關閉原廠 LKAS 才能啟用" + +#: selfdrive/controls/lib/events.py:288 +msgid "Community Feature Detected" +msgstr "檢測到社群開發功能" + +#: selfdrive/controls/lib/events.py:289 +msgid "Enable Community Features in Developer Settings" +msgstr "請至開發人員設定裡啟用社群開發功能" + +#: selfdrive/controls/lib/events.py:296 +msgid "Dashcam Mode" +msgstr "行車記錄模式" + +#: selfdrive/controls/lib/events.py:297 +msgid "Car Unrecognized" +msgstr "無法辨識車款" + +#: selfdrive/controls/lib/events.py:304 selfdrive/controls/lib/events.py:312 +#: selfdrive/controls/lib/events.py:320 +msgid "BRAKE!" +msgstr "剎車!" + +#: selfdrive/controls/lib/events.py:305 +msgid "Stock AEB: Risk of Collision" +msgstr "有碰撞的風險" + +#: selfdrive/controls/lib/events.py:313 +msgid "Stock FCW: Risk of Collision" +msgstr "有碰撞的風險" + +#: selfdrive/controls/lib/events.py:321 +msgid "Risk of Collision" +msgstr "有碰撞的風險" + +#: selfdrive/controls/lib/events.py:329 +msgid "Lane Departure Detected" +msgstr "偏離車道" + +#: selfdrive/controls/lib/events.py:338 +msgid "openpilot will not brake while gas pressed" +msgstr "在您踩著油門的時候 openpilot 將不會剎車" + +#: selfdrive/controls/lib/events.py:346 +msgid "Vehicle Parameter Identification Failed" +msgstr "車子參數識別失敗" + +#: selfdrive/controls/lib/events.py:355 selfdrive/controls/lib/events.py:523 +#: selfdrive/controls/lib/events.py:526 +msgid "Steering Temporarily Unavailable" +msgstr "橫向控制暫時失效" + +#: selfdrive/controls/lib/events.py:362 +msgid "KEEP EYES ON ROAD: Driver Distracted" +msgstr "注意路況:駕駛分心" + +#: selfdrive/controls/lib/events.py:370 +msgid "KEEP EYES ON ROAD" +msgstr "注意路況" + +#: selfdrive/controls/lib/events.py:371 +msgid "Driver Appears Distracted" +msgstr "駕駛分心" + +#: selfdrive/controls/lib/events.py:378 selfdrive/controls/lib/events.py:402 +msgid "DISENGAGE IMMEDIATELY" +msgstr "立即解除" + +#: selfdrive/controls/lib/events.py:379 +msgid "Driver Was Distracted" +msgstr "駕駛分心" + +#: selfdrive/controls/lib/events.py:386 +msgid "TOUCH STEERING WHEEL: No Face Detected" +msgstr "請觸碰方向盤:未偵測到駕駛面容" + +#: selfdrive/controls/lib/events.py:394 +msgid "TOUCH STEERING WHEEL" +msgstr "請觸碰方向盤" + +#: selfdrive/controls/lib/events.py:395 +msgid "Driver Is Unresponsive" +msgstr "駕駛沒有反應" + +#: selfdrive/controls/lib/events.py:403 +msgid "Driver Was Unresponsive" +msgstr "駕駛沒有反應" + +#: selfdrive/controls/lib/events.py:410 +msgid "CHECK DRIVER FACE VISIBILITY" +msgstr "請檢查駕駛面部的可見度" + +#: selfdrive/controls/lib/events.py:411 +msgid "Driver Monitor Model Output Uncertain" +msgstr "駕駛監控模型判斷不明確" + +#: selfdrive/controls/lib/events.py:419 +msgid "Resume Driving Manually" +msgstr "請自行恢復駕駛" + +#: selfdrive/controls/lib/events.py:426 +msgid "STOPPED" +msgstr "已停止" + +#: selfdrive/controls/lib/events.py:427 +msgid "Press Resume to Move" +msgstr "請按 RES 繼續" + +#: selfdrive/controls/lib/events.py:438 +msgid "Steer Left to Start Lane Change" +msgstr "請往左打方向盤切換至左車道" + +#: selfdrive/controls/lib/events.py:439 selfdrive/controls/lib/events.py:447 +#: selfdrive/controls/lib/events.py:455 selfdrive/controls/lib/events.py:463 +#: selfdrive/controls/lib/events.py:802 selfdrive/controls/lib/events.py:810 +msgid "Monitor Other Vehicles" +msgstr "請注意其它車輛" + +#: selfdrive/controls/lib/events.py:446 +msgid "Steer Right to Start Lane Change" +msgstr "請往右打方向盤切換至右車道" + +#: selfdrive/controls/lib/events.py:454 +msgid "Car Detected in Blindspot" +msgstr "盲點偵測到車輛" + +#: selfdrive/controls/lib/events.py:462 +msgid "Changing Lane" +msgstr "切換車道中" + +#: selfdrive/controls/lib/events.py:471 +msgid "Turn Exceeds Steering Limit" +msgstr "彎道超過橫向操控限制" + +#: selfdrive/controls/lib/events.py:496 +msgid "Brake Hold Active" +msgstr "駐車煞車已啟用" + +#: selfdrive/controls/lib/events.py:501 +msgid "Park Brake Engaged" +msgstr "電子駐車已啟動" + +#: selfdrive/controls/lib/events.py:506 +msgid "Pedal Pressed During Attempt" +msgstr "啟用時偵測到駕駛踩踏油門/剎車" + +#: selfdrive/controls/lib/events.py:517 +msgid "Enable Adaptive Cruise" +msgstr "啟用主動定速巡航" + +#: selfdrive/controls/lib/events.py:533 +msgid "Attempting Refocus: Camera Focus Invalid" +msgstr "嘗試對焦:相機已失焦" + +#: selfdrive/controls/lib/events.py:539 +msgid "Out of Storage Space" +msgstr "儲存空間不足" + +#: selfdrive/controls/lib/events.py:544 +msgid "Speed Too Low" +msgstr "車速過慢" + +#: selfdrive/controls/lib/events.py:549 selfdrive/controls/lib/events.py:553 +msgid "NEOS Update Required" +msgstr "NEOS 需要更新" + +#: selfdrive/controls/lib/events.py:550 +msgid "Please Wait for Update" +msgstr "更新中請稍候" + +#: selfdrive/controls/lib/events.py:558 selfdrive/controls/lib/events.py:562 +msgid "No Data from Device Sensors" +msgstr "未收到裝置傳感器數據" + +#: selfdrive/controls/lib/events.py:559 selfdrive/controls/lib/events.py:572 +#: selfdrive/controls/lib/events.py:669 +msgid "Reboot your Device" +msgstr "請重啟裝置" + +#: selfdrive/controls/lib/events.py:571 selfdrive/controls/lib/events.py:575 +msgid "Speaker not found" +msgstr "找不到音效裝置" + +#: selfdrive/controls/lib/events.py:579 +msgid "Distraction Level Too High" +msgstr "駕駛分心太多次" + +#: selfdrive/controls/lib/events.py:583 +msgid "System Overheated" +msgstr "系統過熱" + +#: selfdrive/controls/lib/events.py:584 +msgid "System overheated" +msgstr "系統過熱" + +#: selfdrive/controls/lib/events.py:588 selfdrive/controls/lib/events.py:589 +msgid "Gear not D" +msgstr "不在 D 檔位" + +#: selfdrive/controls/lib/events.py:594 +#, fuzzy +msgid "Calibration Invalid" +msgstr "正在校準中" + +#: selfdrive/controls/lib/events.py:595 +#, fuzzy +msgid "Reposition Device and Recalibrate" +msgstr "校準無效:請將裝置放於新的位置並重新校準" + +#: selfdrive/controls/lib/events.py:598 selfdrive/controls/lib/events.py:599 +msgid "Calibration Invalid: Reposition Device & Recalibrate" +msgstr "校準無效:請將裝置放於新的位置並重新校準" + +#: selfdrive/controls/lib/events.py:603 selfdrive/controls/lib/events.py:605 +msgid "Calibration in Progress" +msgstr "正在校準中" + +#: selfdrive/controls/lib/events.py:609 +msgid "Door Open" +msgstr "車門開啟" + +#: selfdrive/controls/lib/events.py:610 +msgid "Door open" +msgstr "車門未關" + +#: selfdrive/controls/lib/events.py:614 +msgid "Seatbelt Unlatched" +msgstr "安全帶未繫" + +#: selfdrive/controls/lib/events.py:615 +msgid "Seatbelt unlatched" +msgstr "安全帶未繫" + +#: selfdrive/controls/lib/events.py:619 selfdrive/controls/lib/events.py:620 +msgid "ESP Off" +msgstr "ESP 關閉" + +#: selfdrive/controls/lib/events.py:624 selfdrive/controls/lib/events.py:625 +msgid "Low Battery" +msgstr "電量過低" + +#: selfdrive/controls/lib/events.py:629 selfdrive/controls/lib/events.py:630 +msgid "Communication Issue between Processes" +msgstr "行程間出現通訊問題" + +#: selfdrive/controls/lib/events.py:635 selfdrive/controls/lib/events.py:636 +msgid "Radar Communication Issue" +msgstr "雷達通訊出現問題" + +#: selfdrive/controls/lib/events.py:641 selfdrive/controls/lib/events.py:642 +#: selfdrive/controls/lib/events.py:646 selfdrive/controls/lib/events.py:647 +msgid "Radar Error: Restart the Car" +msgstr "雷達訊號錯誤:請重新發動車輛" + +#: selfdrive/controls/lib/events.py:651 selfdrive/controls/lib/events.py:652 +msgid "Driving model lagging" +msgstr "操控模型有延遲" + +#: selfdrive/controls/lib/events.py:656 selfdrive/controls/lib/events.py:657 +msgid "Vision Model Output Uncertain" +msgstr "視覺模型判斷不明確" + +#: selfdrive/controls/lib/events.py:661 selfdrive/controls/lib/events.py:662 +msgid "Device Fell Off Mount" +msgstr "裝置掉落偵測" + +#: selfdrive/controls/lib/events.py:666 selfdrive/controls/lib/events.py:672 +msgid "Low Memory: Reboot Your Device" +msgstr "記憶體不足:請重啟您的裝置" + +#: selfdrive/controls/lib/events.py:668 +msgid "RAM Critically Low" +msgstr "記憶體嚴重不足" + +#: selfdrive/controls/lib/events.py:677 selfdrive/controls/lib/events.py:678 +msgid "Controls Failed" +msgstr "控制發生錯誤" + +#: selfdrive/controls/lib/events.py:682 +msgid "Controls Mismatch" +msgstr "控制不匹配" + +#: selfdrive/controls/lib/events.py:686 selfdrive/controls/lib/events.py:688 +#: selfdrive/controls/lib/events.py:692 +msgid "CAN Error: Check Connections" +msgstr "CAN 訊號錯誤:請檢查線路" + +#: selfdrive/controls/lib/events.py:696 selfdrive/controls/lib/events.py:702 +msgid "LKAS Fault: Restart the Car" +msgstr "LKAS 錯誤:請重新發動車輛" + +#: selfdrive/controls/lib/events.py:698 +msgid "LKAS Fault: Restart the car to engage" +msgstr "LKAS 錯誤:請重新發動車輛" + +#: selfdrive/controls/lib/events.py:706 selfdrive/controls/lib/events.py:712 +#: selfdrive/controls/lib/events.py:795 +msgid "Cruise Fault: Restart the Car" +msgstr "巡航系統錯誤:請重新發動車輛" + +#: selfdrive/controls/lib/events.py:708 selfdrive/controls/lib/events.py:791 +msgid "Cruise Fault: Restart the car to engage" +msgstr "巡航系統錯誤:請重新發動車輛" + +#: selfdrive/controls/lib/events.py:716 +msgid "Gas Fault: Restart the Car" +msgstr "油門錯誤:請重新發動車輛" + +#: selfdrive/controls/lib/events.py:717 +msgid "Gas Error: Restart the Car" +msgstr "油門錯誤:請重新發動車輛" + +#: selfdrive/controls/lib/events.py:722 +#, fuzzy +msgid "" +"Reverse\n" +"Gear" +msgstr "切換至倒車檔" + +#: selfdrive/controls/lib/events.py:726 +msgid "Reverse Gear" +msgstr "切換至倒車檔" + +#: selfdrive/controls/lib/events.py:731 +msgid "Cruise Is Off" +msgstr "巡航系統關閉" + +#: selfdrive/controls/lib/events.py:735 selfdrive/controls/lib/events.py:736 +msgid "Planner Solution Error" +msgstr "Planner Solution 錯誤" + +#: selfdrive/controls/lib/events.py:740 selfdrive/controls/lib/events.py:742 +#: selfdrive/controls/lib/events.py:746 +msgid "Harness Malfunction" +msgstr "Harness 故障" + +#: selfdrive/controls/lib/events.py:743 +msgid "Please Check Hardware" +msgstr "請檢查硬體" + +#: selfdrive/controls/lib/events.py:751 selfdrive/controls/lib/events.py:760 +msgid "openpilot Canceled" +msgstr "openpilot 已取消" + +#: selfdrive/controls/lib/events.py:752 +msgid "No close lead car" +msgstr "前方沒有車輛" + +#: selfdrive/controls/lib/events.py:755 +msgid "No Close Lead Car" +msgstr "前方沒有車輛" + +#: selfdrive/controls/lib/events.py:761 +msgid "Speed too low" +msgstr "車速過慢" + +#: selfdrive/controls/lib/events.py:768 selfdrive/controls/lib/events.py:773 +msgid "Speed Too High" +msgstr "車速過快" + +#: selfdrive/controls/lib/events.py:769 +msgid "Slow down to resume operation" +msgstr "請減速後再啟用" + +#: selfdrive/controls/lib/events.py:774 +msgid "Slow down to engage" +msgstr "請減速後再啟用" + +#: selfdrive/controls/lib/events.py:781 +msgid "Please connect to Internet" +msgstr "請連接網路" + +#: selfdrive/controls/lib/events.py:782 +msgid "An Update Check Is Required to Engage" +msgstr "需檢查更新後才能啟用" + +#: selfdrive/controls/lib/events.py:785 +msgid "Please Connect to Internet" +msgstr "請連接網路" + +#: selfdrive/controls/lib/events.py:801 +msgid "Left ALC will start in 3s" +msgstr "準備自動切至左車道" + +#: selfdrive/controls/lib/events.py:809 +msgid "Right ALC will start in 3s" +msgstr "準備自動切至右車道" + +#: selfdrive/controls/lib/events.py:817 +msgid "STEERING REQUIRED: Lane Keeping OFF" +msgstr "請接管方向盤:車道維持關閉" + +#: selfdrive/controls/lib/events.py:825 +msgid "STEERING REQUIRED: Blinkers ON" +msgstr "請接管方向盤:方向燈開啟" + +#: selfdrive/controls/lib/events.py:833 selfdrive/controls/lib/events.py:838 +msgid "Lead Car Is Moving" +msgstr "前方車輛車移動中" + +#: selfdrive/controls/lib/events.py:847 +msgid "WARNING" +msgstr "警告" + +#: selfdrive/controls/lib/events.py:848 +msgid "Grab wheel to start bypass" +msgstr "請握好方向盤以繞過時間限制" + +#: selfdrive/controls/lib/events.py:855 +msgid "BYPASSING" +msgstr "繞過時間限制中" + +#: selfdrive/controls/lib/events.py:856 +msgid "HOLD WHEEL" +msgstr "握好方向盤" + +#: selfdrive/controls/lib/events.py:863 +msgid "Bypassed!" +msgstr "時間限制已繞過" + +#: selfdrive/controls/lib/events.py:864 +msgid "Release wheel when ready" +msgstr "準備好後請鬆開放向盤" diff --git a/selfdrive/assets/offroad/icon_empty.png b/selfdrive/assets/offroad/icon_empty.png new file mode 100644 index 000000000..a1d2ae57e Binary files /dev/null and b/selfdrive/assets/offroad/icon_empty.png differ diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index 1659b692c..07e0b5710 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -25,7 +25,7 @@ from common.api import Api from common.basedir import PERSIST from common.params import Params from common.realtime import sec_since_boot -from selfdrive.hardware import HARDWARE, PC, TICI +from selfdrive.hardware import HARDWARE, PC, TICI, JETSON from selfdrive.loggerd.config import ROOT from selfdrive.loggerd.xattr_cache import getxattr, setxattr from selfdrive.swaglog import cloudlog, SWAGLOG_DIR @@ -304,7 +304,7 @@ def get_logs_to_send_sorted(): def log_handler(end_event): - if PC: + if PC or JETSON: return log_files = [] diff --git a/selfdrive/athena/registration.py b/selfdrive/athena/registration.py index 6bcb29e4b..1ffc70bd4 100644 --- a/selfdrive/athena/registration.py +++ b/selfdrive/athena/registration.py @@ -11,7 +11,7 @@ from common.spinner import Spinner from common.file_helpers import mkdirs_exists_ok from common.basedir import PERSIST from selfdrive.controls.lib.alertmanager import set_offroad_alert -from selfdrive.hardware import HARDWARE +from selfdrive.hardware import HARDWARE, JETSON from selfdrive.swaglog import cloudlog @@ -20,6 +20,10 @@ UNREGISTERED_DONGLE_ID = "UnregisteredDevice" def register(show_spinner=False) -> str: params = Params() + if not params.get_bool('dp_reg') or params.get_bool('dp_jetson'): + return UNREGISTERED_DONGLE_ID + if JETSON: + return UNREGISTERED_DONGLE_ID params.put("SubscriberInfo", HARDWARE.get_subscriber_info()) IMEI = params.get("IMEI", encoding='utf8') diff --git a/selfdrive/boardd/SConscript b/selfdrive/boardd/SConscript index f2a1f3f7b..65ca9c7f5 100644 --- a/selfdrive/boardd/SConscript +++ b/selfdrive/boardd/SConscript @@ -1,4 +1,14 @@ Import('env', 'envCython', 'common', 'cereal', 'messaging') +# dp - Add read dp_toyota_disable_relay value +if FindFile('dp_toyota_disable_relay', '/data/params/d') != None: + with open('/data/params/d/dp_toyota_disable_relay') as f: + if (int(f.read().strip())) == 1: + env.Append(CCFLAGS='-DDisableRelay') + +if FindFile('dp_panda_no_gps', '/data/params/d') != None: + with open('/data/params/d/dp_panda_no_gps') as f: + if (int(f.read().strip())) == 1: + env.Append(CCFLAGS='-DNoGPS') env.Program('boardd', ['boardd.cc', 'panda.cc', 'pigeon.cc'], LIBS=['usb-1.0', common, cereal, 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 e52c8d2e6..fa1920c48 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -45,10 +45,13 @@ ExitHandler do_exit; void safety_setter_thread() { LOGD("Starting safety setter thread"); // diagnostic only is the default, needed for VIN query + #ifndef DisableRelay panda->set_safety_model(cereal::CarParams::SafetyModel::ELM327); + #endif Params p = Params(); + #ifndef DisableRelay // switch to SILENT when CarVin param is read while (true) { if (do_exit || !panda->connected){ @@ -68,7 +71,7 @@ void safety_setter_thread() { // VIN query done, stop listening to OBDII panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); - + #endif std::string params; LOGW("waiting for params to set safety model"); while (true) { @@ -90,7 +93,7 @@ void safety_setter_thread() { cereal::CarParams::Reader car_params = cmsg.getRoot(); cereal::CarParams::SafetyModel safety_model = car_params.getSafetyModel(); - panda->set_unsafe_mode(0); // see safety_declarations.h for allowed values + panda->set_unsafe_mode(9); // see safety_declarations.h for allowed values auto safety_param = car_params.getSafetyParam(); LOGW("setting safety model: %d with param %d", (int)safety_model, safety_param); @@ -276,12 +279,12 @@ void panda_state_thread(bool spoofing_started) { if (spoofing_started) { pandaState.ignition_line = 1; } - + #ifndef DisableRelay // 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 (pandaState.safety_model == (uint8_t)(cereal::CarParams::SafetyModel::SILENT)) { panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); } - + #endif ignition = ((pandaState.ignition_line != 0) || (pandaState.ignition_can != 0)); if (ignition) { @@ -295,11 +298,12 @@ void panda_state_thread(bool spoofing_started) { if (pandaState.power_save_enabled != power_save_desired){ panda->set_power_saving(power_save_desired); } - + #ifndef DisableRelay // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect if (!ignition && (pandaState.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) { panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); } + #endif #endif // clear VIN, CarParams, and set new safety on car start @@ -415,7 +419,7 @@ void hardware_control_thread() { cnt++; sm.update(1000); // TODO: what happens if EINTR is sent while in sm.update? - if (!Hardware::PC() && sm.updated("deviceState")){ + if (!Hardware::PC() && !Hardware::JETSON() && sm.updated("deviceState")){ // Charging mode bool charging_disabled = sm["deviceState"].getDeviceState().getChargingDisabled(); if (charging_disabled != prev_charging_disabled){ @@ -475,6 +479,15 @@ static void pigeon_publish_raw(PubMaster &pm, const std::string &dat) { } void pigeon_thread() { + // dp - use toyota directly + #ifdef DisableRelay + panda->set_safety_model(cereal::CarParams::SafetyModel::TOYOTA); + #endif + + // from @florianbrede-ayet, disable gps for white panda + #ifdef NoGPS + return; + #endif PubMaster pm({"ubloxRaw"}); bool ignition_last = false; @@ -556,7 +569,7 @@ int main() { err = set_realtime_priority(54); LOG("set priority returns %d", err); - err = set_core_affinity(Hardware::TICI() ? 4 : 3); + err = set_core_affinity(Hardware::TICI() || Hardware::JETSON() ? 4 : 3); LOG("set affinity returns %d", err); while (!do_exit){ diff --git a/selfdrive/camerad/SConscript b/selfdrive/camerad/SConscript index c12d25407..afc3218c1 100644 --- a/selfdrive/camerad/SConscript +++ b/selfdrive/camerad/SConscript @@ -1,4 +1,4 @@ -Import('env', 'arch', 'cereal', 'messaging', 'common', 'gpucommon', 'visionipc', 'USE_WEBCAM') +Import('env', 'arch', 'cereal', 'messaging', 'common', 'gpucommon', 'visionipc', 'USE_WEBCAM', 'USE_MIPI') libs = ['m', 'pthread', common, 'jpeg', 'OpenCL', cereal, messaging, 'zmq', 'capnp', 'kj', visionipc, gpucommon] @@ -9,7 +9,14 @@ elif arch == "larch64": libs += ['atomic'] cameras = ['cameras/camera_qcom2.cc'] else: - if USE_WEBCAM: + if USE_MIPI: + libs += ['opencv_core', 'opencv_highgui', 'opencv_imgproc', 'opencv_videoio'] + cameras = ['cameras/camera_mipi.cc'] + env = env.Clone() + env.Append(CXXFLAGS = '-DMIPI') + env.Append(CFLAGS = '-DMIPI') + env.Append(CPPPATH = '/usr/local/include/opencv4') + elif USE_WEBCAM: libs += ['opencv_core', 'opencv_highgui', 'opencv_imgproc', 'opencv_videoio'] cameras = ['cameras/camera_webcam.cc'] env = env.Clone() diff --git a/selfdrive/camerad/cameras/camera_common.cc b/selfdrive/camerad/cameras/camera_common.cc index cf629bde3..17377d287 100644 --- a/selfdrive/camerad/cameras/camera_common.cc +++ b/selfdrive/camerad/cameras/camera_common.cc @@ -23,6 +23,8 @@ #include "selfdrive/camerad/cameras/camera_qcom2.h" #elif WEBCAM #include "selfdrive/camerad/cameras/camera_webcam.h" +#elif MIPI +#include "selfdrive/camerad/cameras/camera_mipi.h" #else #include "selfdrive/camerad/cameras/camera_frame_stream.h" #endif diff --git a/selfdrive/camerad/cameras/camera_common.h b/selfdrive/camerad/cameras/camera_common.h index ab3efce28..7387bc3bb 100644 --- a/selfdrive/camerad/cameras/camera_common.h +++ b/selfdrive/camerad/cameras/camera_common.h @@ -25,7 +25,8 @@ #define CAMERA_ID_LGC920 6 #define CAMERA_ID_LGC615 7 #define CAMERA_ID_AR0231 8 -#define CAMERA_ID_MAX 9 +#define CAMERA_ID_IMX219 9 +#define CAMERA_ID_MAX 10 #define UI_BUF_COUNT 4 #define YUV_COUNT 40 diff --git a/selfdrive/camerad/cameras/camera_mipi.cc b/selfdrive/camerad/cameras/camera_mipi.cc new file mode 100644 index 000000000..eb96dcffb --- /dev/null +++ b/selfdrive/camerad/cameras/camera_mipi.cc @@ -0,0 +1,154 @@ +#include "selfdrive/camerad/cameras/camera_mipi.h" + +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundefined-inline" +#include +#include +#include +#include +#pragma clang diagnostic pop + +#include "selfdrive/common/clutil.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" + +// id of the video capturing device +const int ROAD_CAMERA_ID = getenv("ROADCAM_ID") ? atoi(getenv("ROADCAM_ID")) : 1; + +#define FRAME_WIDTH 1164 +#define FRAME_HEIGHT 874 +#define FRAME_WIDTH_FRONT 1152 +#define FRAME_HEIGHT_FRONT 864 + +extern ExitHandler do_exit; + +namespace { + +CameraInfo cameras_supported[CAMERA_ID_MAX] = { + // road facing + [CAMERA_ID_IMX219] = { + .frame_width = FRAME_WIDTH, + .frame_height = FRAME_HEIGHT, + .frame_stride = FRAME_WIDTH*3, + .bayer = false, + .bayer_flip = false, + }, +}; +std::string gstreamer_pipeline(int sensor_id, int capture_width, int capture_height, int framerate, int flip_method, int display_width, int display_height) { + return "nvarguscamerasrc sensor_mode=1 sensor-id=" + std::to_string(sensor_id) + " ! video/x-raw(memory:NVMM), width=(int)" + std::to_string(capture_width) + ", height=(int)" + + std::to_string(capture_height) + ", format=(string)NV12, framerate=(fraction)" + std::to_string(framerate) + + "/1 ! nvvidconv flip-method=" + std::to_string(flip_method) + " ! video/x-raw, width=(int)" + std::to_string(display_width) + ", height=(int)" + + std::to_string(display_height) + ", format=(string)BGRx ! videoconvert ! video/x-raw, format=(string)BGR ! appsink"; +} +void camera_open(CameraState *s, bool rear) { + // empty +} + +void camera_close(CameraState *s) { + // empty +} + +void camera_init(VisionIpcServer * v, CameraState *s, int camera_id, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type) { + assert(camera_id < std::size(cameras_supported)); + s->ci = cameras_supported[camera_id]; + assert(s->ci.frame_width != 0); + + s->camera_num = camera_id; + s->fps = fps; + s->buf.init(device_id, ctx, s, v, FRAME_BUF_COUNT, rgb_type, yuv_type); +} + +void run_camera(CameraState *s, cv::VideoCapture &video_cap, float *ts) { + assert(video_cap.isOpened()); + + cv::Size size(s->ci.frame_width, s->ci.frame_height); + const cv::Mat transform = cv::Mat(3, 3, CV_32F, ts); + uint32_t frame_id = 0; + size_t buf_idx = 0; + + while (!do_exit) { + cv::Mat frame_mat, transformed_mat; + video_cap >> frame_mat; + cv::warpPerspective(frame_mat, transformed_mat, transform, size, cv::INTER_LINEAR, cv::BORDER_CONSTANT, 0); + + s->buf.camera_bufs_metadata[buf_idx] = {.frame_id = frame_id}; + + auto &buf = s->buf.camera_bufs[buf_idx]; + int transformed_size = transformed_mat.total() * transformed_mat.elemSize(); + CL_CHECK(clEnqueueWriteBuffer(buf.copy_q, buf.buf_cl, CL_TRUE, 0, transformed_size, transformed_mat.data, 0, NULL, NULL)); + + s->buf.queue(buf_idx); + + ++frame_id; + buf_idx = (buf_idx + 1) % FRAME_BUF_COUNT; + } +} + +static void road_camera_thread(CameraState *s) { + set_thread_name("mipi_road_camera_thread"); + + std::string pipeline = gstreamer_pipeline( + 1, + 1920, + 1280, + s->fps, + 2, + 800, + 600); + + cv::VideoCapture cap_road(pipeline, cv::CAP_GSTREAMER); // road + + // transforms calculation see tools/webcam/warp_vis.py + float ts[9] = {1.50330396, 0.0, -59.40969163, + 0.0, 1.50330396, 76.20704846, + 0.0, 0.0, 1.0}; + run_camera(s, cap_road, ts); +} + +} // namespace + +void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) { + camera_init(v, &s->road_cam, CAMERA_ID_IMX219, 20, device_id, ctx, + VISION_STREAM_RGB_BACK, VISION_STREAM_YUV_BACK); + s->pm = new PubMaster({"roadCameraState", /*"driverCameraState,"*/ "thumbnail"}); +} + +void camera_autoexposure(CameraState *s, float grey_frac) {} + +void cameras_open(MultiCameraState *s) { + camera_open(&s->road_cam, true); +} + +void cameras_close(MultiCameraState *s) { + camera_close(&s->road_cam); + delete s->pm; +} + +void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) { + const CameraBuf *b = &c->buf; + MessageBuilder msg; + auto framed = msg.initEvent().initRoadCameraState(); + fill_frame_data(framed, b->cur_frame_data); + framed.setImage(kj::arrayPtr((const uint8_t *)b->cur_yuv_buf->addr, b->cur_yuv_buf->len)); + framed.setTransform(b->yuv_transform.v); + s->pm->send("roadCameraState", msg); +} + +void cameras_run(MultiCameraState *s) { + std::vector threads; + threads.push_back(start_process_thread(s, &s->road_cam, process_road_camera)); + + std::thread t_rear = std::thread(road_camera_thread, &s->road_cam); + set_thread_name("mipi_thread"); + + t_rear.join(); + + for (auto &t : threads) t.join(); + + cameras_close(s); +} diff --git a/selfdrive/camerad/cameras/camera_mipi.h b/selfdrive/camerad/cameras/camera_mipi.h new file mode 100644 index 000000000..819387f3d --- /dev/null +++ b/selfdrive/camerad/cameras/camera_mipi.h @@ -0,0 +1,28 @@ +#pragma once + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include "selfdrive/camerad/cameras/camera_common.h" + +#define FRAME_BUF_COUNT 16 + +typedef struct CameraState { + CameraInfo ci; + int camera_num; + int fps; + float digital_gain; + CameraBuf buf; +} CameraState; + + +typedef struct MultiCameraState { + CameraState road_cam; + CameraState driver_cam; + + SubMaster *sm; + PubMaster *pm; +} MultiCameraState; diff --git a/selfdrive/camerad/cameras/camera_qcom.cc b/selfdrive/camerad/cameras/camera_qcom.cc index aa386e5c8..a2a0059bd 100644 --- a/selfdrive/camerad/cameras/camera_qcom.cc +++ b/selfdrive/camerad/cameras/camera_qcom.cc @@ -27,7 +27,7 @@ // leeco actuator (DW9800W H-Bridge Driver IC) // from sniff -const uint16_t INFINITY_DAC = 364; +//const uint16_t INFINITY_DAC = 364; extern ExitHandler do_exit; @@ -48,9 +48,25 @@ CameraInfo cameras_supported[CAMERA_ID_MAX] = { .frame_height = 1748, .frame_stride = 2912, .bayer = true, - .bayer_flip = 3, + .bayer_flip = 0, .hdr = true }, + [CAMERA_ID_IMX179] = { + .frame_width = 3280, + .frame_height = 2464, + .frame_stride = 4104, + .bayer = true, + .bayer_flip = 0, + .hdr = false + }, + [CAMERA_ID_S5K3P8SP] = { + .frame_width = 2304, + .frame_height = 1728, + .frame_stride = 2880, + .bayer = true, + .bayer_flip = 1, + .hdr = false + }, [CAMERA_ID_OV8865] = { .frame_width = 1632, .frame_height = 1224, @@ -162,6 +178,24 @@ static int ov8865_apply_exposure(CameraState *s, int gain, int integ_lines, uint return sensor_write_regs(s, reg_array, std::size(reg_array), MSM_CAMERA_I2C_BYTE_DATA); } +static int imx179_s5k3p8sp_apply_exposure(CameraState *s, int gain, int integ_lines, uint32_t frame_length) { + //printf("driver camera: %d %d %d\n", gain, integ_lines, frame_length); + struct msm_camera_i2c_reg_array reg_array[] = { + {0x104,0x1,0}, + + // FRM_LENGTH + {0x340, (uint16_t)(frame_length >> 8), 0}, {0x341, (uint16_t)(frame_length & 0xff), 0}, + // coarse_int_time + {0x202, (uint16_t)(integ_lines >> 8), 0}, {0x203, (uint16_t)(integ_lines & 0xff),0}, + // global_gain + {0x204, (uint16_t)(gain >> 8), 0}, {0x205, (uint16_t)(gain & 0xff),0}, + + // REG_HOLD + {0x104,0x0,0}, + }; + return sensor_write_regs(s, reg_array, std::size(reg_array), MSM_CAMERA_I2C_BYTE_DATA); +} + static void camera_init(VisionIpcServer *v, CameraState *s, int camera_id, int camera_num, uint32_t pixel_clock, uint32_t line_length_pclk, uint32_t max_gain, uint32_t fps, cl_device_id device_id, cl_context ctx, @@ -179,18 +213,41 @@ static void camera_init(VisionIpcServer *v, CameraState *s, int camera_id, int c s->frame_length = s->pixel_clock / line_length_pclk / s->fps; s->self_recover = 0; - s->apply_exposure = (camera_id == CAMERA_ID_IMX298) ? imx298_apply_exposure : ov8865_apply_exposure; + if (camera_id == CAMERA_ID_IMX298) { + s->apply_exposure = imx298_apply_exposure; + } else if (camera_id == CAMERA_ID_S5K3P8SP || camera_id == CAMERA_ID_IMX179) { + s->apply_exposure = imx179_s5k3p8sp_apply_exposure; + } else { + s->apply_exposure = ov8865_apply_exposure; + } s->buf.init(device_id, ctx, s, v, FRAME_BUF_COUNT, rgb_type, yuv_type, camera_release_buffer); } void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) { char project_name[1024] = {0}; property_get("ro.boot.project_name", project_name, ""); - assert(strlen(project_name) == 0); - // sensor is flipped in LP3 - // IMAGE_ORIENT = 3 - init_array_imx298[0].reg_data = 3; + char product_name[1024] = {0}; + property_get("ro.product.name", product_name, ""); + + if (strlen(project_name) == 0) { + LOGD("LePro 3 op system detected"); + s->device = DEVICE_LP3; + + // sensor is flipped in LP3 + // IMAGE_ORIENT = 3 + init_array_imx298[0].reg_data = 3; + cameras_supported[CAMERA_ID_IMX298].bayer_flip = 3; + } else if (strcmp(product_name, "OnePlus3") == 0 && strcmp(project_name, "15811") != 0) { + // no more OP3 support + s->device = DEVICE_OP3; + assert(false); + } else if (strcmp(product_name, "OnePlus3") == 0 && strcmp(project_name, "15811") == 0) { + // only OP3T support + s->device = DEVICE_OP3T; + } else { + assert(false); + } // 0 = ISO 100 // 256 = ISO 200 @@ -212,11 +269,30 @@ void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_i #endif device_id, ctx, VISION_STREAM_RGB_BACK, VISION_STREAM_YUV_BACK); + s->road_cam.apply_exposure = imx298_apply_exposure; - camera_init(v, &s->driver_cam, CAMERA_ID_OV8865, 1, - /*pixel_clock=*/72000000, /*line_length_pclk=*/1602, - /*max_gain=*/510, 10, device_id, ctx, - VISION_STREAM_RGB_FRONT, VISION_STREAM_YUV_FRONT); + if (s->device == DEVICE_OP3T) { + camera_init(v, &s->driver_cam, CAMERA_ID_S5K3P8SP, 1, + /*pixel_clock=*/560000000, /*line_length_pclk=*/5120, + /*max_gain=*/510, 10, device_id, ctx, + VISION_STREAM_RGB_FRONT, VISION_STREAM_YUV_FRONT); + s->driver_cam.apply_exposure = imx179_s5k3p8sp_apply_exposure; + } else if (s->device == DEVICE_LP3) { + camera_init(v, &s->driver_cam, CAMERA_ID_OV8865, 1, + /*pixel_clock=*/72000000, /*line_length_pclk=*/1602, + /*max_gain=*/510, 10, device_id, ctx, + VISION_STREAM_RGB_FRONT, VISION_STREAM_YUV_FRONT); + s->driver_cam.apply_exposure = ov8865_apply_exposure; + } else { + camera_init(v, &s->driver_cam, CAMERA_ID_IMX179, 1, + /*pixel_clock=*/251200000, /*line_length_pclk=*/3440, + /*max_gain=*/224, 20, device_id, ctx, + VISION_STREAM_RGB_FRONT, VISION_STREAM_YUV_FRONT); + s->driver_cam.apply_exposure = imx179_s5k3p8sp_apply_exposure; + } + + s->road_cam.device = s->device; + s->driver_cam.device = s->device; s->sm = new SubMaster({"driverState"}); s->pm = new PubMaster({"roadCameraState", "driverCameraState", "thumbnail"}); @@ -260,8 +336,10 @@ static void set_exposure(CameraState *s, float exposure_frac, float gain_frac) { if (gain != s->cur_gain || integ_lines != s->cur_integ_lines) { if (s->apply_exposure == ov8865_apply_exposure) { gain = 800 * gain_frac; // ISO + err = s->apply_exposure(s, gain, integ_lines, s->frame_length); + } else if (s->apply_exposure) { + err = s->apply_exposure(s, gain, integ_lines, s->frame_length); } - err = s->apply_exposure(s, gain, integ_lines, s->frame_length); if (err == 0) { std::lock_guard lk(s->frame_info_lock); s->cur_gain = gain; @@ -320,95 +398,310 @@ static void do_autoexposure(CameraState *s, float grey_frac) { } } -static void sensors_init(MultiCameraState *s) { - msm_camera_sensor_slave_info slave_infos[2] = { - (msm_camera_sensor_slave_info){ // road camera - .sensor_name = "imx298", - .eeprom_name = "sony_imx298", - .actuator_name = "dw9800w", - .ois_name = "", - .flash_name = "pmic", - .camera_id = CAMERA_0, - .slave_addr = 32, - .i2c_freq_mode = I2C_FAST_MODE, - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, - .sensor_id_info = {.sensor_id_reg_addr = 22, .sensor_id = 664, .module_id = 9, .vcm_id = 6}, - .power_setting_array = { - .power_setting_a = { - {.seq_type = SENSOR_GPIO, .delay = 1}, - {.seq_type = SENSOR_VREG, .seq_val = 2}, - {.seq_type = SENSOR_GPIO, .seq_val = 5, .config_val = 2}, - {.seq_type = SENSOR_VREG, .seq_val = 1}, - {.seq_type = SENSOR_VREG, .seq_val = 3, .delay = 1}, - {.seq_type = SENSOR_CLK, .config_val = 24000000, .delay = 1}, - {.seq_type = SENSOR_GPIO, .config_val = 2, .delay = 10}, - }, - .size = 7, - .power_down_setting_a = { - {.seq_type = SENSOR_CLK, .delay = 1}, - {.seq_type = SENSOR_GPIO, .delay = 1}, - {.seq_type = SENSOR_VREG, .seq_val = 1}, - {.seq_type = SENSOR_GPIO, .seq_val = 5}, - {.seq_type = SENSOR_VREG, .seq_val = 2}, - {.seq_type = SENSOR_VREG, .seq_val = 3, .delay = 1}, - }, - .size_down = 6, - }, - .is_init_params_valid = 0, - .sensor_init_params = {.modes_supported = 1, .position = BACK_CAMERA_B, .sensor_mount_angle = 90}, - .output_format = MSM_SENSOR_BAYER, - }, - (msm_camera_sensor_slave_info){ // driver camera - .sensor_name = "ov8865_sunny", - .eeprom_name = "ov8865_plus", - .actuator_name = "", - .ois_name = "", - .flash_name = "", - .camera_id = CAMERA_2, - .slave_addr = 108, - .i2c_freq_mode = I2C_FAST_MODE, - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, - .sensor_id_info = {.sensor_id_reg_addr = 12299, .sensor_id = 34917, .module_id = 2}, - .power_setting_array = { - .power_setting_a = { - {.seq_type = SENSOR_GPIO, .delay = 5}, - {.seq_type = SENSOR_VREG, .seq_val = 1}, - {.seq_type = SENSOR_VREG, .seq_val = 2}, - {.seq_type = SENSOR_VREG}, - {.seq_type = SENSOR_CLK, .config_val = 24000000, .delay = 1}, - {.seq_type = SENSOR_GPIO, .config_val = 2, .delay = 1}, - }, - .size = 6, - .power_down_setting_a = { - {.seq_type = SENSOR_GPIO, .delay = 5}, - {.seq_type = SENSOR_CLK, .delay = 1}, - {.seq_type = SENSOR_VREG}, - {.seq_type = SENSOR_VREG, .seq_val = 1}, - {.seq_type = SENSOR_VREG, .seq_val = 2, .delay = 1}, - }, - .size_down = 5, - }, - .is_init_params_valid = 0, - .sensor_init_params = {.modes_supported = 1, .position = FRONT_CAMERA_B, .sensor_mount_angle = 270}, - .output_format = MSM_SENSOR_BAYER, - }}; +static uint8_t* get_eeprom(int eeprom_fd, size_t *out_len) { + msm_eeprom_cfg_data cfg = {.cfgtype = CFG_EEPROM_GET_CAL_DATA}; + int err = cam_ioctl(eeprom_fd, VIDIOC_MSM_EEPROM_CFG, &cfg, "get_eeprom begin"); + assert(err >= 0); - unique_fd sensorinit_fd = open("/dev/v4l-subdev11", O_RDWR | O_NONBLOCK); - assert(sensorinit_fd >= 0); - for (auto &info : slave_infos) { - info.power_setting_array.power_setting = &info.power_setting_array.power_setting_a[0]; - info.power_setting_array.power_down_setting = &info.power_setting_array.power_down_setting_a[0]; - sensor_init_cfg_data sensor_init_cfg = {.cfgtype = CFG_SINIT_PROBE, .cfg.setting = &info}; - int err = cam_ioctl(sensorinit_fd, VIDIOC_MSM_SENSOR_INIT_CFG, &sensor_init_cfg, "sensor init cfg"); - assert(err >= 0); + uint32_t num_bytes = cfg.cfg.get_data.num_bytes; + assert(num_bytes > 100); + + uint8_t* buffer = (uint8_t*)malloc(num_bytes); + assert(buffer); + memset(buffer, 0, num_bytes); + + cfg.cfgtype = CFG_EEPROM_READ_CAL_DATA; + cfg.cfg.read_data.num_bytes = num_bytes; + cfg.cfg.read_data.dbuffer = buffer; + err = cam_ioctl(eeprom_fd, VIDIOC_MSM_EEPROM_CFG, &cfg, "get_eeprom end"); + assert(err >= 0); + + *out_len = num_bytes; + return buffer; +} + +static void imx298_ois_calibration(int ois_fd, uint8_t* eeprom) { + const int ois_registers[][2] = { + // == SET_FADJ_PARAM() == (factory adjustment) + + // Set Hall Current DAC + {0x8230, *(uint16_t*)(eeprom+0x102)}, //_P_30_ADC_CH0 (CURDAT) + + // Set Hall PreAmp Offset + {0x8231, *(uint16_t*)(eeprom+0x104)}, //_P_31_ADC_CH1 (HALOFS_X) + {0x8232, *(uint16_t*)(eeprom+0x106)}, //_P_32_ADC_CH2 (HALOFS_Y) + + // Set Hall-X/Y PostAmp Offset + {0x841e, *(uint16_t*)(eeprom+0x108)}, //_M_X_H_ofs + {0x849e, *(uint16_t*)(eeprom+0x10a)}, //_M_Y_H_ofs + + // Set Residual Offset + {0x8239, *(uint16_t*)(eeprom+0x10c)}, //_P_39_Ch3_VAL_1 (PSTXOF) + {0x823b, *(uint16_t*)(eeprom+0x10e)}, //_P_3B_Ch3_VAL_3 (PSTYOF) + + // DIGITAL GYRO OFFSET + {0x8406, *(uint16_t*)(eeprom+0x110)}, //_M_Kgx00 + {0x8486, *(uint16_t*)(eeprom+0x112)}, //_M_Kgy00 + {0x846a, *(uint16_t*)(eeprom+0x120)}, //_M_TMP_X_ + {0x846b, *(uint16_t*)(eeprom+0x122)}, //_M_TMP_Y_ + + // HALLSENSE + // Set Hall Gain + {0x8446, *(uint16_t*)(eeprom+0x114)}, //_M_KgxHG + {0x84c6, *(uint16_t*)(eeprom+0x116)}, //_M_KgyHG + // Set Cross Talk Canceller + {0x8470, *(uint16_t*)(eeprom+0x124)}, //_M_KgxH0 + {0x8472, *(uint16_t*)(eeprom+0x126)}, //_M_KgyH0 + + // LOOPGAIN + {0x840f, *(uint16_t*)(eeprom+0x118)}, //_M_KgxG + {0x848f, *(uint16_t*)(eeprom+0x11a)}, //_M_KgyG + + // Position Servo ON ( OIS OFF ) + {0x847f, 0x0c0c}, //_M_EQCTL + }; + + struct msm_camera_i2c_seq_reg_array ois_reg_settings[std::size(ois_registers)] = {{0}}; + for (int i=0; i> 8) & 0xff; + ois_reg_settings[i].reg_data_size = 2; } + struct msm_camera_i2c_seq_reg_setting ois_reg_setting = { + .reg_setting = &ois_reg_settings[0], + .size = std::size(ois_reg_settings), + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .delay = 0, + }; + msm_ois_cfg_data cfg = {.cfgtype = CFG_OIS_I2C_WRITE_SEQ_TABLE, .cfg.settings = &ois_reg_setting}; + cam_ioctl(ois_fd, VIDIOC_MSM_OIS_CFG, &cfg, "ois reg calibration"); +} + +static void sensors_init(MultiCameraState *s) { + int err; + + unique_fd sensorinit_fd; + if (s->device == DEVICE_LP3) { + sensorinit_fd = open("/dev/v4l-subdev11", O_RDWR | O_NONBLOCK); + } else { + sensorinit_fd = open("/dev/v4l-subdev12", O_RDWR | O_NONBLOCK); + } + assert(sensorinit_fd >= 0); + + // init road camera sensor + + struct msm_camera_sensor_slave_info slave_info = {0}; + if (s->device == DEVICE_LP3) { + slave_info = (struct msm_camera_sensor_slave_info){ + .sensor_name = "imx298", + .eeprom_name = "sony_imx298", + .actuator_name = "dw9800w", + .ois_name = "", + .flash_name = "pmic", + .camera_id = CAMERA_0, + .slave_addr = 32, + .i2c_freq_mode = I2C_FAST_MODE, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .sensor_id_info = {.sensor_id_reg_addr = 22, .sensor_id = 664, .module_id = 9, .vcm_id = 6}, + .power_setting_array = { + .power_setting_a = { + {.seq_type = SENSOR_GPIO, .delay = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 2}, + {.seq_type = SENSOR_GPIO, .seq_val = 5, .config_val = 2}, + {.seq_type = SENSOR_VREG, .seq_val = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 3, .delay = 1}, + {.seq_type = SENSOR_CLK, .config_val = 24000000, .delay = 1}, + {.seq_type = SENSOR_GPIO, .config_val = 2, .delay = 10}, + }, + .size = 7, + .power_down_setting_a = { + {.seq_type = SENSOR_CLK, .delay = 1}, + {.seq_type = SENSOR_GPIO, .delay = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 1}, + {.seq_type = SENSOR_GPIO, .seq_val = 5}, + {.seq_type = SENSOR_VREG, .seq_val = 2}, + {.seq_type = SENSOR_VREG, .seq_val = 3, .delay = 1}, + }, + .size_down = 6, + }, + .is_init_params_valid = 0, + .sensor_init_params = {.modes_supported = 1, .position = BACK_CAMERA_B, .sensor_mount_angle = 90}, + .output_format = MSM_SENSOR_BAYER, + }; + } else { + slave_info = (struct msm_camera_sensor_slave_info){ + .sensor_name = "imx298", + .eeprom_name = "sony_imx298", + .actuator_name = "rohm_bu63165gwl", + .ois_name = "rohm_bu63165gwl", + .camera_id = CAMERA_0, + .slave_addr = 52, + .i2c_freq_mode = I2C_CUSTOM_MODE, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .sensor_id_info = {.sensor_id_reg_addr = 22, .sensor_id = 664}, + .power_setting_array = { + .power_setting_a = { + {.seq_type = SENSOR_GPIO, .delay = 2}, + {.seq_type = SENSOR_VREG, .seq_val = 2, .delay = 2}, + {.seq_type = SENSOR_VREG, .delay = 2}, + {.seq_type = SENSOR_VREG, .seq_val = 1, .delay = 2}, + {.seq_type = SENSOR_GPIO, .seq_val = 6, .config_val = 2}, + {.seq_type = SENSOR_VREG, .seq_val = 3, .delay = 5}, + {.seq_type = SENSOR_VREG, .seq_val = 4, .delay = 5}, + {.seq_type = SENSOR_CLK, .config_val = 24000000, .delay = 2}, + {.seq_type = SENSOR_GPIO, .config_val = 2, .delay = 2}, + }, + .size = 9, + .power_down_setting_a = { + {.seq_type = SENSOR_GPIO, .delay = 10}, + {.seq_type = SENSOR_CLK, .delay = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 4}, + {.seq_type = SENSOR_VREG, .seq_val = 3, .delay = 1}, + {.seq_type = SENSOR_GPIO, .seq_val = 6}, + {.seq_type = SENSOR_VREG, .seq_val = 1}, + {.seq_type = SENSOR_VREG}, + {.seq_type = SENSOR_VREG, .seq_val = 2}, + }, + .size_down = 8, + }, + .is_init_params_valid = 0, + .sensor_init_params = {.modes_supported = 1, .position = BACK_CAMERA_B, .sensor_mount_angle = 360}, + .output_format = MSM_SENSOR_BAYER, + }; + } + slave_info.power_setting_array.power_setting = + (struct msm_sensor_power_setting *)&slave_info.power_setting_array.power_setting_a[0]; + slave_info.power_setting_array.power_down_setting = + (struct msm_sensor_power_setting *)&slave_info.power_setting_array.power_down_setting_a[0]; + sensor_init_cfg_data sensor_init_cfg = {.cfgtype = CFG_SINIT_PROBE, .cfg.setting = &slave_info}; + err = cam_ioctl(sensorinit_fd, VIDIOC_MSM_SENSOR_INIT_CFG, &sensor_init_cfg, "sensor init cfg (road)"); + assert(err >= 0); + + struct msm_camera_sensor_slave_info slave_info2 = {0}; + if (s->device == DEVICE_LP3) { + slave_info2 = (struct msm_camera_sensor_slave_info){ + .sensor_name = "ov8865_sunny", + .eeprom_name = "ov8865_plus", + .actuator_name = "", + .ois_name = "", + .flash_name = "", + .camera_id = CAMERA_2, + .slave_addr = 108, + .i2c_freq_mode = I2C_FAST_MODE, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .sensor_id_info = {.sensor_id_reg_addr = 12299, .sensor_id = 34917, .module_id = 2}, + .power_setting_array = { + .power_setting_a = { + {.seq_type = SENSOR_GPIO, .delay = 5}, + {.seq_type = SENSOR_VREG, .seq_val = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 2}, + {.seq_type = SENSOR_VREG}, + {.seq_type = SENSOR_CLK, .config_val = 24000000, .delay = 1}, + {.seq_type = SENSOR_GPIO, .config_val = 2, .delay = 1}, + }, + .size = 6, + .power_down_setting_a = { + {.seq_type = SENSOR_GPIO, .delay = 5}, + {.seq_type = SENSOR_CLK, .delay = 1}, + {.seq_type = SENSOR_VREG}, + {.seq_type = SENSOR_VREG, .seq_val = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 2, .delay = 1}, + }, + .size_down = 5, + }, + .is_init_params_valid = 0, + .sensor_init_params = {.modes_supported = 1, .position = FRONT_CAMERA_B, .sensor_mount_angle = 270}, + .output_format = MSM_SENSOR_BAYER, + }; + } else if (s->driver_cam.camera_id == CAMERA_ID_S5K3P8SP) { + // init driver camera + slave_info2 = (struct msm_camera_sensor_slave_info){ + .sensor_name = "s5k3p8sp", + .eeprom_name = "s5k3p8sp_m24c64s", + .actuator_name = "", + .ois_name = "", + .camera_id = CAMERA_1, + .slave_addr = 32, + .i2c_freq_mode = I2C_FAST_MODE, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .sensor_id_info = {.sensor_id = 12552}, + .power_setting_array = { + .power_setting_a = { + {.seq_type = SENSOR_GPIO, .delay = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 2, .delay = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 1, .delay = 1}, + {.seq_type = SENSOR_VREG, .delay = 1}, + {.seq_type = SENSOR_CLK, .config_val = 24000000, .delay = 1}, + {.seq_type = SENSOR_GPIO, .config_val = 2, .delay = 1}, + }, + .size = 6, + .power_down_setting_a = { + {.seq_type = SENSOR_CLK, .delay = 1}, + {.seq_type = SENSOR_GPIO, .delay = 1}, + {.seq_type = SENSOR_VREG, .delay = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 1, .delay = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 2, .delay = 1}, + }, + .size_down = 5, + }, + .is_init_params_valid = 0, + .sensor_init_params = {.modes_supported = 1, .position = FRONT_CAMERA_B, .sensor_mount_angle = 270}, + .output_format = MSM_SENSOR_BAYER, + }; + } else { + // init driver camera + slave_info2 = (struct msm_camera_sensor_slave_info){ + .sensor_name = "imx179", + .eeprom_name = "sony_imx179", + .actuator_name = "", + .ois_name = "", + .camera_id = CAMERA_1, + .slave_addr = 32, + .i2c_freq_mode = I2C_FAST_MODE, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .sensor_id_info = {.sensor_id_reg_addr = 2, .sensor_id = 377, .sensor_id_mask = 4095}, + .power_setting_array = { + .power_setting_a = { + {.seq_type = SENSOR_VREG, .seq_val = 2}, + {.seq_type = SENSOR_VREG, .seq_val = 1}, + {.seq_type = SENSOR_VREG}, + {.seq_type = SENSOR_GPIO, .config_val = 2}, + {.seq_type = SENSOR_CLK, .config_val = 24000000}, + }, + .size = 5, + .power_down_setting_a = { + {.seq_type = SENSOR_CLK}, + {.seq_type = SENSOR_GPIO, .delay = 1}, + {.seq_type = SENSOR_VREG, .delay = 2}, + {.seq_type = SENSOR_VREG, .seq_val = 1}, + {.seq_type = SENSOR_VREG, .seq_val = 2}, + }, + .size_down = 5, + }, + .is_init_params_valid = 0, + .sensor_init_params = {.modes_supported = 1, .position = FRONT_CAMERA_B, .sensor_mount_angle = 270}, + .output_format = MSM_SENSOR_BAYER, + }; + } + slave_info2.power_setting_array.power_setting = + (struct msm_sensor_power_setting *)&slave_info2.power_setting_array.power_setting_a[0]; + slave_info2.power_setting_array.power_down_setting = + (struct msm_sensor_power_setting *)&slave_info2.power_setting_array.power_down_setting_a[0]; + sensor_init_cfg.cfgtype = CFG_SINIT_PROBE; + sensor_init_cfg.cfg.setting = &slave_info2; + err = cam_ioctl(sensorinit_fd, VIDIOC_MSM_SENSOR_INIT_CFG, &sensor_init_cfg, "sensor init cfg (driver)"); + assert(err >= 0); } static void camera_open(CameraState *s, bool is_road_cam) { + int err; + struct csid_cfg_data csid_cfg_data = {}; struct v4l2_event_subscription sub = {}; struct msm_actuator_cfg_data actuator_cfg_data = {}; + struct msm_ois_cfg_data ois_cfg_data = {}; // open devices const char *sensor_dev; @@ -417,19 +710,45 @@ static void camera_open(CameraState *s, bool is_road_cam) { assert(s->csid_fd >= 0); s->csiphy_fd = open("/dev/v4l-subdev0", O_RDWR | O_NONBLOCK); assert(s->csiphy_fd >= 0); - sensor_dev = "/dev/v4l-subdev17"; - s->isp_fd = open("/dev/v4l-subdev13", O_RDWR | O_NONBLOCK); + if (s->device == DEVICE_LP3) { + sensor_dev = "/dev/v4l-subdev17"; + } else { + sensor_dev = "/dev/v4l-subdev18"; + } + if (s->device == DEVICE_LP3) { + s->isp_fd = open("/dev/v4l-subdev13", O_RDWR | O_NONBLOCK); + } else { + s->isp_fd = open("/dev/v4l-subdev14", O_RDWR | O_NONBLOCK); + } assert(s->isp_fd >= 0); + s->eeprom_fd = open("/dev/v4l-subdev8", O_RDWR | O_NONBLOCK); + assert(s->eeprom_fd >= 0); + s->actuator_fd = open("/dev/v4l-subdev7", O_RDWR | O_NONBLOCK); assert(s->actuator_fd >= 0); + + if (s->device != DEVICE_LP3) { + s->ois_fd = open("/dev/v4l-subdev10", O_RDWR | O_NONBLOCK); + assert(s->ois_fd >= 0); + } } else { s->csid_fd = open("/dev/v4l-subdev5", O_RDWR | O_NONBLOCK); assert(s->csid_fd >= 0); s->csiphy_fd = open("/dev/v4l-subdev2", O_RDWR | O_NONBLOCK); assert(s->csiphy_fd >= 0); - sensor_dev = "/dev/v4l-subdev18"; - s->isp_fd = open("/dev/v4l-subdev14", O_RDWR | O_NONBLOCK); + if (s->device == DEVICE_LP3) { + sensor_dev = "/dev/v4l-subdev18"; + } else { + sensor_dev = "/dev/v4l-subdev19"; + } + if (s->device == DEVICE_LP3) { + s->isp_fd = open("/dev/v4l-subdev14", O_RDWR | O_NONBLOCK); + } else { + s->isp_fd = open("/dev/v4l-subdev15", O_RDWR | O_NONBLOCK); + } assert(s->isp_fd >= 0); + s->eeprom_fd = open("/dev/v4l-subdev9", O_RDWR | O_NONBLOCK); + assert(s->eeprom_fd >= 0); } // wait for sensor device @@ -448,7 +767,7 @@ static void camera_open(CameraState *s, bool is_road_cam) { struct msm_camera_csi_lane_params csi_lane_params = {0}; csi_lane_params.csi_lane_mask = 0x1f; csiphy_cfg_data csiphy_cfg_data = { .cfg.csi_lane_params = &csi_lane_params, .cfgtype = CSIPHY_RELEASE}; - int err = cam_ioctl(s->csiphy_fd, VIDIOC_MSM_CSIPHY_IO_CFG, &csiphy_cfg_data, "release csiphy"); + err = cam_ioctl(s->csiphy_fd, VIDIOC_MSM_CSIPHY_IO_CFG, &csiphy_cfg_data, "release csiphy"); // CSID: release csid csid_cfg_data.cfgtype = CSID_RELEASE; @@ -462,6 +781,12 @@ static void camera_open(CameraState *s, bool is_road_cam) { actuator_cfg_data.cfgtype = CFG_ACTUATOR_POWERDOWN; cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator powerdown"); + if (is_road_cam && s->device != DEVICE_LP3) { + // ois powerdown + ois_cfg_data.cfgtype = CFG_OIS_POWERDOWN; + err = cam_ioctl(s->ois_fd, VIDIOC_MSM_OIS_CFG, &ois_cfg_data, "ois powerdown"); + } + // reset isp // struct msm_vfe_axi_halt_cmd halt_cmd = { // .stop_camif = 1, @@ -487,6 +812,8 @@ static void camera_open(CameraState *s, bool is_road_cam) { // **** GO GO GO **** LOG("******************** GO GO GO ************************"); + s->eeprom = get_eeprom(s->eeprom_fd, &s->eeprom_size); + // CSID: init csid csid_cfg_data.cfgtype = CSID_INIT; cam_ioctl(s->csid_fd, VIDIOC_MSM_CSID_IO_CFG, &csid_cfg_data, "init csid"); @@ -516,6 +843,10 @@ static void camera_open(CameraState *s, bool is_road_cam) { // SENSOR: send i2c configuration if (s->camera_id == CAMERA_ID_IMX298) { err = sensor_write_regs(s, init_array_imx298, std::size(init_array_imx298), MSM_CAMERA_I2C_BYTE_DATA); + } else if (s->camera_id == CAMERA_ID_S5K3P8SP) { + err = sensor_write_regs(s, init_array_s5k3p8sp, std::size(init_array_s5k3p8sp), MSM_CAMERA_I2C_WORD_DATA); + } else if (s->camera_id == CAMERA_ID_IMX179) { + err = sensor_write_regs(s, init_array_imx179, std::size(init_array_imx179), MSM_CAMERA_I2C_BYTE_DATA); } else if (s->camera_id == CAMERA_ID_OV8865) { err = sensor_write_regs(s, init_array_ov8865, std::size(init_array_ov8865), MSM_CAMERA_I2C_BYTE_DATA); } else { @@ -531,56 +862,137 @@ static void camera_open(CameraState *s, bool is_road_cam) { actuator_cfg_data.cfgtype = CFG_ACTUATOR_INIT; cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator init"); - struct msm_actuator_reg_params_t actuator_reg_params[] = { - { - .reg_write_type = MSM_ACTUATOR_WRITE_DAC, - // MSB here at address 3 - .reg_addr = 3, - .data_type = 9, - .addr_type = 4, - }, - }; + // no OIS in LP3 + if (s->device != DEVICE_LP3) { + // see sony_imx298_eeprom_format_afdata in libmmcamera_sony_imx298_eeprom.so + const float far_margin = -0.28; + uint16_t macro_dac = *(uint16_t*)(s->eeprom + 0x24); + s->infinity_dac = *(uint16_t*)(s->eeprom + 0x26); + LOG("macro_dac: %d infinity_dac: %d", macro_dac, s->infinity_dac); - struct reg_settings_t actuator_init_settings[] = { - { .reg_addr=2, .addr_type=MSM_ACTUATOR_BYTE_ADDR, .reg_data=1, .data_type = MSM_ACTUATOR_BYTE_DATA, .i2c_operation = MSM_ACT_WRITE, .delay = 0 }, // PD = power down - { .reg_addr=2, .addr_type=MSM_ACTUATOR_BYTE_ADDR, .reg_data=0, .data_type = MSM_ACTUATOR_BYTE_DATA, .i2c_operation = MSM_ACT_WRITE, .delay = 2 }, // 0 = power up - { .reg_addr=2, .addr_type=MSM_ACTUATOR_BYTE_ADDR, .reg_data=2, .data_type = MSM_ACTUATOR_BYTE_DATA, .i2c_operation = MSM_ACT_WRITE, .delay = 2 }, // RING = SAC mode - { .reg_addr=6, .addr_type=MSM_ACTUATOR_BYTE_ADDR, .reg_data=64, .data_type = MSM_ACTUATOR_BYTE_DATA, .i2c_operation = MSM_ACT_WRITE, .delay = 0 }, // 0x40 = SAC3 mode - { .reg_addr=7, .addr_type=MSM_ACTUATOR_BYTE_ADDR, .reg_data=113, .data_type = MSM_ACTUATOR_BYTE_DATA, .i2c_operation = MSM_ACT_WRITE, .delay = 0 }, - // 0x71 = DIV1 | DIV0 | SACT0 -- Tvib x 1/4 (quarter) - // SAC Tvib = 6.3 ms + 0.1 ms = 6.4 ms / 4 = 1.6 ms - // LSC 1-step = 252 + 1*4 = 256 ms / 4 = 64 ms - }; + int dac_range = macro_dac - s->infinity_dac; + s->infinity_dac += far_margin * dac_range; - struct region_params_t region_params[] = { - {.step_bound = {238, 0,}, .code_per_step = 235, .qvalue = 128} - }; + LOG(" -> macro_dac: %d infinity_dac: %d", macro_dac, s->infinity_dac); - actuator_cfg_data.cfgtype = CFG_SET_ACTUATOR_INFO; - actuator_cfg_data.cfg.set_info = (struct msm_actuator_set_info_t){ - .actuator_params = { - .act_type = ACTUATOR_BIVCM, - .reg_tbl_size = 1, - .data_size = 10, - .init_setting_size = 5, - .i2c_freq_mode = I2C_STANDARD_MODE, - .i2c_addr = 24, - .i2c_addr_type = MSM_ACTUATOR_BYTE_ADDR, - .i2c_data_type = MSM_ACTUATOR_WORD_DATA, - .reg_tbl_params = &actuator_reg_params[0], - .init_settings = &actuator_init_settings[0], - .park_lens = {.damping_step = 1023, .damping_delay = 14000, .hw_params = 11, .max_step = 20}, - }, - .af_tuning_params = { - .initial_code = INFINITY_DAC, - .pwd_step = 0, - .region_size = 1, - .total_steps = 238, - .region_params = ®ion_params[0], - }, - }; + struct msm_actuator_reg_params_t actuator_reg_params[] = { + {.reg_write_type = MSM_ACTUATOR_WRITE_DAC, .reg_addr = 240, .data_type = 10, .addr_type = 4}, + {.reg_write_type = MSM_ACTUATOR_WRITE_DAC, .reg_addr = 241, .data_type = 10, .addr_type = 4}, + {.reg_write_type = MSM_ACTUATOR_WRITE_DAC, .reg_addr = 242, .data_type = 10, .addr_type = 4}, + {.reg_write_type = MSM_ACTUATOR_WRITE_DAC, .reg_addr = 243, .data_type = 10, .addr_type = 4}, + }; - cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator set info"); + //... + struct reg_settings_t actuator_init_settings[1] = {0}; + + struct region_params_t region_params[] = { + {.step_bound = {512, 0,}, .code_per_step = 118, .qvalue = 128} + }; + + actuator_cfg_data.cfgtype = CFG_SET_ACTUATOR_INFO; + actuator_cfg_data.cfg.set_info = (struct msm_actuator_set_info_t){ + .actuator_params = { + .act_type = ACTUATOR_VCM, + .reg_tbl_size = 4, + .data_size = 10, + .init_setting_size = 0, + .i2c_freq_mode = I2C_CUSTOM_MODE, + .i2c_addr = 28, + .i2c_addr_type = MSM_ACTUATOR_BYTE_ADDR, + .i2c_data_type = MSM_ACTUATOR_BYTE_DATA, + .reg_tbl_params = &actuator_reg_params[0], + .init_settings = &actuator_init_settings[0], + .park_lens = { + .damping_step = 1023, + .damping_delay = 15000, + .hw_params = 58404, + .max_step = 20, + } + }, + .af_tuning_params = { + .initial_code = (int16_t)s->infinity_dac, + .pwd_step = 0, + .region_size = 1, + .total_steps = 512, + .region_params = ®ion_params[0], + }, + }; + err = cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator set info"); + + // power up ois + ois_cfg_data.cfgtype = CFG_OIS_POWERUP; + err = cam_ioctl(s->ois_fd, VIDIOC_MSM_OIS_CFG, &ois_cfg_data, "ois powerup"); + + ois_cfg_data.cfgtype = CFG_OIS_INIT; + err = cam_ioctl(s->ois_fd, VIDIOC_MSM_OIS_CFG, &ois_cfg_data, "ois init"); + + ois_cfg_data.cfgtype = CFG_OIS_CONTROL; + ois_cfg_data.cfg.set_info.ois_params = (struct msm_ois_params_t){ + // .data_size = 26312, + .setting_size = 120, + .i2c_addr = 28, + .i2c_freq_mode = I2C_CUSTOM_MODE, + // .i2c_addr_type = wtf + // .i2c_data_type = wtf + .settings = &ois_init_settings[0], + }; + cam_ioctl(s->ois_fd, VIDIOC_MSM_OIS_CFG, &ois_cfg_data, "ois init settings"); + } else { + // leeco actuator (DW9800W H-Bridge Driver IC) + // from sniff + s->infinity_dac = 364; + + struct msm_actuator_reg_params_t actuator_reg_params[] = { + { + .reg_write_type = MSM_ACTUATOR_WRITE_DAC, + // MSB here at address 3 + .reg_addr = 3, + .data_type = 9, + .addr_type = 4, + }, + }; + + struct reg_settings_t actuator_init_settings[] = { + { .reg_addr=2, .addr_type=MSM_ACTUATOR_BYTE_ADDR, .reg_data=1, .data_type = MSM_ACTUATOR_BYTE_DATA, .i2c_operation = MSM_ACT_WRITE, .delay = 0 }, // PD = power down + { .reg_addr=2, .addr_type=MSM_ACTUATOR_BYTE_ADDR, .reg_data=0, .data_type = MSM_ACTUATOR_BYTE_DATA, .i2c_operation = MSM_ACT_WRITE, .delay = 2 }, // 0 = power up + { .reg_addr=2, .addr_type=MSM_ACTUATOR_BYTE_ADDR, .reg_data=2, .data_type = MSM_ACTUATOR_BYTE_DATA, .i2c_operation = MSM_ACT_WRITE, .delay = 2 }, // RING = SAC mode + { .reg_addr=6, .addr_type=MSM_ACTUATOR_BYTE_ADDR, .reg_data=64, .data_type = MSM_ACTUATOR_BYTE_DATA, .i2c_operation = MSM_ACT_WRITE, .delay = 0 }, // 0x40 = SAC3 mode + { .reg_addr=7, .addr_type=MSM_ACTUATOR_BYTE_ADDR, .reg_data=113, .data_type = MSM_ACTUATOR_BYTE_DATA, .i2c_operation = MSM_ACT_WRITE, .delay = 0 }, + // 0x71 = DIV1 | DIV0 | SACT0 -- Tvib x 1/4 (quarter) + // SAC Tvib = 6.3 ms + 0.1 ms = 6.4 ms / 4 = 1.6 ms + // LSC 1-step = 252 + 1*4 = 256 ms / 4 = 64 ms + }; + + struct region_params_t region_params[] = { + {.step_bound = {238, 0,}, .code_per_step = 235, .qvalue = 128} + }; + + actuator_cfg_data.cfgtype = CFG_SET_ACTUATOR_INFO; + actuator_cfg_data.cfg.set_info = (struct msm_actuator_set_info_t){ + .actuator_params = { + .act_type = ACTUATOR_BIVCM, + .reg_tbl_size = 1, + .data_size = 10, + .init_setting_size = 5, + .i2c_freq_mode = I2C_STANDARD_MODE, + .i2c_addr = 24, + .i2c_addr_type = MSM_ACTUATOR_BYTE_ADDR, + .i2c_data_type = MSM_ACTUATOR_WORD_DATA, + .reg_tbl_params = &actuator_reg_params[0], + .init_settings = &actuator_init_settings[0], + .park_lens = {.damping_step = 1023, .damping_delay = 14000, .hw_params = 11, .max_step = 20}, + }, + .af_tuning_params = { + .initial_code = (int16_t)s->infinity_dac, + .pwd_step = 0, + .region_size = 1, + .total_steps = 238, + .region_params = ®ion_params[0], + }, + }; + + cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator set info"); + } } if (s->camera_id == CAMERA_ID_IMX298) { @@ -592,6 +1004,10 @@ static void camera_open(CameraState *s, bool is_road_cam) { struct msm_camera_csiphy_params csiphy_params = {}; if (s->camera_id == CAMERA_ID_IMX298) { csiphy_params = {.lane_cnt = 4, .settle_cnt = 14, .lane_mask = 0x1f, .csid_core = 0}; + } else if (s->camera_id == CAMERA_ID_S5K3P8SP) { + csiphy_params = {.lane_cnt = 4, .settle_cnt = 24, .lane_mask = 0x1f, .csid_core = 0}; + } else if (s->camera_id == CAMERA_ID_IMX179) { + csiphy_params = {.lane_cnt = 4, .settle_cnt = 11, .lane_mask = 0x1f, .csid_core = 2}; } else if (s->camera_id == CAMERA_ID_OV8865) { // guess! csiphy_params = {.lane_cnt = 4, .settle_cnt = 24, .lane_mask = 0x1f, .csid_core = 2}; @@ -722,24 +1138,47 @@ static void camera_open(CameraState *s, bool is_road_cam) { cam_ioctl(s->isp_fd, VIDIOC_MSM_ISP_CFG_STREAM, &s->stream_cfg, "isp start stream"); } +static struct damping_params_t actuator_ringing_params = { + .damping_step = 1023, + .damping_delay = 15000, + .hw_params = 0x0000e422, +}; + static void road_camera_start(CameraState *s) { + struct msm_actuator_cfg_data actuator_cfg_data = {0}; + set_exposure(s, 1.0, 1.0); + int inf_step; int err = sensor_write_regs(s, start_reg_array, std::size(start_reg_array), MSM_CAMERA_I2C_BYTE_DATA); LOG("sensor start regs: %d", err); - int inf_step = 512 - INFINITY_DAC; + if (s->device != DEVICE_LP3) { + imx298_ois_calibration(s->ois_fd, s->eeprom); + inf_step = 332 - s->infinity_dac; - // initial guess - s->lens_true_pos = 400; + // initial guess + s->lens_true_pos = 300; + } else { + // default is OP3, this is for LeEco + actuator_ringing_params.damping_step = 1023; + actuator_ringing_params.damping_delay = 20000; + actuator_ringing_params.hw_params = 13; + + // focus on infinity assuming phone is perpendicular + inf_step = 512 - s->infinity_dac; + + // initial guess + s->lens_true_pos = 400; + } // reset lens position - struct msm_actuator_cfg_data actuator_cfg_data = {}; + memset(&actuator_cfg_data, 0, sizeof(actuator_cfg_data)); actuator_cfg_data.cfgtype = CFG_SET_POSITION; actuator_cfg_data.cfg.setpos = (struct msm_actuator_set_position_t){ .number_of_steps = 1, - .hw_params = (uint32_t)7, - .pos = {INFINITY_DAC, 0}, + .hw_params = (uint32_t)((s->device != DEVICE_LP3) ? 0x0000e424 : 7), + .pos = {s->infinity_dac, 0}, .delay = {0,} }; cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator set pos"); @@ -767,16 +1206,11 @@ static void road_camera_start(CameraState *s) { } void actuator_move(CameraState *s, uint16_t target) { + int step = target - s->cur_lens_pos; // LP3 moves only on even positions. TODO: use proper sensor params - - // focus on infinity assuming phone is perpendicular - static struct damping_params_t actuator_ringing_params = { - .damping_step = 1023, - .damping_delay = 20000, - .hw_params = 13, - }; - - int step = (target - s->cur_lens_pos) / 2; + if (s->device == DEVICE_LP3) { + step /= 2; + } int dest_step_pos = s->cur_step_pos + step; dest_step_pos = std::clamp(dest_step_pos, 0, 255); @@ -861,6 +1295,9 @@ static std::optional get_accel_z(SubMaster *sm) { } static void do_autofocus(CameraState *s, SubMaster *sm) { + const int dac_down = s->device == DEVICE_LP3 ? LP3_AF_DAC_DOWN : OP3T_AF_DAC_DOWN; + const int dac_up = s->device == DEVICE_LP3 ? LP3_AF_DAC_UP : OP3T_AF_DAC_UP; + float lens_true_pos = s->lens_true_pos.load(); if (!isnan(s->focus_err)) { // learn lens_true_pos @@ -873,8 +1310,8 @@ static void do_autofocus(CameraState *s, SubMaster *sm) { } const float sag = (s->last_sag_acc_z / 9.8) * 128; // stay off the walls - lens_true_pos = std::clamp(lens_true_pos, float(LP3_AF_DAC_DOWN), float(LP3_AF_DAC_UP)); - int target = std::clamp(lens_true_pos - sag, float(LP3_AF_DAC_DOWN), float(LP3_AF_DAC_UP)); + lens_true_pos = std::clamp(lens_true_pos, float(dac_down), float(dac_up)); + int target = std::clamp(lens_true_pos - sag, float(dac_down), float(dac_up)); s->lens_true_pos.store(lens_true_pos); /*char debug[4096]; @@ -929,7 +1366,11 @@ void cameras_open(MultiCameraState *s) { s->v4l_fd = open("/dev/video0", O_RDWR | O_NONBLOCK); assert(s->v4l_fd >= 0); - s->ispif_fd = open("/dev/v4l-subdev15", O_RDWR | O_NONBLOCK); + if (s->device == DEVICE_LP3) { + s->ispif_fd = open("/dev/v4l-subdev15", O_RDWR | O_NONBLOCK); + } else { + s->ispif_fd = open("/dev/v4l-subdev16", O_RDWR | O_NONBLOCK); + } assert(s->ispif_fd >= 0); // ISPIF: stop @@ -990,6 +1431,7 @@ static void camera_close(CameraState *s) { cam_ioctl(s->isp_fd, VIDIOC_MSM_ISP_RELEASE_STREAM, &stream_release, "isp release stream"); } } + free(s->eeprom); } const char* get_isp_event_name(uint32_t type) { @@ -1060,19 +1502,24 @@ static void ops_thread(MultiCameraState *s) { } static void setup_self_recover(CameraState *c, const uint16_t *lapres, size_t lapres_size) { + const int dac_down = c->device == DEVICE_LP3 ? LP3_AF_DAC_DOWN : OP3T_AF_DAC_DOWN; + const int dac_up = c->device == DEVICE_LP3 ? LP3_AF_DAC_UP : OP3T_AF_DAC_UP; + const int dac_m = c->device == DEVICE_LP3 ? LP3_AF_DAC_M : OP3T_AF_DAC_M; + const int dac_3sig = c->device == DEVICE_LP3 ? LP3_AF_DAC_3SIG : OP3T_AF_DAC_3SIG; + const float lens_true_pos = c->lens_true_pos.load(); int self_recover = c->self_recover.load(); - if (self_recover < 2 && (lens_true_pos < (LP3_AF_DAC_DOWN + 1) || lens_true_pos > (LP3_AF_DAC_UP - 1)) && is_blur(lapres, lapres_size)) { + if (self_recover < 2 && (lens_true_pos < (dac_down + 1) || lens_true_pos > (dac_up - 1)) && is_blur(lapres, lapres_size)) { // truly stuck, needs help if (--self_recover < -FOCUS_RECOVER_PATIENCE) { LOGD("road camera bad state detected. attempting recovery from %.1f, recover state is %d", lens_true_pos, self_recover); // parity determined by which end is stuck at - self_recover = FOCUS_RECOVER_STEPS + (lens_true_pos < LP3_AF_DAC_M ? 1 : 0); + self_recover = FOCUS_RECOVER_STEPS + (lens_true_pos < dac_m ? 1 : 0); } - } else if (self_recover < 2 && (lens_true_pos < (LP3_AF_DAC_M - LP3_AF_DAC_3SIG) || lens_true_pos > (LP3_AF_DAC_M + LP3_AF_DAC_3SIG))) { + } else if (self_recover < 2 && (lens_true_pos < (dac_m - dac_3sig) || lens_true_pos > (dac_m + dac_3sig))) { // in suboptimal position with high prob, but may still recover by itself if (--self_recover < -(FOCUS_RECOVER_PATIENCE * 3)) { - self_recover = FOCUS_RECOVER_STEPS / 2 + (lens_true_pos < LP3_AF_DAC_M ? 1 : 0); + self_recover = FOCUS_RECOVER_STEPS / 2 + (lens_true_pos < dac_m ? 1 : 0); } } else if (self_recover < 0) { self_recover += 1; // reset if fine diff --git a/selfdrive/camerad/cameras/camera_qcom.h b/selfdrive/camerad/cameras/camera_qcom.h index 1bcfed205..704c0995b 100644 --- a/selfdrive/camerad/cameras/camera_qcom.h +++ b/selfdrive/camerad/cameras/camera_qcom.h @@ -19,12 +19,20 @@ #define FRAME_BUF_COUNT 4 #define METADATA_BUF_COUNT 4 +#define DEVICE_OP3 0 +#define DEVICE_OP3T 1 +#define DEVICE_LP3 2 + #define NUM_FOCUS 8 #define LP3_AF_DAC_DOWN 366 #define LP3_AF_DAC_UP 634 #define LP3_AF_DAC_M 440 #define LP3_AF_DAC_3SIG 52 +#define OP3T_AF_DAC_DOWN 224 +#define OP3T_AF_DAC_UP 456 +#define OP3T_AF_DAC_M 300 +#define OP3T_AF_DAC_3SIG 96 #define FOCUS_RECOVER_PATIENCE 50 // 2.5 seconds of complete blur #define FOCUS_RECOVER_STEPS 240 // 6 seconds @@ -43,6 +51,7 @@ typedef struct StreamState { typedef struct CameraState { int camera_num; int camera_id; + int device; int fps; CameraInfo ci; @@ -71,7 +80,7 @@ typedef struct CameraState { camera_apply_exposure_func apply_exposure; // rear camera only,used for focusing - unique_fd actuator_fd; + unique_fd actuator_fd, ois_fd, eeprom_fd; std::atomic focus_err; std::atomic last_sag_acc_z; std::atomic lens_true_pos; @@ -80,10 +89,15 @@ typedef struct CameraState { uint16_t cur_lens_pos; int16_t focus[NUM_FOCUS]; uint8_t confidence[NUM_FOCUS]; + uint16_t infinity_dac; + size_t eeprom_size; + uint8_t *eeprom; } CameraState; typedef struct MultiCameraState { + int device; + unique_fd ispif_fd; unique_fd msmcfg_fd; unique_fd v4l_fd; diff --git a/selfdrive/camerad/cameras/sensor_i2c.h b/selfdrive/camerad/cameras/sensor_i2c.h index b46ebb370..3b4070c87 100644 --- a/selfdrive/camerad/cameras/sensor_i2c.h +++ b/selfdrive/camerad/cameras/sensor_i2c.h @@ -594,6 +594,1163 @@ static struct msm_camera_i2c_reg_array start_reg_array[] = {{0x100,0x1,0}}; // stop, enable standby mode static struct msm_camera_i2c_reg_array stop_reg_array[] = {{0x100,0x0,0}}; +/////////////////// + + +static struct msm_camera_i2c_reg_array init_array_imx179[] = { + { 0x100, 0x0, 0}, // MODE_SELECT + { 0x101, 0x0, 0}, // IMAGE_ORIENT + { 0x202, 0x9, 0}, { 0x203, 0xd2, 0}, // COARSE_INTEGRATION_TIME + { 0x301, 0x5, 0}, // vt_pix_clk_div + { 0x303, 0x1, 0}, // vt_sys_clk_div + { 0x305, 0x6, 0}, // pre_pll_clk_div + { 0x309, 0x5, 0}, // op_pix_clk_div + { 0x30b, 0x1, 0}, // op_sys_clk_div + { 0x30c, 0x0, 0}, { 0x30d, 0x9d, 0}, + + { 0x340, 0x9, 0}, { 0x341, 0xd6, 0}, // frame_length_lines + { 0x342, 0xd, 0}, { 0x343, 0x70, 0}, // line_length_pclk + { 0x344, 0x0, 0}, { 0x345, 0x0, 0}, // x_addr_start + { 0x346, 0x0, 0}, { 0x347, 0x0, 0}, // y_addr_start + { 0x348, 0xc, 0}, { 0x349, 0xcf, 0}, // last_pixel / x_addr_end + { 0x34a, 0x9, 0}, { 0x34b, 0x9f, 0}, // last_line / y_addr_end + { 0x34c, 0xc, 0}, { 0x34d, 0xd0, 0}, // pixels_per_line / x_output_size + { 0x34e, 0x9, 0}, { 0x34f, 0xa0, 0}, // lines_per_frame / y_output_size + { 0x383, 0x1, 0}, // x_odd_inc + { 0x387, 0x1, 0}, // y_odd_inc + { 0x390, 0x0, 0}, // binning_mode + { 0x401, 0x0, 0}, // SCALING_MODE + { 0x405, 0x10, 0}, // SCALE_M + + {0x3020, 0x10, 0}, + {0x3041, 0x15, 0}, // READ_MODE? + {0x3042, 0x87, 0}, + {0x3089, 0x4f, 0}, + {0x3309, 0x9a, 0}, + {0x3344, 0x57, 0}, + {0x3345, 0x1f, 0}, + {0x3362, 0xa, 0}, + {0x3363, 0xa, 0}, + {0x3364, 0x0, 0}, + {0x3368, 0x18, 0}, + {0x3369, 0x0, 0}, + {0x3370, 0x6f, 0}, + {0x3371, 0x27, 0}, + {0x3372, 0x4f, 0}, + {0x3373, 0x2f, 0}, + {0x3374, 0x27, 0}, + {0x3375, 0x2f, 0}, + {0x3376, 0x97, 0}, + {0x3377, 0x37, 0}, + {0x33c8, 0x0, 0}, + {0x33d4, 0xc, 0}, + {0x33d5, 0xd0, 0}, + {0x33d6, 0x9, 0}, + {0x33d7, 0xa0, 0}, + // znr + {0x4100, 0xe, 0}, + {0x4108, 0x1, 0}, + {0x4109, 0x7c, 0}, +}; + + + +/////////////// ois stuff /////////////// + +/* +#define _OP_FIRM_DWNLD 0x80 +#define _OP_Periphe_RW 0x82 +#define _OP_Memory__RW 0x84 +#define _OP_AD_TRNSFER 0x86 +#define _OP_COEF_DWNLD 0x88 +#define _OP_PrgMem__RD 0x8A +#define _OP_SpecialCMD 0x8C +*/ + +static struct reg_settings_ois_t ois_init_settings[] = { + { + .reg_addr = 0x8262, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0xbf03, + .data_type = MSM_CAMERA_I2C_WORD_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + },{ + .reg_addr = 0x8263, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x9f05, + .data_type = MSM_CAMERA_I2C_WORD_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + },{ + .reg_addr = 0x8264, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x6040, + .data_type = MSM_CAMERA_I2C_WORD_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + },{ + .reg_addr = 0x8260, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x1130, + .data_type = MSM_CAMERA_I2C_WORD_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + },{ + .reg_addr = 0x8265, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x8000, + .data_type = MSM_CAMERA_I2C_WORD_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + },{ + .reg_addr = 0x8261, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0280, + .data_type = MSM_CAMERA_I2C_WORD_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + },{ + .reg_addr = 0x8261, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0380, + .data_type = MSM_CAMERA_I2C_WORD_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + },{ + .reg_addr = 0x8261, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0988, + .data_type = MSM_CAMERA_I2C_WORD_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x34\x84\x00\x03\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x03\x00\x10\x7e\x84\x50\x00\x08\x40\x7e\xa0\x00\x03\x00\x10\x7e\x84\x60\x00\x08\x40\x7e\xa0\x00\x03\x00\x90\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8084, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x10\x08\x80\x00\xa0\x10\x00\x08\x7f\xff\x11\x8f\x02\x07\x80\x00\x11\x40\xff\xa0\x90\x01\x84\x20\x8f\x08\x40\xfe\x90\x40\xf5", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x80a0, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x08\x80\x01\xa0\x00\x01\x11\x8f\x02\x07\xff\xff\x11\x08\x00\x20\x50\x12\x07\x00\x10\x08\x80\x00\xa0\x10\xff\x84\x20\x0a", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x7f\xff\x21\x08\xfe\x84\x00\x04\x07\x20\x0c\x08\x7f\xff\x21\x08\xfe\x84\x00\x03\x00\x90\x17\x84\x20\x1f\x08\x80\x17\xa0\x10\x10", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x7f\xff\x21\x10\x00\x08\x01\x00\x11\x40\x51\xa0\x90\x17\x84\x20\x0f\x08\x80\x47\xa0\x8d\x0c\x07\x00\x00\x11\x30\x03\x07\x80\x41", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8090, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x50\x00\x08\x40\xfc\x90\x88\x2f\x84\x00\x00\x11\x30\x02\x07\x40\xff\x90\x50\x00\x08\x40\xfd\x90\x40\x7f\xa0\x10\xff\x84\x20\x2c", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x7f\xff\x11\x20\x0d\x08\x80\x0f\x90\x80\x26\xa0\x90\x2e\x84\x00\x10\x08\x90\x26\x84\x00\x10\x08\x80\x1f\xa0\x20\x2e\x08\x40\xed", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8090, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x20\x0f\x08\x80\x0e\x90\x00\x00\x21\x30\x02\x07\x40\xeb\xa0\x50\x00\x08\x40\xfe\x90\x40\x7f\xa0\x04\xeb\x84\x10\x00\x20\x20\x0f", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x80\x00\x21\x60\x04\x07\x40\xff\xa0\x10\x00\x08\x40\xea\x90\x10\x00\x20\x20\x0f\x08\x80\x00\x11\x00\x0b\x07\x08\x00\x20\x60\x0d", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\x00\x08\x40\xea\x90\x8f\x06\x07\x04\xff\x84\x20\x09\x60\x10\xfc\x84\x08\xfd\x84\x04\xfe\x84\x00\x03\x00\x00\x10\x08\x80\x37", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x80a0, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x90\x69\x84\x00\x10\x08\x80\x69\xa0\x20\x1a\x08\x40\x64\xa0\x10\x10\x08\x80\x4f\xa0\x20\x1d\x08\x40\x5f\xa0\x20\x1e\x08\x40\x5d", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x80a0, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\x00\x08\x80\x68\x90\x40\xfe\xa0\x20\x0e\x07\x50\x00\x08\x40\x7f\xa0\x04\xfe\x84\x00\x04\x00\x10\xf0\x44\x50\x00\x08\x00\x7f", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8011, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x20\xf0\x60\x04\x5c\x84\x04\x61\x84\x04\x57\x84\x00\x00\x21\x04\x74\x84\x00\x40\x21\x00\x0b\x07\x04\x74\x84\x00\x00\x21\x10\x57", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8084, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x30\x20\x08\x00\x04\x11\x50\x00\x08\x03\xff\x11\x20\xfa\x60\x10\xf0\x44\x50\x20\x08\x00\x7f\x11\x60\x20\x08\x40\x00\x08\x00\x08", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8011, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x30\x1a\x07\x50\x00\x08\x07\x00\x11\x9f\x1d\x07\x8b\x1e\x07\x9c\x15\x07\x20\xf8\x60\x10\x28\x44\x60\x00\x08\x01\x00\x11\x20\x28", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8060, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x87\x1b\x07\x40\xf7\xa0\x81\x27\x07\x20\x48\x60\x10\x0a\x44\x10\xf4\x84\x3b\xd4\x00\xe0\x14\x43\x08\x00\x20\x00\x06\x07\x89\x02", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\xae\x90\x81\x04\x07\x40\x2e\x90\x40\x7f\xa0\x10\x2e\x44\x20\x2f\x08\x9f\x02\x07\x00\x00\x11\x10\x00\x20\x00\x00\x08\x40\x67", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x80a0, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x11\x84\x02\x07\x20\xf0\x60\x9f\x03\x07\x40\x7e\xa0\x40\x65\x90\x10\x62\x84\x10\x10\x08\x40\x61\xa0\x20\x1d\x08\x40\x5f", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x80a0, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x20\x1e\x08\x40\x5d\xa0\x10\x00\x08\x40\x5e\x90\x20\x30\x60\x10\xcf\x84\x20\x1c\x08\x7f\xff\x21\x3b\xf7\x00\xc8\x14\x43\x10\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8020, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x08\x40\xb5\x90\x40\xad\xa0\x00\x0a\x07\x10\x4f\x84\x20\x1c\x08\x7f\xff\x21\x3c\x01\x00\x48\x14\x43\x10\x00\x20\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x35\x90\x40\x2d\xa0\x00\x14\x07\x80\x0c\x07\x82\x03\x07\x04\x50\x84\x10\x00\x20\x20\x02\x07\x00\x08\x21\x40\x00\x08\x00\x01", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8011, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x50\xa0\x00\x04\x00\x20\x7f\x00\x80\x14\x43\x01\x00\x01\x04\x00\x11\x02\x00\x21\x10\x9f\x84\x10\x20\x08\x40\x97\x90\x10\xbf", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8084, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x20\x1d\x08\x40\xc6\xa0\x20\x8e\x08\x40\x72\x90\x40\x16\xa0\x10\x96\x84\x10\x00\x08\x40\x9e\x90\x20\x36\x60\x20\x91\x00\x00\x14", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8043, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x01\x01\x00\x04\x11\x00\x02\x21\x10\x1f\x84\x10\x20\x08\x40\x17\x90\x10\x3f\x84\x20\x1d\x08\x40\x46\xa0\x20\x8e\x08\x40\x70", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8090, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x96\xa0\x10\x16\x84\x10\x00\x08\x40\x1e\x90\x20\x34\x60\x10\x65\x84\x50\x10\x08\x00\x00\x21\x84\x03\x07\x20\xf0\x60\x9f\x03", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x7e\xa0\x00\x10\x08\x40\x65\xa0\x20\x0d\x08\x40\x64\x90\x40\x62\xa0\x00\x04\x00\x04\x1c\x44\x04\x1b\x44\xc3\xff\x21\x87\x04", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x7f\xa0\x10\x42\x84\x20\x1e\x08\x7f\xff\x21\x10\x20\x08\x40\x1c\x90\x10\x07\x84\x10\x00\x08\x40\x06\x90\x40\x55\xa0\x10\xc2", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8084, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x20\x1e\x08\x7f\xff\x21\x10\x20\x08\x40\x9c\x90\x10\x87\x84\x10\x00\x08\x40\x86\x90\x40\x56\xa0\x10\x56\x84\x20\x0f\x08\x40\x7b", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8090, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x22\x00\x60\x40\x00\x08\x40\x79\xa0\x00\x08\x11\x10\x55\x84\x20\x0f\x08\x40\x7a\x90\x22\x00\x60\x50\x00\x08\x40\x79\xa0\x00\xff", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8011, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x04\x6f\x84\x00\x05\x21\x21\x39\x00\x04\x00\x11\x10\xc1\x84\x20\x0f\x08\x70\x07\x07\x10\x10\x08\x40\xc0\xa0\x20\x0f\x08\x7f\xff", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8011, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x8f\x02\x07\x80\x00\x11\x08\x00\x20\x08\xc1\x84\x40\xbd\x90\x9e\x02\x07\x40\x7f\xa0\x40\xec\x90\x04\x6e\x84\x00\x05\x21\x21\x4c", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x04\x11\x10\x41\x84\x20\x0f\x08\x70\x07\x07\x10\x10\x08\x40\x40\xa0\x20\x0f\x08\x7f\xff\x11\x8f\x02\x07\x80\x00\x11\x08\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8020, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x08\x41\x84\x40\x3d\x90\x9e\x02\x07\x40\x7f\xa0\x40\x6d\x90\x10\x2d\x44\x20\xe7\x00\x08\x00\x11\x20\x32\x60\x80\x14\x43\x10\x2c", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8044, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x20\xec\x00\x00\x08\x11\x20\x31\x60\x00\x14\x43\x04\x34\x44\x40\x5b\xa0\x00\x04\x00\x21\x6a\x00\x80\x00\x11\x21\x70\x00\x3f\xff", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8011, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x08\xe8\x84\x20\x32\x50\x08\x68\x84\x20\x31\x50\x08\x5e\x84\x20\x30\x50\x0f\xc4\x07\x10\x34\x44\x10\x5b\x84\x6f\xf3\x07\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x02\x00\x21\x40\xfc\x90\x3d\xd4\x00\x04\xfc\x84\x00\x00\x21\x04\xfd\x84\x00\x08\x21\x00\x04\x00\x21\x81\x00\xc0\x00\x11\x04\x5b", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8084, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x02\x00\x21\x70\x06\x07\x10\xfe\x84\x30\x20\x08\x00\x03\x11\x10\x00\x08\x40\x59\x90\x04\xff\x84\x40\x58\xa0\x10\x59\x84\x20\x0f", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x59\xa0\x20\x00\x11\x70\x1e\x07\x10\x00\x08\x00\x0b\x11\x0f\xe4\x07\x10\x59\x84\x00\x00\x08\x20\x30\x50\x40\x59\xa0\x70\x06", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\x00\x08\x00\x0a\x11\x0f\xec\x07\x08\x34\x44\x02\x10\x11\x10\x58\x84\x20\x0f\x08\x40\x58\xa0\x20\x00\x11\x30\x08\x07\x0f\xf4", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\x58\x84\x00\x00\x08\x20\x30\x50\x40\x58\xa0\x70\x06\x07\x10\x00\x08\x00\x05\x11\x00\x04\x00\x10\x5a\x84\x00\x00\x08\x00\x01", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8011, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x5a\xa0\x08\x34\x44\x02\x00\x11\x30\x08\x07\x60\x00\x08\x00\x00\x11\x40\x5a\xa0\x8f\x4f\x07\x40\x7e\xa0\x00\x04\x00\x3c\xdd", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\x00\x20\xa8\x14\x43\x04\xa7\x84\x20\x8e\x08\x40\xc4\x90\x40\xaf\xa0\x20\x0f\x08\x40\xc5\x90\x40\xa7\xa0\x3c\xe7\x00\x10\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8020, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x28\x14\x43\x04\x27\x84\x20\x8e\x08\x40\x44\x90\x40\x2f\xa0\x20\x0f\x08\x40\x45\x90\x40\x27\xa0\x00\x04\x00\x10\xf0\x44\x50\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\xff\xf7\x11\x93\x04\x07\x20\xf0\x60\x04\x61\x84\x04\x5c\x84\x40\x57\xa0\x00\x04\x00\x10\x61\x84\x00\x20\x08\x20\x1f\x08\x40\xff", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x80a0, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\x00\x08\x40\x5c\x90\x40\x57\xa0\x04\x74\x84\x10\x00\x20\x00\x00\x08\x40\x74\xa0\x00\x01\x11\x20\x05\x07\x00\x40\x21\x70\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x7f\xff\x21\x08\xff\x84\x42\x00\x90\x85\x02\x07\x20\xf0\x60\x7f\xff\x11\x60\x20\x08\x00\xd0\x11\x40\x00\x08\x00\x02\x11\x86\x1b", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x74\xa0\x08\x6f\x84\x00\x00\x11\x04\xf1\x84\x00\x40\x21\x21\xf7\x00\x02\x00\x11\x60\x07\x07\x10\x20\x08\x40\xc3\x90\x20\x2f", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x80\x00\x11\x70\x02\x07\x7f\xff\x11\x10\x00\x08\x40\x8d\x90\x40\x85\xa0\x08\x6e\x84\x00\x00\x11\x04\xf0\x84\x00\x40\x21\x22\x07", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x02\x11\x60\x07\x07\x10\x20\x08\x40\x43\x90\x20\x2f\x08\x80\x00\x11\x70\x02\x07\x7f\xff\x11\x10\x00\x08\x40\x0d\x90\x40\x05", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x80a0, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\xec\x84\x00\x10\x08\x10\xe7\x84\x40\xe7\xa0\x20\x0f\x08\x40\xef\xa0\x10\x6d\x84\x00\x10\x08\x10\x6c\x84\x40\x6c\xa0\x20\x0f", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x7d\xa0\x7f\xff\x11\x00\x04\x00\x10\xef\x84\x00\x10\x08\x10\xee\x84\x40\xee\xa0\x20\x0f\x08\x40\xbd\xa0\x10\x7d\x84\x00\x10", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\x7c\x84\x40\x7c\xa0\x20\x0f\x08\x40\x3d\xa0\x40\x00\x11\x3e\x9b\x00\xfb\xff\x21\x6f\x14\x43\x3e\x9e\x00\xff\xfb\x21\x6e\x14", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8043, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x3d\x57\x00\x40\xaf\xa0\xa0\x14\x43\x3d\x5a\x00\x40\x2f\xa0\x20\x14\x43\x00\x04\x00\x3d\x5e\x00\x40\xa5\xa0\xb0\x14\x43\x3d\x61", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x25\xa0\x30\x14\x43\x00\x00\x00\x22\x28\x00\x00\x02\x07\x22\x26\x00\x8a\x03\x07\x89\x04\x07\x40\x7e\xa0\x40\xbd\x90\x98\x14", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8043, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\x9c\x84\x20\x8f\x08\x40\x9a\x90\x40\x99\xa0\x20\x2e\x08\x40\xbd\x90\x00\x10\x08\x40\x9b\xa0\x20\x0e\x08\x7f\xff\x21\x40\xf5", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8090, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x22\x3c\x00\x00\x02\x07\x22\x3a\x00\x82\x03\x07\x81\x04\x07\x40\x7e\xa0\x40\x3d\x90\x18\x14\x43\x10\x1c\x84\x20\x8f", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8008, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x1a\x90\x40\x19\xa0\x20\x2e\x08\x40\x3d\x90\x00\x10\x08\x40\x1b\xa0\x20\x0e\x08\x7f\xff\x21\x40\xf5\x90\x3d\x8c\x00\xb8\x14", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8043, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\xc2\xa0\x3d\x8f\x00\x38\x14\x43\x40\x42\xa0\x00\x04\x00\x10\x51\x84\x20\x0f\x08\x7f\xc0\x11\x40\x51\xa0\x08\xbb\x84\x08\x3b", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8084, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\xcb\x90\x11\x9e\x02\x07\xc7\x00\x11\x40\x7f\xa0\x08\xba\x84\x08\x3a\x84\x74\x70\x11\x9e\x02\x07\x59\x00\x11\x40\x7f\xa0\x3e\xed", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\xfd\xff\x21\xf1\x14\x43\x3e\xf0\x00\xff\xfd\x21\xf0\x14\x43\x00\x04\x00\x04\xb9\x84\x40\xb6\xa0\x04\x39\x84\x40\x36\xa0\x00\x04", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x3e\xc3\x00\x40\x87\xa0\x80\x14\x43\x3e\xc6\x00\x40\x07\xa0\x00\x14\x43\x00\x04\x00\x00\x00\x00\x04\xf5\x84\x00\x00\x21\x70\x03", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\xf5\x84\x10\x00\x08\x40\xf3\x90\x40\xf5\xa0\x3e\xd2\x00\x40\x85\xa0\x88\x14\x43\x3e\xd5\x00\x40\x05\xa0\x08\x14\x43\x00\x04", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8000, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x01\x07\x00\x02\x07\x00\x03\x07\x00\x04\x07\x00\x06\x07\x00\x16\x07\x00\x1e\x07\x00\x24\x07\x00\x3c\x07\x00\x72\x07\x00\x8d", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\xe0\x07\x00\xf6\x07\x01\x9f\x07\x01\xd1\x07\x00\x10\x07\x1f\xff\x07\x20\x03\x60\x0f\x5f\x07\x08\xfa\x84\x04\x11\x44\xff\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8011, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x2f\x63\x07\x70\x10\x08\x00\xf0\x21\x50\x00\x08\x00\xf0\x21\x40\xf9\x90\x00\x08\x07\x3e\x79\x00\x0f\x6b\x07\x90\x01\x07\x40\xf9", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x80a0, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x3f\x6e\x07\x70\x00\x08\x00\x7f\x11\x40\xf8\xa0\x9d\x07\x07\x20\x12\x60\x08\xfa\x84\x04\x11\x44\x3e\x54\x00\x00\x16\x07\x48\x80", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8011, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x08\x09\x44\x40\x75\x90\x7f\xef\x07\x10\x00\x20\x00\x10\x08\xff\xff\x21\x06\x00\x84\x40\xfb\xa0\x60\x00\x08\x00\x00\x21\x40\xff", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8090, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\xfb\x84\x60\x20\x08\x40\xfb\x90\x30\x00\x08\x00\x08\x11\x3d\xea\x00\x04\xfb\x84\x3d\xec\x00\x04\xff\x84\x40\xf8\xa0\x04\x11", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8044, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x8f\xff\x07\x20\x19\x60\x3e\xd2\x00\x00\x31\x07\x00\x01\x00\x00\x33\x07\x00\x02\x00\x27\x18\x43\x75\x00\x43\x8f\xff\x07\x20\x19", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8060, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x04\xf5\x84\x40\xf2\xa0\x04\x51\x84\x7f\xff\x21\x04\xf5\x84\x00\x00\x21\x04\xf3\x84\x00\x10\x21\x04\xf2\x84\x0c\x00\x21\x04\x72", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8044, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x77\x21\x3f\xfa\x07\x70\x20\x08\x00\x00\x11\x10\x2d\x44\x10\x2c\x44\x00\x20\x08\x10\x00\x11\x00\x00\x08\x00\x00\x11\x80\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8021, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x04\x73\x44\x07\x07\x21\x04\x72\x44\x00\x07\x21\x04\x73\x44\x07\x77\x21\x04\x73\x44\x00\x70\x21\x04\x2e\x44\x04\x2d\x44\x04\x2c", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8044, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x80\x00\x21\x04\x1c\x44\x04\x1b\x44\x0d\x00\x21\x04\x1c\x44\x04\x1b\x44\x0c\x80\x21\x04\x1c\x44\x04\x1b\x44\x1f\x08\x21\x0f\x18", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8043, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x08\x28\x44\x01\x11\x11\x08\x5d\x84\x10\x00\x10\x10\x00\x08\x40\x00\x21\x30\x04\x07\x40\xff\x90\x50\x20\x08\xc0\x00\x11\x10\xff", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8084, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x20\x08\x00\x40\x11\x40\x00\x08\x00\x01\x11\x20\x51\x60\x10\x00\x44\x60\x00\x08\x40\x54\x90\x20\x00\x60\x00\x79\x07\x81\x48", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x80\x03\x07\x40\xf8\xa0\x48\xc0\x11\x00\x77\x07\x00\x78\x07\x00\x79\x07\x00\x04\x07\x00\x7b\x07\x00\x7c\x07\x00\x7d\x07\x00\x55", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8007, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x7f\x07\x00\x80\x07\x00\x81\x07\x00\x74\x07\x00\x83\x07\x00\x82\x07\x00\x85\x07\x00\x86\x07\x0f\xef\x07\x1f\xff\x07\xff\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8011, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x10\x00\x20\x30\x10\x08\x00\x01\x21\x50\x00\x08\x00\x0f\x21\x40\xf9\x90\x30\x90\x07\x70\x10\x08\x00\x80\x21\x50\x00\x08\x00\xf0", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8021, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x08\xf9\x84\x04\xf8\x84\x2f\xff\x07\x3e\x59\x00\x04\xf1\x84\x04\xf0\x84\x04\x5a\x84\x00\x00\x21\x04\xf6\x84\x00\x02\x21\x04\xfa", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8084, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x40\x00\x21\x04\xf7\x84\x01\x04\x21\x04\x1c\x44\x04\x1b\x44\x0b\x23\x21\x0f\x18\x43\x04\x70\x44\x06\x66\x21\x04\x3b\x44\x04\x39", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8044, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x80\x21\x04\x3c\x44\x2a\x0a\x21\x04\x2f\x44\x00\x44\x21\x04\x29\x44\x00\x00\x21\x03\x19\x42\x4e\x19\x43\x0c\x59\x43\x27\x18", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8043, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x15\x00\x43\x04\x22\x44\x03\x07\x21\x04\x21\x44\x11\x11\x21\x04\x20\x44\x33\x33\x21\x00\x00\x42\xc0\x3d\x42\x80\x3d\x43\x04\x35", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8044, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x21\x04\x05\x43\x42\xcd\x00", + .reg_data_seq_size = 9, + },{ + .reg_addr = 0x88ef, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x20\x00\x18\x00\x00\x00\x00\xab\x0a\x00\x40\x00\x40\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x27\x83\x64\x7e\xca\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x88b2, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x7f\x59\x7f\xbe\x7f\xfe\x7f\xfe\x7f\xee\x73\x54\x4c\x70\x5a\x00\x6b\x0e\x6b\x1c\x5b\xcb\x32\x8c\x0b\xd2\x13\x07\x28\x01\x49\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8800, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\xff\x7f\x0b\x97\x14\xae\xf7\x53\x26\x63\x07\x46\x00\x20\x00\x89\x00\x40\x80\x41\x00\x7f\xff\x7f\xd3\x09\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x88ff, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x7f\x00\x00\x00\x00\x90\xcb\x70\x74\xfe\x7f\x52\x09\x00\x00\xfe\x7f\x00\x00\x00\x00\x00\xf2\x00\x40\xf0\x7f\x00\x0c\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8800, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x4a\x00\x4a\x00\x24\xff\x7f\x00\x00\x00\x00\x00\x00\x00\x00\xff\x7f\x00\x00\x00\x50\x00\x30\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8800, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\xa0\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\x7f\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8800, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\xff\x7f\x00\x78\x00\x08\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\xff\x7f\x00\x40\x00\x40\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8800, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x80\xff\x7f\x1c\x1b\xc5\x07\xc0\x20\x12\xf0\x00\x10\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8800, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x59\x00\x00\x00\x40\x00\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8800, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\xff\x7f\x0b", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8897, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x14\xae\xf7\x53\x26\x63\x07\x46\x00\x20\x00\x89\x00\x40\x80\x41\x00\x7f\xff\x7f\xd3\x09\x00\x00\xff\x7f\x00\x00\x00\x00\x90\xcb", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8870, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x74\xfe\x7f\x52\x09\x00\x00\xfe\x7f\x00\x00\x00\x00\x00\xf2\x00\x40\xf0\x7f\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4a\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x884a, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x24\xff\x7f\x00\x00\x00\x00\x00\x00\x00\x00\xff\x7f\x00\x00\x00\x50\x00\x30\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x03", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8800, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\x7f\x00\x00\x00\x00\x00\x00\xff\x7f\x00", + .reg_data_seq_size = 32, + },{ + .reg_addr = 0x8878, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0000, + .data_type = MSM_CAMERA_I2C_SEQ_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "\x00\x08\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\xff\x7f\x00\x40\x00\x40", + .reg_data_seq_size = 18, + },{ + .reg_addr = 0x8205, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0c00, + .data_type = MSM_CAMERA_I2C_WORD_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + },{ + .reg_addr = 0x8205, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0d00, + .data_type = MSM_CAMERA_I2C_WORD_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + },{ + .reg_addr = 0x8c01, + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + .reg_data = 0x0001, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .i2c_operation = MSM_OIS_WRITE, + .delay = 0, + .reg_data_seq = "", + .reg_data_seq_size = 0, + } +}; + /* // still mode settings: {0x847f, 0x0c0c,}, //_M_EQCTL @@ -616,6 +1773,26 @@ static struct msm_camera_i2c_reg_array stop_reg_array[] = {{0x100,0x0,0}}; {0x847f, 0x0d0d,}, //_M_EQCTL */ +static struct msm_camera_i2c_reg_array init_array_s5k3p8sp[] = { + {0x6028,0x2000,0}, {0x6214,0x7971,0}, {0x6218,0x7150,0}, {0x30e,0x3d,0}, + {0x6028,0x2000,0}, {0x602a,0x2f38,0}, {0x6f12,0x88,0}, {0x6f12,0xd70,0}, + {0x344,0x18,0}, + {0x348,0x1217,0}, // last_pixel = 0x90C*2 + {0x346,0x18,0}, + {0x34a,0xd97,0}, // last_line = 0x6CC*2 + {0x34c,0x900,0}, // width? + {0x34e,0x6c0,0}, // height? + {0x342,0x1400,0}, // line_length_pclk + {0x340,0xe3b,0}, // frame_length_lines + {0x202,0x200,0}, // integ_time + {0x200,0x618,0}, + {0x900,0x122,0}, {0x380,0x1,0}, {0x382,0x3,0}, {0x384,0x3,0}, {0x386,0x1,0}, {0x400,0x0,0}, {0x404,0x10,0}, + {0x3604,0x2,0}, {0x3606,0x103,0}, {0xf496,0x48,0}, {0xf470,0x20,0}, {0xf43a,0x15,0}, {0xf484,0x6,0}, {0xf440,0xaf,0}, {0xf442,0x44c6,0}, + {0xf408,0xfff7,0}, {0x3664,0x19,0}, {0xf494,0x1010,0}, {0x367a,0x100,0}, {0x362a,0x104,0}, {0x362e,0x404,0}, {0x32b2,0x8,0}, {0x3286,0x3,0}, {0x328a,0x5,0}, + {0xf47c,0x1f,0}, {0xf62e,0xc5,0}, {0xf630,0xcd,0}, {0xf632,0xdd,0}, {0xf634,0xe5,0}, {0xf636,0xf5,0}, {0xf638,0xfd,0}, {0xf63a,0x10d,0}, {0xf63c,0x115,0}, {0xf63e,0x125,0}, {0xf640,0x12d,0}, + {0x6028,0x2000,0}, {0x602a,0x1704,0}, {0x6f12,0x8011,0}, {0x3070,0x0,0}, {0xb0e,0x0,0}, {0x317a,0x7,0}, {0x31c0,0xc8,0}, {0x1006,0x4,0}, {0x31a4,0x102,0}, +}; + static struct msm_camera_i2c_reg_array init_array_ov8865[] = { // round 1 //{0x103,0x1,0}, // software reset diff --git a/selfdrive/camerad/main.cc b/selfdrive/camerad/main.cc index 9636fd27b..a2c839b6c 100644 --- a/selfdrive/camerad/main.cc +++ b/selfdrive/camerad/main.cc @@ -21,6 +21,8 @@ #include "selfdrive/camerad/cameras/camera_qcom2.h" #elif WEBCAM #include "selfdrive/camerad/cameras/camera_webcam.h" +#elif MIPI +#include "selfdrive/camerad/cameras/camera_mipi.h" #else #include "selfdrive/camerad/cameras/camera_frame_stream.h" #endif @@ -47,7 +49,7 @@ int main(int argc, char *argv[]) { set_realtime_priority(53); if (Hardware::EON()) { set_core_affinity(2); - } else if (Hardware::TICI()) { + } else if (Hardware::TICI() || Hardware::JETSON()) { set_core_affinity(6); } diff --git a/selfdrive/camerad/snapshot/snapshot.py b/selfdrive/camerad/snapshot/snapshot.py index b7dd300da..52c67d65e 100755 --- a/selfdrive/camerad/snapshot/snapshot.py +++ b/selfdrive/camerad/snapshot/snapshot.py @@ -10,7 +10,7 @@ from typing import List import cereal.messaging as messaging from common.params import Params from common.realtime import DT_MDL -from common.transformations.camera import eon_f_frame_size, eon_d_frame_size, tici_f_frame_size +from common.transformations.camera import eon_f_frame_size, eon_d_frame_size, leon_d_frame_size, tici_f_frame_size from selfdrive.hardware import TICI from selfdrive.controls.lib.alertmanager import set_offroad_alert from selfdrive.manager.process_config import managed_processes @@ -39,7 +39,7 @@ def rois_in_focus(lapres: List[float]) -> float: def get_snapshots(frame="roadCameraState", front_frame="driverCameraState", focus_perc_threshold=0.): - frame_sizes = [eon_f_frame_size, eon_d_frame_size, tici_f_frame_size] + frame_sizes = [eon_f_frame_size, eon_d_frame_size, leon_d_frame_size, tici_f_frame_size] frame_sizes = {w * h: (w, h) for (w, h) in frame_sizes} sockets = [] diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index ba214410d..ee3d4c321 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.version import comma_remote, tested_branch from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars @@ -14,7 +14,7 @@ EventName = car.CarEvent.EventName def get_startup_event(car_recognized, controller_available, fuzzy_fingerprint, fw_seen): - if comma_remote and tested_branch: + if True: event = EventName.startup else: event = EventName.startupMaster @@ -87,7 +87,8 @@ def only_toyota_left(candidate_cars): # **** for use live only **** def fingerprint(logcan, sendcan): - fixed_fingerprint = os.environ.get('FINGERPRINT', "") + dp_car_assigned = Params().get('dp_car_assigned', encoding='utf8') + fixed_fingerprint = os.environ.get('FINGERPRINT', "" if dp_car_assigned is None else dp_car_assigned) skip_fw_query = os.environ.get('SKIP_FW_QUERY', False) if not fixed_fingerprint and not skip_fw_query: @@ -181,11 +182,26 @@ def get_car(logcan, sendcan): cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints) candidate = "mock" - CarInterface, CarController, CarState = interfaces[candidate] - car_params = CarInterface.get_params(candidate, fingerprints, car_fw) - car_params.carVin = vin - car_params.carFw = car_fw - car_params.fingerprintSource = source - car_params.fuzzyFingerprint = not exact_match + try: + CarInterface, CarController, CarState = interfaces[candidate] + car_params = CarInterface.get_params(candidate, fingerprints, car_fw) + candidate_changed = Params().get('dp_last_candidate') != candidate + put_nonblocking("dp_sr_stock", str(car_params.steerRatio)) + # update last candidate + if candidate_changed: + put_nonblocking('dp_last_candidate', candidate) + # update steering_ratio init val + dp_sr_custom = Params().get("dp_sr_custom", encoding='utf8') + if dp_sr_custom == '' or candidate_changed or (dp_sr_custom != '' and float(dp_sr_custom) <= 9.99): + put_nonblocking("dp_sr_custom", str(car_params.steerRatio)) + car_params.carVin = vin + car_params.carFw = car_fw + car_params.fingerprintSource = source + car_params.fuzzyFingerprint = not exact_match - return CarInterface(car_params, CarController, CarState), car_params + return CarInterface(car_params, CarController, CarState), car_params + except KeyError: + put_nonblocking("dp_car_assigned", '') + put_nonblocking("dp_sr_custom", '9.99') + put_nonblocking("dp_sr_stock", '9.99') + return None, None diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 46681b13e..c146aa722 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -3,9 +3,14 @@ from selfdrive.car.chrysler.chryslercan import create_lkas_hud, create_lkas_comm create_wheel_buttons from selfdrive.car.chrysler.values import CAR, CarControllerParams from opendbc.can.packer import CANPacker +from common.dp_common import common_controller_ctrl class CarController(): def __init__(self, dbc_name, CP, VM): + # dp + self.last_blinker_on = False + self.blinker_end_frame = 0. + self.apply_steer_last = 0 self.ccframe = 0 self.prev_frame = -1 @@ -16,7 +21,7 @@ class CarController(): self.packer = CANPacker(dbc_name) - def update(self, enabled, CS, actuators, pcm_cancel_cmd, hud_alert): + def update(self, enabled, CS, actuators, pcm_cancel_cmd, hud_alert, dragonconf): # this seems needed to avoid steering faults and to force the sync with the EPS counter frame = CS.lkas_counter if self.prev_frame == frame: @@ -40,6 +45,18 @@ class CarController(): if not lkas_active: apply_steer = 0 + # dp + blinker_on = CS.out.leftBlinker or CS.out.rightBlinker + if not enabled: + self.blinker_end_frame = 0 + if self.last_blinker_on and not blinker_on: + self.blinker_end_frame = frame + dragonconf.dpSignalOffDelay + apply_steer = common_controller_ctrl(enabled, + dragonconf, + blinker_on or frame < self.blinker_end_frame, + apply_steer, CS.out.vEgo) + self.last_blinker_on = blinker_on + self.apply_steer_last = apply_steer can_sends = [] diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index f37ae953a..f4ecdee9b 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -3,7 +3,7 @@ from cereal import car from selfdrive.car.chrysler.values import CAR from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase - +from common.dp_common import common_interface_atl, common_interface_get_params_lqr class CarInterface(CarInterfaceBase): @staticmethod @@ -15,6 +15,7 @@ class CarInterface(CarInterfaceBase): ret = CarInterfaceBase.get_std_params(candidate, fingerprint) ret.carName = "chrysler" ret.safetyModel = car.CarParams.SafetyModel.chrysler + ret.lateralTuning.init('pid') # Chrysler port is a community feature, since we don't own one to test ret.communityFeature = True @@ -53,15 +54,21 @@ class CarInterface(CarInterfaceBase): ret.enableBsm = 720 in fingerprint[0] + # dp + ret = common_interface_get_params_lqr(ret) + return ret # returns a car.CarState - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): # ******************* do can recv ******************* self.cp.update_strings(can_strings) self.cp_cam.update_strings(can_strings) ret = self.CS.update(self.cp, self.cp_cam) + # dp + self.dragonconf = dragonconf + ret.cruiseState.enabled = common_interface_atl(ret, dragonconf.dpAtl) ret.canValid = self.cp.can_valid and self.cp_cam.can_valid @@ -89,6 +96,6 @@ class CarInterface(CarInterfaceBase): if (self.CS.frame == -1): return [] # if we haven't seen a frame 220, then do not update. - can_sends = self.CC.update(c.enabled, self.CS, c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert) + can_sends = self.CC.update(c.enabled, self.CS, c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert, self.dragonconf) return can_sends diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 0949ffe22..ac9d31dd8 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -3,6 +3,7 @@ from cereal import car from selfdrive.car import make_can_msg from selfdrive.car.ford.fordcan import create_steer_command, create_lkas_ui, spam_cancel_button from opendbc.can.packer import CANPacker +from common.dp_common import common_controller_ctrl MAX_STEER_DELTA = 1 @@ -10,6 +11,10 @@ TOGGLE_DEBUG = False class CarController(): def __init__(self, dbc_name, CP, VM): + # dp + self.last_blinker_on = False + self.blinker_end_frame = 0. + self.packer = CANPacker(dbc_name) self.enable_camera = CP.enableCamera self.enabled_last = False @@ -19,13 +24,26 @@ class CarController(): self.steer_alert_last = False self.lkas_action = 0 - def update(self, enabled, CS, frame, actuators, visual_alert, pcm_cancel): + def update(self, enabled, CS, frame, actuators, visual_alert, pcm_cancel, dragonconf): can_sends = [] steer_alert = visual_alert == car.CarControl.HUDControl.VisualAlert.steerRequired apply_steer = actuators.steer + # dp + blinker_on = CS.out.leftBlinker or CS.out.rightBlinker + if not enabled: + self.blinker_end_frame = 0 + if self.last_blinker_on and not blinker_on: + self.blinker_end_frame = frame + dragonconf.dpSignalOffDelay + apply_steer = common_controller_ctrl(enabled, + dragonconf, + blinker_on or frame < self.blinker_end_frame, + apply_steer, CS.out.vEgo) + self.last_blinker_on = blinker_on + + if self.enable_camera: if pcm_cancel: diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py index 100d47240..2c517edae 100644 --- a/selfdrive/car/ford/carstate.py +++ b/selfdrive/car/ford/carstate.py @@ -8,6 +8,9 @@ from selfdrive.car.ford.values import DBC WHEEL_RADIUS = 0.33 class CarState(CarStateBase): + def __init__(self, CP): + super().__init__(CP) + def update(self, cp): ret = car.CarState.new_message() ret.wheelSpeeds.rr = cp.vl["WheelSpeed_CG1"]["WhlRr_W_Meas"] * WHEEL_RADIUS diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index aec368cd0..5f5c2e083 100755 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -5,6 +5,7 @@ from selfdrive.config import Conversions as CV from selfdrive.car.ford.values import MAX_ANGLE from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase +from common.dp_common import common_interface_atl, common_interface_get_params_lqr class CarInterface(CarInterfaceBase): @@ -17,6 +18,7 @@ class CarInterface(CarInterfaceBase): def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None): ret = CarInterfaceBase.get_std_params(candidate, fingerprint) ret.carName = "ford" + ret.lateralTuning.init('pid') ret.safetyModel = car.CarParams.SafetyModel.ford ret.dashcamOnly = True @@ -46,15 +48,20 @@ class CarInterface(CarInterfaceBase): ret.enableCamera = True cloudlog.warning("ECU Camera Simulated: %r", ret.enableCamera) + # dp + ret = common_interface_get_params_lqr(ret) + return ret # returns a car.CarState - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): # ******************* do can recv ******************* self.cp.update_strings(can_strings) ret = self.CS.update(self.cp) - + # dp + self.dragonconf = dragonconf + ret.cruiseState.enabled = common_interface_atl(ret, dragonconf.dpAtl) ret.canValid = self.cp.can_valid # events @@ -73,7 +80,7 @@ class CarInterface(CarInterfaceBase): def apply(self, c): can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators, - c.hudControl.visualAlert, c.cruiseControl.cancel) + c.hudControl.visualAlert, c.cruiseControl.cancel, self.dragonconf) self.frame += 1 return can_sends diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 116a562ac..2b1746f6f 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -6,12 +6,17 @@ from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car.gm import gmcan from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams from opendbc.can.packer import CANPacker +from common.dp_common import common_controller_ctrl VisualAlert = car.CarControl.HUDControl.VisualAlert class CarController(): def __init__(self, dbc_name, CP, VM): + # dp + self.last_blinker_on = False + self.blinker_end_frame = 0. + self.start_time = 0. self.apply_steer_last = 0 self.lka_icon_status_last = (False, False) @@ -24,7 +29,7 @@ class CarController(): self.packer_ch = CANPacker(DBC[CP.carFingerprint]['chassis']) def update(self, enabled, CS, frame, actuators, - hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert): + hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert, dragonconf): P = self.params @@ -41,6 +46,18 @@ class CarController(): else: apply_steer = 0 + # dp + blinker_on = CS.out.leftBlinker or CS.out.rightBlinker + if not enabled: + self.blinker_end_frame = 0 + if self.last_blinker_on and not blinker_on: + self.blinker_end_frame = frame + dragonconf.dpSignalOffDelay + apply_steer = common_controller_ctrl(enabled, + dragonconf, + blinker_on or frame < self.blinker_end_frame, + apply_steer, CS.out.vEgo) + self.last_blinker_on = blinker_on + self.apply_steer_last = apply_steer idx = (frame // P.STEER_STEP) % 4 diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 7c28406cb..fe59b59b9 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -5,6 +5,7 @@ from selfdrive.car.gm.values import CAR, CruiseButtons, \ AccState from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase +from common.dp_common import common_interface_atl, common_interface_get_params_lqr ButtonType = car.CarState.ButtonEvent.Type EventName = car.CarEvent.EventName @@ -19,6 +20,8 @@ class CarInterface(CarInterfaceBase): def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None): ret = CarInterfaceBase.get_std_params(candidate, fingerprint) ret.carName = "gm" + # dp + ret.lateralTuning.init('pid') ret.safetyModel = car.CarParams.SafetyModel.gm ret.enableCruise = False # stock cruise control is kept off @@ -112,14 +115,19 @@ class CarInterface(CarInterfaceBase): ret.steerLimitTimer = 0.4 ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz + # dp + ret = common_interface_get_params_lqr(ret) + return ret # returns a car.CarState - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): self.cp.update_strings(can_strings) ret = self.CS.update(self.cp) - + # dp + self.dragonconf = dragonconf + ret.cruiseState.enabled = common_interface_atl(ret, dragonconf.dpAtl) ret.canValid = self.cp.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False @@ -188,7 +196,7 @@ class CarInterface(CarInterfaceBase): can_sends = self.CC.update(enabled, self.CS, self.frame, c.actuators, hud_v_cruise, c.hudControl.lanesVisible, - c.hudControl.leadVisible, c.hudControl.visualAlert) + c.hudControl.leadVisible, c.hudControl.visualAlert, self.dragonconf) self.frame += 1 return can_sends diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 53304583b..0d00513f6 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -7,6 +7,7 @@ from selfdrive.car import create_gas_command from selfdrive.car.honda import hondacan from selfdrive.car.honda.values import CruiseButtons, CAR, VISUAL_HUD, HONDA_BOSCH, CarControllerParams from opendbc.can.packer import CANPacker +from common.dp_common import common_controller_ctrl VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -72,11 +73,33 @@ 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 CarController(): + def rough_speed(self, lead_distance): + if self.prev_lead_distance != lead_distance: + self.lead_distance_counter_prev = self.lead_distance_counter + self.rough_lead_speed += 0.3334 * ( + (lead_distance - self.prev_lead_distance) / self.lead_distance_counter_prev - self.rough_lead_speed) + self.lead_distance_counter = 0.0 + elif self.lead_distance_counter >= self.lead_distance_counter_prev: + self.rough_lead_speed = (self.lead_distance_counter * self.rough_lead_speed) / (self.lead_distance_counter + 1.0) + self.lead_distance_counter += 1.0 + self.prev_lead_distance = lead_distance + return self.rough_lead_speed + + def __init__(self, dbc_name, CP, VM): + # dp + self.last_blinker_on = False + self.blinker_end_frame = 0. + self.prev_lead_distance = 0.0 + self.stopped_lead_distance = 0.0 + self.lead_distance_counter = 1 + self.lead_distance_counter_prev = 1 + self.rough_lead_speed = 0.0 + self.braking = False self.brake_steady = 0. self.brake_last = 0. @@ -89,7 +112,7 @@ class CarController(): 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): + hud_v_cruise, hud_show_lanes, dragonconf, hud_show_car, hud_alert): P = self.params @@ -109,7 +132,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 @@ -125,25 +148,37 @@ 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 **** # steer torque is converted back to CAN reference (positive when steering right) 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 + blinker_on = CS.out.leftBlinker or CS.out.rightBlinker + if not enabled: + self.blinker_end_frame = 0 + if self.last_blinker_on and not blinker_on: + self.blinker_end_frame = frame + dragonconf.dpSignalOffDelay + apply_steer = common_controller_ctrl(enabled, + dragonconf, + blinker_on or frame < self.blinker_end_frame, + apply_steer, CS.out.vEgo) + self.last_blinker_on = blinker_on + # Send steering command. idx = frame % 4 can_sends.append(hondacan.create_steering_control(self.packer, apply_steer, lkas_active, CS.CP.carFingerprint, idx, CS.CP.openpilotLongitudinalControl)) # Send dashboard UI commands. - if (frame % 10) == 0: + if not dragonconf.dpAtl and (frame % 10) == 0: idx = (frame//10) % 4 can_sends.extend(hondacan.create_ui_commands(self.packer, pcm_speed, hud, CS.CP.carFingerprint, CS.is_metric, idx, CS.CP.openpilotLongitudinalControl, CS.stock_hud)) @@ -151,18 +186,35 @@ class CarController(): if (frame % 2) == 0: idx = frame // 2 can_sends.append(hondacan.create_bosch_supplemental_1(self.packer, CS.CP.carFingerprint, idx)) + if dragonconf.dpAtl: + pass # If using stock ACC, spam cancel command to kill gas when OP disengages. - if pcm_cancel_cmd: + elif not dragonconf.dpAllowGas and pcm_cancel_cmd: can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.CANCEL, idx, CS.CP.carFingerprint)) elif CS.out.cruiseState.standstill: - can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint)) + if CS.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORDH, CAR.INSIGHT): + rough_lead_speed = self.rough_speed(CS.lead_distance) + if CS.lead_distance > (self.stopped_lead_distance + 15.0) or rough_lead_speed > 0.1: + self.stopped_lead_distance = 0.0 + can_sends.append( + hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint)) + elif CS.CP.carFingerprint in (CAR.CIVIC_BOSCH, CAR.CRV_HYBRID): + if CS.hud_lead == 1: + can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint)) + else: + can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint)) + else: + self.stopped_lead_distance = CS.lead_distance + self.prev_lead_distance = CS.lead_distance else: # Send gas and brake commands. if (frame % 2) == 0: idx = frame // 2 ts = frame * DT_CTRL - if CS.CP.carFingerprint in HONDA_BOSCH: + if dragonconf.dpAtl: + pass + elif CS.CP.carFingerprint in HONDA_BOSCH: pass # TODO: implement else: apply_gas = clip(actuators.gas, 0., 1.) diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index d081fef0d..b0b627332 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -50,6 +50,7 @@ def get_can_signals(CP, gearbox_msg="GEARBOX"): ("PEDAL_GAS", "POWERTRAIN_DATA", 0), ("CRUISE_SETTING", "SCM_BUTTONS", 0), ("ACC_STATUS", "POWERTRAIN_DATA", 0), + ("HUD_LEAD", "ACC_HUD", 0), ] checks = [ @@ -120,12 +121,14 @@ def get_can_signals(CP, gearbox_msg="GEARBOX"): checks += [("CRUISE_PARAMS", 10)] else: checks += [("CRUISE_PARAMS", 50)] - - if CP.carFingerprint in (CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G): + if CP.carFingerprint in (CAR.ACCORD, CAR.ACCORDH, CAR.INSIGHT): + signals += [("DRIVERS_DOOR_OPEN", "SCM_FEEDBACK", 1), + ("LEAD_DISTANCE", "RADAR_HUD", 0)] + elif CP.carFingerprint in (CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.ACURA_RDX_3G): signals += [("DRIVERS_DOOR_OPEN", "SCM_FEEDBACK", 1)] elif CP.carFingerprint == CAR.ODYSSEY_CHN: signals += [("DRIVERS_DOOR_OPEN", "SCM_BUTTONS", 1)] - elif CP.carFingerprint == CAR.HRV: + elif CP.carFingerprint in [CAR.HRV, CAR.JADE]: signals += [("DRIVERS_DOOR_OPEN", "SCM_BUTTONS", 1), ("WHEELS_MOVING", "STANDSTILL", 1)] else: @@ -164,7 +167,7 @@ def get_can_signals(CP, gearbox_msg="GEARBOX"): checks += [ ("GAS_PEDAL_2", 100), ] - elif CP.carFingerprint == CAR.HRV: + elif CP.carFingerprint in [CAR.HRV, CAR.JADE]: signals += [("CAR_GAS", "GAS_PEDAL", 0), ("MAIN_ON", "SCM_BUTTONS", 0), ("BRAKE_HOLD_ACTIVE", "VSA_STATUS", 0)] @@ -213,6 +216,11 @@ class CarState(CarStateBase): self.v_cruise_pcm_prev = 0 self.cruise_mode = 0 + #dp + self.lkMode = True + self.hud_lead = 0 + self.lead_distance = 0. + def update(self, cp, cp_cam, cp_body): ret = car.CarState.new_message() @@ -226,13 +234,17 @@ class CarState(CarStateBase): # ******************* parse out can ******************* # TODO: find wheels moving bit in dbc - if self.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G): + if self.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORDH, CAR.INSIGHT): + ret.standstill = cp.vl["ENGINE_DATA"]["XMISSION_SPEED"] < 0.1 + ret.doorOpen = bool(cp.vl["SCM_FEEDBACK"]["DRIVERS_DOOR_OPEN"]) + self.lead_distance = cp.vl["RADAR_HUD"]["LEAD_DISTANCE"] + elif self.CP.carFingerprint in (CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.ACURA_RDX_3G): ret.standstill = cp.vl["ENGINE_DATA"]["XMISSION_SPEED"] < 0.1 ret.doorOpen = bool(cp.vl["SCM_FEEDBACK"]["DRIVERS_DOOR_OPEN"]) elif self.CP.carFingerprint == CAR.ODYSSEY_CHN: ret.standstill = cp.vl["ENGINE_DATA"]["XMISSION_SPEED"] < 0.1 ret.doorOpen = bool(cp.vl["SCM_BUTTONS"]["DRIVERS_DOOR_OPEN"]) - elif self.CP.carFingerprint == CAR.HRV: + elif self.CP.carFingerprint in [CAR.HRV, CAR.JADE]: ret.doorOpen = bool(cp.vl["SCM_BUTTONS"]["DRIVERS_DOOR_OPEN"]) else: ret.standstill = not cp.vl["STANDSTILL"]["WHEELS_MOVING"] @@ -268,6 +280,14 @@ class CarState(CarStateBase): ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE"] ret.steeringRateDeg = 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"] @@ -291,7 +311,7 @@ class CarState(CarStateBase): self.pedal_gas = cp.vl["POWERTRAIN_DATA"]["PEDAL_GAS"] # crv doesn't include cruise control - if self.CP.carFingerprint in (CAR.CRV, CAR.CRV_EU, CAR.HRV, CAR.ODYSSEY, CAR.ACURA_RDX, CAR.RIDGELINE, CAR.PILOT_2019, CAR.ODYSSEY_CHN): + if self.CP.carFingerprint in (CAR.CRV, CAR.CRV_EU, CAR.HRV, CAR.ODYSSEY, CAR.ACURA_RDX, CAR.RIDGELINE, CAR.PILOT_2019, CAR.ODYSSEY_CHN, CAR.JADE): ret.gas = self.pedal_gas / 256. else: ret.gas = cp.vl["GAS_PEDAL_2"]["CAR_GAS"] / 256. @@ -338,13 +358,19 @@ class CarState(CarStateBase): ret.cruiseState.available = bool(main_on) ret.cruiseState.nonAdaptive = self.cruise_mode != 0 + # afa feature + self.hud_lead = cp.vl["ACC_HUD"]['HUD_LEAD'] + # Gets rid of Pedal Grinding noise when brake is pressed at slow speeds for some models if self.CP.carFingerprint in (CAR.PILOT, CAR.PILOT_2019, CAR.RIDGELINE): if ret.brake > 0.05: ret.brakePressed = True # TODO: discover the CAN msg that has the imperial unit bit for all other cars - self.is_metric = not cp.vl["HUD_SETTING"]["IMPERIAL_UNIT"] if self.CP.carFingerprint in (CAR.CIVIC) else False + if self.CP.carFingerprint in [CAR.JADE]: + self.is_metric = True + else: + self.is_metric = not cp.vl["HUD_SETTING"]["IMPERIAL_UNIT"] if self.CP.carFingerprint in (CAR.CIVIC) else False if self.CP.carFingerprint in HONDA_BOSCH: ret.stockAeb = bool(cp.vl["ACC_CONTROL"]["AEB_STATUS"] and cp.vl["ACC_CONTROL"]["ACCEL_COMMAND"] < -1e-5) diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 65d61a70d..da08b1a44 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -8,6 +8,8 @@ from selfdrive.car.honda.values import CruiseButtons, CAR, HONDA_BOSCH, HONDA_BO from selfdrive.car import STD_CARGO_KG, CivicParams, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.controls.lib.longitudinal_planner import _A_CRUISE_MAX_V_FOLLOWING from selfdrive.car.interfaces import CarInterfaceBase +from common.dp_common import common_interface_atl, common_interface_get_params_lqr +from common.params import Params A_ACC_MAX = max(_A_CRUISE_MAX_V_FOLLOWING) @@ -119,6 +121,7 @@ class CarInterface(CarInterfaceBase): def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[]): # pylint: disable=dangerous-default-value ret = CarInterfaceBase.get_std_params(candidate, fingerprint) ret.carName = "honda" + ret.lateralTuning.init('pid') if candidate in HONDA_BOSCH: ret.safetyModel = car.CarParams.SafetyModel.hondaBoschHarness @@ -403,6 +406,20 @@ class CarInterface(CarInterfaceBase): ret.longitudinalTuning.kiBP = [0., 35.] ret.longitudinalTuning.kiV = [0.18, 0.12] + elif candidate == CAR.JADE: + stop_and_go = False + ret.mass = 1557. + STD_CARGO_KG + ret.wheelbase = 2.76 + ret.centerToFront = ret.wheelbase * 0.41 + ret.steerRatio = 15.2 + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] + tire_stiffness_factor = 0.5 + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16], [0.025]] + ret.longitudinalTuning.kpBP = [0., 5., 35.] + ret.longitudinalTuning.kpV = [1.2, 0.8, 0.5] + ret.longitudinalTuning.kiBP = [0., 35.] + ret.longitudinalTuning.kiV = [0.18, 0.12] + else: raise ValueError("unsupported car %s" % candidate) @@ -413,7 +430,10 @@ class CarInterface(CarInterfaceBase): # min speed to enable ACC. if car can do stop and go, then set enabling speed # to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not # conflict with PCM acc - ret.minEnableSpeed = -1. if (stop_and_go or ret.enableGasInterceptor) else 25.5 * CV.MPH_TO_MS + if candidate in [CAR.JADE]: + ret.minEnableSpeed = 30 * CV.KPH_TO_MS + else: + ret.minEnableSpeed = -1. if (stop_and_go or ret.enableGasInterceptor) else 25.5 * CV.MPH_TO_MS # TODO: get actual value, for now starting with reasonable value for # civic and scaling by mass and wheelbase @@ -436,10 +456,30 @@ class CarInterface(CarInterfaceBase): ret.steerRateCost = 0.5 ret.steerLimitTimer = 0.8 + # dp + if Params().get('dp_honda_eps_mod') == b'1': + if candidate == CAR.CIVIC: + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 8000], [0, 2560, 3840]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.1]] #tuned by Comma + elif candidate in (CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL): + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2564, 8000], [0, 2564, 3840]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.09]] #2.5 default mod #Tuned by TMG + elif candidate in (CAR.ACCORD, CAR.ACCORDH): + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.09]] + elif candidate == CAR.CRV_5G: + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 10000], [0, 2560, 3840]] #tuned by Titanminer (8000) + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.21], [0.07]] + elif candidate == CAR.CRV_HYBRID: + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0x0, 0xB5, 0x161, 0x2D6, 0x4C0, 0x70D, 0xC42, 0x1058, 0x2C00], [0x0, 0x160, 0x1F0, 0x2E0, 0x378, 0x4A0, 0x5F0, 0x804, 0xF00]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.21], [0.07]] #still needs to finish tuning for the new car + ret.lateralTuning.pid.kf = 0.00004 + + ret = common_interface_get_params_lqr(ret) + return ret # returns a car.CarState - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): # ******************* do can recv ******************* self.cp.update_strings(can_strings) self.cp_cam.update_strings(can_strings) @@ -447,7 +487,10 @@ class CarInterface(CarInterfaceBase): self.cp_body.update_strings(can_strings) ret = self.CS.update(self.cp, self.cp_cam, self.cp_body) - + # dp + self.dragonconf = dragonconf + ret.cruiseState.enabled = common_interface_atl(ret, dragonconf.dpAtl) + ret.lkMode = self.CS.lkMode ret.canValid = self.cp.can_valid and self.cp_cam.can_valid and (self.cp_body is None or self.cp_body.can_valid) ret.yawRate = self.VM.yaw_rate(ret.steeringAngleDeg * CV.DEG_TO_RAD, ret.vEgo) @@ -489,6 +532,8 @@ class CarInterface(CarInterfaceBase): # events events = self.create_common_events(ret, pcm_enable=self.CP.enableCruise) + if not self.CS.lkMode or (dragonconf.dpAtl and ret.vEgo <= self.CP.minEnableSpeed): + events.add(EventName.manualSteeringRequired) if self.CS.brake_error: events.add(EventName.brakeUnavailable) if self.CS.brake_hold and self.CS.CP.openpilotLongitudinalControl: @@ -505,8 +550,8 @@ class CarInterface(CarInterfaceBase): and (c.actuators.brake <= 0. or not self.CP.openpilotLongitudinalControl): # non loud alert if cruise disables below 25mph as expected (+ a little margin) if ret.vEgo < self.CP.minEnableSpeed + 2.: - events.add(EventName.speedTooLow) - else: + # events.add(EventName.speedTooLow) + # else: events.add(EventName.cruiseDisabled) if self.CS.CP.minEnableSpeed > 0 and ret.vEgo < 0.001: events.add(EventName.manualRestart) @@ -546,6 +591,7 @@ class CarInterface(CarInterfaceBase): pcm_accel, hud_v_cruise, c.hudControl.lanesVisible, + self.dragonconf, hud_show_car=c.hudControl.leadVisible, hud_alert=c.hudControl.visualAlert) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 79bc28d29..2c0109464 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -54,6 +54,7 @@ class CAR: PILOT_2019 = "HONDA PILOT 2019" RIDGELINE = "HONDA RIDGELINE 2017" INSIGHT = "HONDA INSIGHT 2019" + JADE = "HONDA JADE 2017" # diag message that in some Nidec cars only appear with 1s freq if VIN query is performed DIAG_MSGS = {1600: 5, 1601: 8} @@ -112,6 +113,9 @@ FINGERPRINTS = { { 57: 3, 145: 8, 228: 5, 229: 4, 308: 5, 316: 8, 339: 7, 342: 6, 344: 8, 380: 8, 392: 6, 399: 7, 411: 5, 419: 8, 420: 8, 422: 8, 425: 8, 426: 8, 427: 3, 432: 7, 464: 8, 476: 4, 490: 8, 506: 8, 512: 6, 513: 6, 542: 7, 545: 5, 546: 3, 597: 8, 660: 8, 773: 7, 777: 8, 780: 8, 795: 8, 800: 8, 804: 8, 808: 8, 817: 4, 819: 7, 821: 5, 829: 5, 871: 8, 881: 8, 882: 2, 884: 7, 891: 8, 892: 8, 923: 2, 927: 8, 929: 8, 963: 8, 965: 8, 966: 8, 967: 8, 983: 8, 985: 3, 1027: 5, 1029: 8, 1039: 8, 1064: 7, 1088: 8, 1089: 8, 1092: 1, 1108: 8, 1125: 8, 1296: 8, 1424: 5, 1445: 8, 1600: 5, 1601: 8, 1612: 5, 1613: 5, 1616: 5, 1617: 8, 1618: 5, 1623: 5, 1668: 5 }], + CAR.JADE: [{ + 57: 3, 145: 8, 228: 5, 304: 8, 342: 6, 344: 8, 380: 8, 398: 3, 399: 7, 401: 8, 420: 8, 422: 8, 428: 8, 432: 7, 464: 8, 487: 4, 490: 8, 506: 8, 507: 1, 597: 8, 660: 8, 661: 4, 773: 7, 777: 8, 780: 8, 804: 8, 808: 8, 829: 5, 862: 8, 884: 7, 892: 8, 923: 2, 929: 4, 1057: 5, 1365: 5, 1424: 5, 1600: 5, 1601: 8 + }], } # add DIAG_MSGS to fingerprints @@ -770,6 +774,8 @@ FW_VERSIONS = { b'39990-TPA-G030\x00\x00', b'39990-TPG-A020\x00\x00', b'39990-TMA-H020\x00\x00', + b'39990-TMA,H020\x00\x00', + b'39990,TMA-H020\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TMA-H110\x00\x00', @@ -1248,6 +1254,7 @@ DBC = { CAR.PILOT_2019: dbc_dict('honda_pilot_touring_2017_can_generated', 'acura_ilx_2016_nidec'), CAR.RIDGELINE: dbc_dict('honda_ridgeline_black_edition_2017_can_generated', 'acura_ilx_2016_nidec'), CAR.INSIGHT: dbc_dict('honda_insight_ex_2019_can_generated', None), + CAR.JADE: dbc_dict('honda_hrv_touring_2019_can_generated', 'acura_ilx_2016_nidec'), } STEER_THRESHOLD = { @@ -1271,6 +1278,7 @@ STEER_THRESHOLD = { CAR.PILOT_2019: 1200, CAR.RIDGELINE: 1200, CAR.INSIGHT: 1200, + CAR.JADE: 1200, } SPEED_FACTOR = { @@ -1294,6 +1302,7 @@ SPEED_FACTOR = { CAR.PILOT_2019: 1., CAR.RIDGELINE: 1., CAR.INSIGHT: 1., + CAR.JADE: 1.025, } HONDA_BOSCH = set([CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G]) diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 5f7019fdf..12a3d7e11 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -4,6 +4,8 @@ from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car.hyundai.hyundaican import create_lkas11, create_clu11, create_lfahda_mfc from selfdrive.car.hyundai.values import Buttons, CarControllerParams, CAR from opendbc.can.packer import CANPacker +from common.dp_common import common_controller_ctrl +from common.params import Params VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -34,6 +36,11 @@ def process_hud_alert(enabled, fingerprint, visual_alert, left_lane, class CarController(): def __init__(self, dbc_name, CP, VM): + # dp + self.last_blinker_on = False + self.blinker_end_frame = 0. + self.dp_hkg_smart_mdps = Params().get('dp_hkg_smart_mdps') == b'1' + self.p = CarControllerParams(CP) self.packer = CANPacker(dbc_name) @@ -43,7 +50,7 @@ class CarController(): self.last_resume_frame = 0 def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, - left_lane, right_lane, left_lane_depart, right_lane_depart): + left_lane, right_lane, left_lane_depart, right_lane_depart, dragonconf): # Steering Torque new_steer = int(round(actuators.steer * self.p.STEER_MAX)) apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p) @@ -53,12 +60,24 @@ class CarController(): lkas_active = enabled and not CS.out.steerWarning # fix for Genesis hard fault at low speed - if CS.out.vEgo < 16.7 and self.car_fingerprint == CAR.HYUNDAI_GENESIS: + if not self.dp_hkg_smart_mdps and CS.out.vEgo < 16.7 and self.car_fingerprint == CAR.HYUNDAI_GENESIS: lkas_active = False if not lkas_active: apply_steer = 0 + # dp + blinker_on = CS.out.leftBlinker or CS.out.rightBlinker + if not enabled: + self.blinker_end_frame = 0 + if self.last_blinker_on and not blinker_on: + self.blinker_end_frame = frame + dragonconf.dpSignalOffDelay + apply_steer = common_controller_ctrl(enabled, + dragonconf, + blinker_on or frame < self.blinker_end_frame, + apply_steer, CS.out.vEgo) + self.last_blinker_on = blinker_on + self.apply_steer_last = apply_steer sys_warning, sys_state, left_lane_warning, right_lane_warning = \ diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index c4ff372df..8b55c2e34 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -4,6 +4,8 @@ from selfdrive.config import Conversions as CV from selfdrive.car.hyundai.values import CAR from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase +from common.dp_common import common_interface_atl, common_interface_get_params_lqr +from common.params import Params class CarInterface(CarInterfaceBase): @@ -18,6 +20,7 @@ class CarInterface(CarInterfaceBase): ret.carName = "hyundai" ret.safetyModel = car.CarParams.SafetyModel.hyundai ret.radarOffCan = True + ret.lateralTuning.init('pid') # Most Hyundai car ports are community features for now ret.communityFeature = candidate not in [CAR.SONATA, CAR.PALISADE] @@ -212,6 +215,15 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 16.5 ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16], [0.01]] + ret.lateralTuning.init('indi') + ret.lateralTuning.indi.innerLoopGainV = [3.5] + ret.lateralTuning.indi.innerLoopGainBP = [0.] + ret.lateralTuning.indi.outerLoopGainV = [2.0] + ret.lateralTuning.indi.outerLoopGainBP = [0.] + ret.lateralTuning.indi.timeConstantV = [1.4] + ret.lateralTuning.indi.actuatorEffectivenessV = [2.3] + ret.lateralTuning.indi.actuatorEffectivenessBP = [0.] + ret.minSteerSpeed = 60 * CV.KPH_TO_MS elif candidate == CAR.GENESIS_G90: ret.mass = 2200 ret.wheelbase = 3.15 @@ -239,26 +251,38 @@ class CarInterface(CarInterfaceBase): ret.enableCamera = True ret.enableBsm = 0x58b in fingerprint[0] + # dp + if Params().get('dp_hkg_smart_mdps') == b'1': + ret.minSteerSpeed = 0. + ret = common_interface_get_params_lqr(ret) return ret - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): self.cp.update_strings(can_strings) self.cp_cam.update_strings(can_strings) ret = self.CS.update(self.cp, self.cp_cam) + # dp + self.dragonconf = dragonconf + if ret.vEgo >= self.CP.minSteerSpeed: + ret.cruiseState.enabled = common_interface_atl(ret, dragonconf.dpAtl) ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False events = self.create_common_events(ret) # TODO: addd abs(self.CS.angle_steers) > 90 to 'steerTempUnavailable' event - # low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s) - if ret.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.: - self.low_speed_alert = True - if ret.vEgo > (self.CP.minSteerSpeed + 4.): - self.low_speed_alert = False - if self.low_speed_alert: - events.add(car.CarEvent.EventName.belowSteerSpeed) + if dragonconf.dpAtl: + if ret.vEgo < self.CP.minSteerSpeed: + events.add(car.CarEvent.EventName.belowSteerSpeed) + else: + # low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s) + if ret.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.: + self.low_speed_alert = True + if ret.vEgo > (self.CP.minSteerSpeed + 4.): + self.low_speed_alert = False + if self.low_speed_alert: + events.add(car.CarEvent.EventName.belowSteerSpeed) ret.events = events.to_msg() @@ -268,6 +292,6 @@ class CarInterface(CarInterfaceBase): def apply(self, c): can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert, c.hudControl.leftLaneVisible, - c.hudControl.rightLaneVisible, c.hudControl.leftLaneDepart, c.hudControl.rightLaneDepart) + c.hudControl.rightLaneVisible, c.hudControl.leftLaneDepart, c.hudControl.rightLaneDepart, self.dragonconf) self.frame += 1 return can_sends diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index c69789598..b0e8c34bb 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -3,11 +3,12 @@ from cereal import car from selfdrive.car import dbc_dict Ecu = car.CarParams.Ecu +from common.params import Params # Steer torque limits class CarControllerParams: def __init__(self, CP): - if CP.carFingerprint in [CAR.SONATA, CAR.PALISADE, CAR.SANTA_FE, CAR.VELOSTER, CAR.GENESIS_G70, CAR.IONIQ_EV_2020, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.ELANTRA_2021]: + if Params().get('dp_hkg_smart_mdps') == b'1' or CP.carFingerprint in [CAR.SONATA, CAR.PALISADE, CAR.SANTA_FE, CAR.VELOSTER, CAR.GENESIS_G70, CAR.IONIQ_EV_2020, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.ELANTRA_2021]: self.STEER_MAX = 384 else: self.STEER_MAX = 255 diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index f049434bf..b34797836 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -29,6 +29,8 @@ class CarInterfaceBase(): self.frame = 0 self.low_speed_alert = False + self.dragonconf = None + if CarState is not None: self.CS = CarState(CP) self.cp = self.CS.get_can_parser(CP) @@ -39,6 +41,8 @@ class CarInterfaceBase(): if CarController is not None: self.CC = CarController(self.cp.dbc_name, CP, self.VM) + self.dragonconf = None + @staticmethod def calc_accel_override(a_ego, a_target, v_ego, v_target): return 1. @@ -86,7 +90,7 @@ class CarInterfaceBase(): return ret # returns a car.CarState, pass in car.CarControl - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): raise NotImplementedError # return sendcan, pass in a car.CarControl @@ -100,26 +104,28 @@ class CarInterfaceBase(): events.add(EventName.doorOpen) if cs_out.seatbeltUnlatched: events.add(EventName.seatbeltNotLatched) - if cs_out.gearShifter != GearShifter.drive and cs_out.gearShifter not in extra_gears: + if cs_out.gearShifter != GearShifter.drive and cs_out.gearShifter not in extra_gears and self.dragonconf.dpGearCheck: events.add(EventName.wrongGear) if cs_out.gearShifter == GearShifter.reverse: events.add(EventName.reverseGear) - if not cs_out.cruiseState.available: + if not cs_out.cruiseState.available and not self.dragonconf.dpAtl: events.add(EventName.wrongCarMode) if cs_out.espDisabled: events.add(EventName.espDisabled) - if cs_out.gasPressed: + if cs_out.gasPressed and not self.dragonconf.dpAllowGas: events.add(EventName.gasPressed) if cs_out.stockFcw: events.add(EventName.stockFcw) if cs_out.stockAeb: events.add(EventName.stockAeb) - if cs_out.vEgo > MAX_CTRL_SPEED: + if cs_out.vEgo > MAX_CTRL_SPEED and self.dragonconf.dpSpeedCheck: events.add(EventName.speedTooHigh) - if cs_out.cruiseState.nonAdaptive: + if cs_out.cruiseState.nonAdaptive and not self.dragonconf.dpAtl: events.add(EventName.wrongCruiseMode) - if cs_out.steerError: + if (cs_out.leftBlinker or cs_out.rightBlinker) and self.dragonconf.dpLateralMode == 0: + events.add(EventName.manualSteeringRequiredBlinkersOn) + elif cs_out.steerError: events.add(EventName.steerUnavailable) elif cs_out.steerWarning: if cs_out.steeringPressed: @@ -130,9 +136,15 @@ 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.add(EventName.pedalPressed) + if self.dragonconf.dpAtl: + pass + elif self.dragonconf.dpAllowGas: + if cs_out.brakePressed and (not self.CS.out.brakePressed or not cs_out.standstill): + events.add(EventName.pedalPressed) + else: + 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.add(EventName.pedalPressed) # we engage when pcm is active (rising edge) if pcm_enable: diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 5d9e9c9bb..0eb3ecac9 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -2,14 +2,19 @@ from selfdrive.car.mazda import mazdacan from selfdrive.car.mazda.values import CarControllerParams, Buttons from opendbc.can.packer import CANPacker from selfdrive.car import apply_std_steer_torque_limits +from common.dp_common import common_controller_ctrl class CarController(): def __init__(self, dbc_name, CP, VM): + # dp + self.last_blinker_on = False + self.blinker_end_frame = 0. + self.apply_steer_last = 0 self.packer = CANPacker(dbc_name) self.steer_rate_limited = False - def update(self, enabled, CS, frame, actuators): + def update(self, enabled, CS, frame, actuators, dragonconf): """ Controls thread """ can_sends = [] @@ -36,6 +41,18 @@ class CarController(): # Send at a rate of 5hz until we sync with stock ACC state can_sends.append(mazdacan.create_button_cmd(self.packer, CS.CP.carFingerprint, Buttons.CANCEL)) + # dp + blinker_on = CS.out.leftBlinker or CS.out.rightBlinker + if not enabled: + self.blinker_end_frame = 0 + if self.last_blinker_on and not blinker_on: + self.blinker_end_frame = frame + dragonconf.dpSignalOffDelay + apply_steer = common_controller_ctrl(enabled, + dragonconf, + blinker_on or frame < self.blinker_end_frame, + apply_steer, CS.out.vEgo) + self.last_blinker_on = blinker_on + self.apply_steer_last = apply_steer can_sends.append(mazdacan.create_steering_control(self.packer, CS.CP.carFingerprint, diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index c79ff9b3a..41461eb7c 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -4,6 +4,7 @@ from selfdrive.config import Conversions as CV from selfdrive.car.mazda.values import CAR, LKAS_LIMITS from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase +from common.dp_common import common_interface_atl, common_interface_get_params_lqr ButtonType = car.CarState.ButtonEvent.Type EventName = car.CarEvent.EventName @@ -20,6 +21,7 @@ class CarInterface(CarInterfaceBase): ret.carName = "mazda" ret.safetyModel = car.CarParams.SafetyModel.mazda + ret.lateralTuning.init('pid') ret.dashcamOnly = True @@ -75,15 +77,21 @@ class CarInterface(CarInterfaceBase): ret.enableCamera = True + # dp + ret = common_interface_get_params_lqr(ret) + return ret # returns a car.CarState - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): self.cp.update_strings(can_strings) self.cp_cam.update_strings(can_strings) ret = self.CS.update(self.cp, self.cp_cam) + # dp + self.dragonconf = dragonconf + ret.cruiseState.enabled = common_interface_atl(ret, dragonconf.dpAtl) ret.canValid = self.cp.can_valid and self.cp_cam.can_valid # events @@ -101,6 +109,6 @@ class CarInterface(CarInterfaceBase): return self.CS.out def apply(self, c): - can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators) + can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators, self.dragonconf) self.frame += 1 return can_sends diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py index 604851cb9..4ec7c7d6a 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -49,7 +49,7 @@ class CarInterface(CarInterfaceBase): return ret # returns a car.CarState - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): # 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/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py index 8f763f358..253cd4d0c 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -3,13 +3,17 @@ from common.numpy_fast import clip, interp from selfdrive.car.nissan import nissancan from opendbc.can.packer import CANPacker from selfdrive.car.nissan.values import CAR, CarControllerParams - +from common.dp_common import common_controller_ctrl VisualAlert = car.CarControl.HUDControl.VisualAlert class CarController(): def __init__(self, dbc_name, CP, VM): + # dp + self.last_blinker_on = False + self.blinker_end_frame = 0. + self.CP = CP self.car_fingerprint = CP.carFingerprint @@ -19,7 +23,7 @@ class CarController(): self.packer = CANPacker(dbc_name) def update(self, enabled, CS, frame, actuators, cruise_cancel, hud_alert, - left_line, right_line, left_lane_depart, right_lane_depart): + left_line, right_line, left_lane_depart, right_lane_depart, dragonconf): """ Controls thread """ # Send CAN commands. @@ -58,6 +62,18 @@ class CarController(): apply_angle = CS.out.steeringAngleDeg self.lkas_max_torque = 0 + # dp + blinker_on = CS.out.leftBlinker or CS.out.rightBlinker + if not enabled: + self.blinker_end_frame = 0 + if self.last_blinker_on and not blinker_on: + self.blinker_end_frame = frame + dragonconf.dpSignalOffDelay + apply_angle = common_controller_ctrl(enabled, + dragonconf, + blinker_on or frame < self.blinker_end_frame, + apply_angle, CS.out.vEgo) + self.last_blinker_on = blinker_on + self.last_angle = apply_angle if not enabled and acc_active: diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index 30f4e94f9..3b1a354e4 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -3,6 +3,7 @@ from cereal import car from selfdrive.car.nissan.values import CAR from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase +from common.dp_common import common_interface_atl, common_interface_get_params_lqr class CarInterface(CarInterfaceBase): def __init__(self, CP, CarController, CarState): @@ -19,6 +20,7 @@ class CarInterface(CarInterfaceBase): ret = CarInterfaceBase.get_std_params(candidate, fingerprint) ret.carName = "nissan" ret.safetyModel = car.CarParams.SafetyModel.nissan + ret.lateralTuning.init('pid') # Nissan port is a community feature, since we don't own one to test ret.communityFeature = True @@ -58,16 +60,21 @@ class CarInterface(CarInterfaceBase): # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) + # dp + ret = common_interface_get_params_lqr(ret) + return ret # returns a car.CarState - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): self.cp.update_strings(can_strings) self.cp_cam.update_strings(can_strings) self.cp_adas.update_strings(can_strings) ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam) - + # dp + self.dragonconf = dragonconf + ret.cruiseState.enabled = common_interface_atl(ret, dragonconf.dpAtl) ret.canValid = self.cp.can_valid and self.cp_adas.can_valid and self.cp_cam.can_valid buttonEvents = [] @@ -89,6 +96,6 @@ class CarInterface(CarInterfaceBase): can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert, c.hudControl.leftLaneVisible, c.hudControl.rightLaneVisible, - c.hudControl.leftLaneDepart, c.hudControl.rightLaneDepart) + c.hudControl.leftLaneDepart, c.hudControl.rightLaneDepart, self.dragonconf) self.frame += 1 return can_sends diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index 8ec957a65..0e750b465 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -2,10 +2,14 @@ from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car.subaru import subarucan from selfdrive.car.subaru.values import DBC, PREGLOBAL_CARS, CarControllerParams from opendbc.can.packer import CANPacker - +from common.dp_common import common_controller_ctrl class CarController(): def __init__(self, dbc_name, CP, VM): + # dp + self.last_blinker_on = False + self.blinker_end_frame = 0. + self.apply_steer_last = 0 self.es_distance_cnt = -1 self.es_accel_cnt = -1 @@ -15,7 +19,7 @@ class CarController(): self.packer = CANPacker(DBC[CP.carFingerprint]['pt']) - def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, left_line, right_line): + def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, left_line, right_line, dragonconf): can_sends = [] @@ -33,6 +37,18 @@ class CarController(): if not enabled: apply_steer = 0 + # dp + blinker_on = CS.out.leftBlinker or CS.out.rightBlinker + if not enabled: + self.blinker_end_frame = 0 + if self.last_blinker_on and not blinker_on: + self.blinker_end_frame = frame + dragonconf.dpSignalOffDelay + apply_steer = common_controller_ctrl(enabled, + dragonconf, + blinker_on or frame < self.blinker_end_frame, + apply_steer, CS.out.vEgo) + self.last_blinker_on = blinker_on + if CS.CP.carFingerprint in PREGLOBAL_CARS: can_sends.append(subarucan.create_preglobal_steering_control(self.packer, apply_steer, frame, CarControllerParams.STEER_STEP)) else: diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index bb8669fb1..a0696c2f9 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -3,6 +3,7 @@ from cereal import car from selfdrive.car.subaru.values import CAR, PREGLOBAL_CARS from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase +from common.dp_common import common_interface_atl, common_interface_get_params_lqr class CarInterface(CarInterfaceBase): @@ -16,6 +17,7 @@ class CarInterface(CarInterfaceBase): ret.carName = "subaru" ret.radarOffCan = True + ret.lateralTuning.init('pid') if candidate in PREGLOBAL_CARS: ret.safetyModel = car.CarParams.SafetyModel.subaruLegacy @@ -102,15 +104,20 @@ class CarInterface(CarInterfaceBase): # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) + # dp + ret = common_interface_get_params_lqr(ret) + return ret # returns a car.CarState - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): self.cp.update_strings(can_strings) self.cp_cam.update_strings(can_strings) ret = self.CS.update(self.cp, self.cp_cam) - + # dp + self.dragonconf = dragonconf + ret.cruiseState.enabled = common_interface_atl(ret, dragonconf.dpAtl) ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False @@ -122,6 +129,6 @@ class CarInterface(CarInterfaceBase): def apply(self, c): can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert, - c.hudControl.leftLaneVisible, c.hudControl.rightLaneVisible) + c.hudControl.leftLaneVisible, c.hudControl.rightLaneVisible, self.dragonconf) self.frame += 1 return can_sends diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 9b3ff060d..94c73401f 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -54,6 +54,10 @@ FINGERPRINTS = { CAR.OUTBACK_PREGLOBAL_2018: [{ # OUTBACK LIMITED 3.6R 2019 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 644: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 886: 2, 977: 8, 1614: 8, 1632: 8, 1657: 8, 1658: 8, 1672: 8, 1736: 8, 1743: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 1862: 8, 1870: 8, 1920: 8, 1927: 8, 1928: 8, 1935: 8, 1968: 8, 1976: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 + }, + # OUTBACK 2.5i-ES 2019 - Taiwan + { + 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 346: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 644: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 886: 2, 977: 8, 1614: 8, 1632: 8, 1640: 8, 1657: 8, 1658: 8, 1672: 8, 1722: 8, 1736: 8, 1745: 8, 1786: 5, 1787: 5 }], CAR.FORESTER_PREGLOBAL: [{ # FORESTER PREMIUM 2.5i 2017 diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 1bc18efb7..c046ed62a 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -7,6 +7,7 @@ from selfdrive.car.toyota.toyotacan import create_steer_command, create_ui_comma from selfdrive.car.toyota.values import Ecu, CAR, STATIC_MSGS, NO_STOP_TIMER_CAR, TSS2_CAR, \ MIN_ACC_SPEED, PEDAL_HYST_GAP, CarControllerParams from opendbc.can.packer import CANPacker +from common.dp_common import common_controller_ctrl VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -28,6 +29,10 @@ def accel_hysteresis(accel, accel_steady, enabled): class CarController(): def __init__(self, dbc_name, CP, VM): + # dp + self.last_blinker_on = False + self.blinker_end_frame = 0. + self.last_steer = 0 self.accel_steady = 0. self.alert_active = False @@ -45,7 +50,7 @@ class CarController(): self.packer = CANPacker(dbc_name) def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, hud_alert, - left_line, right_line, lead, left_lane_depart, right_lane_depart): + left_line, right_line, lead, left_lane_depart, right_lane_depart, dragonconf): # *** compute control surfaces *** @@ -75,7 +80,7 @@ class CarController(): self.steer_rate_limited = new_steer != apply_steer # Cut steering while we're in a known fault state (2s) - if not enabled or CS.steer_state in [9, 25]: + if not enabled or CS.steer_state in [9, 25] or abs(CS.out.steeringRateDeg) > 100 or (abs(CS.out.steeringAngleDeg) > 150 and CS.CP.carFingerprint in [CAR.RAV4H, CAR.PRIUS]): apply_steer = 0 apply_steer_req = 0 else: @@ -86,12 +91,24 @@ class CarController(): pcm_cancel_cmd = 1 # on entering standstill, send standstill request - if CS.out.standstill and not self.last_standstill and CS.CP.carFingerprint not in NO_STOP_TIMER_CAR: + if not dragonconf.dpToyotaSng and CS.out.standstill and not self.last_standstill and CS.CP.carFingerprint not in NO_STOP_TIMER_CAR: self.standstill_req = True if CS.pcm_acc_status != 8: # pcm entered standstill or it's disabled self.standstill_req = False + # dp + blinker_on = CS.out.leftBlinker or CS.out.rightBlinker + if not enabled: + self.blinker_end_frame = 0 + if self.last_blinker_on and not blinker_on: + self.blinker_end_frame = frame + dragonconf.dpSignalOffDelay + apply_steer = common_controller_ctrl(enabled, + dragonconf, + blinker_on or frame < self.blinker_end_frame, + apply_steer, CS.out.vEgo) + self.last_blinker_on = blinker_on + self.last_steer = apply_steer self.last_accel = pcm_accel_cmd self.last_standstill = CS.out.standstill @@ -119,7 +136,9 @@ 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 dragonconf.dpAtl: + pass + elif pcm_cancel_cmd and CS.CP.carFingerprint == CAR.LEXUS_IS: can_sends.append(create_acc_cancel_command(self.packer)) elif CS.CP.openpilotLongitudinalControl: can_sends.append(create_accel_command(self.packer, pcm_accel_cmd, pcm_cancel_cmd, self.standstill_req, lead)) @@ -146,6 +165,11 @@ class CarController(): # forcing the pcm to disengage causes a bad fault sound so play a good sound instead send_ui = True + # dp + if not dragonconf.dpToyotaLdw: + left_lane_depart = False + 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)) diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 1f5cae59f..1aa45d361 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -5,7 +5,7 @@ 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, NO_STOP_TIMER_CAR - +from common.params import Params class CarState(CarStateBase): def __init__(self, CP): @@ -19,6 +19,8 @@ class CarState(CarStateBase): self.needs_angle_offset = True self.accurate_steer_angle_seen = False self.angle_offset = 0. + # dp + self.dp_toyota_zss = Params().get('dp_toyota_zss') == b'1' def update(self, cp, cp_cam): ret = car.CarState.new_message() @@ -45,11 +47,14 @@ class CarState(CarStateBase): ret.standstill = ret.vEgoRaw < 0.001 # Some newer models have a more accurate angle measurement in the TORQUE_SENSOR message. Use if non-zero - if abs(cp.vl["STEER_TORQUE_SENSOR"]["STEER_ANGLE"]) > 1e-3: + if self.dp_toyota_zss or abs(cp.vl["STEER_TORQUE_SENSOR"]["STEER_ANGLE"]) > 1e-3: self.accurate_steer_angle_seen = True if self.accurate_steer_angle_seen: - ret.steeringAngleDeg = cp.vl["STEER_TORQUE_SENSOR"]["STEER_ANGLE"] - self.angle_offset + if self.dp_toyota_zss: + ret.steeringAngleDeg = cp.vl["SECONDARY_STEER_ANGLE"]["ZORRO_STEER"] - self.angle_offset + else: + ret.steeringAngleDeg = cp.vl["STEER_TORQUE_SENSOR"]["STEER_ANGLE"] - self.angle_offset if self.needs_angle_offset: angle_wheel = cp.vl["STEER_ANGLE_SENSOR"]["STEER_ANGLE"] + cp.vl["STEER_ANGLE_SENSOR"]["STEER_FRACTION"] if abs(angle_wheel) > 1e-3: @@ -176,6 +181,9 @@ class CarState(CarStateBase): ("BSM", 1) ] + if Params().get('dp_toyota_zss') == b'1': + signals += [("ZORRO_STEER", "SECONDARY_STEER_ANGLE", 0)] + 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 6408ad01a..80bb3c5b2 100755 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -5,11 +5,19 @@ from selfdrive.car.toyota.values import Ecu, CAR, TSS2_CAR, NO_DSU_CAR, MIN_ACC_ from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.swaglog import cloudlog from selfdrive.car.interfaces import CarInterfaceBase +from common.dp_common import common_interface_atl, common_interface_get_params_lqr +from common.params import Params EventName = car.CarEvent.EventName class CarInterface(CarInterfaceBase): + def __init__(self, CP, CarController, CarState): + super().__init__(CP, CarController, CarState) + + # dp + self.dp_cruise_speed = 0. + @staticmethod def compute_gb(accel, speed): return float(accel) / CarControllerParams.ACCEL_SCALE @@ -54,6 +62,9 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 16.88 # 14.5 is spec end-to-end tire_stiffness_factor = 0.5533 ret.mass = 3650. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid + if ret.enableGasInterceptor: + ret.longitudinalTuning.kpV = [0.4, 0.36, 0.325] # arne's tune. + ret.longitudinalTuning.kiV = [0.195, 0.10] ret.lateralTuning.init('lqr') ret.lateralTuning.lqr.scale = 1500.0 @@ -349,15 +360,36 @@ class CarInterface(CarInterfaceBase): ret.longitudinalTuning.kpV = [3.6, 2.4, 1.5] ret.longitudinalTuning.kiV = [0.54, 0.36] + # dp + ret = common_interface_get_params_lqr(ret) + if candidate == CAR.PRIUS and Params().get('dp_toyota_zss') == b'1': + ret.mass = 3370. * CV.LB_TO_KG + STD_CARGO_KG + ret.lateralTuning.indi.timeConstantV = [0.1] + ret.lateralTuning.indi.timeConstantBP = [0.] + ret.steerRateCost = 0.5 + return ret # returns a car.CarState - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): # ******************* do can recv ******************* self.cp.update_strings(can_strings) self.cp_cam.update_strings(can_strings) ret = self.CS.update(self.cp, self.cp_cam) + # dp + self.dragonconf = dragonconf + ret.cruiseState.enabled = common_interface_atl(ret, dragonconf.dpAtl) + # if ret.cruiseState.enabled and dragonconf.dpToyotaLowestCruiseOverride and ret.cruiseState.speed < dragonconf.dpToyotaLowestCruiseOverrideAt * CV.KPH_TO_MS: + # if dragonconf.dpToyotaLowestCruiseOverrideVego: + # if self.dp_cruise_speed == 0.: + # ret.cruiseState.speed = self.dp_cruise_speed = max( dragonconf.dpToyotaLowestCruiseOverrideSpeed * CV.KPH_TO_MS,ret.vEgo) + # else: + # ret.cruiseState.speed = self.dp_cruise_speed + # else: + # ret.cruiseState.speed = dragonconf.dpToyotaLowestCruiseOverrideSpeed * CV.KPH_TO_MS + # else: + # self.dp_cruise_speed = 0. ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False @@ -389,7 +421,7 @@ class CarInterface(CarInterfaceBase): c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert, c.hudControl.leftLaneVisible, c.hudControl.rightLaneVisible, c.hudControl.leadVisible, - c.hudControl.leftLaneDepart, c.hudControl.rightLaneDepart) + c.hudControl.leftLaneDepart, c.hudControl.rightLaneDepart, self.dragonconf) self.frame += 1 return can_sends diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 080b70f61..20ee8e553 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -10,8 +10,8 @@ PEDAL_HYST_GAP = 3. * CV.MPH_TO_MS class CarControllerParams: 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 # 1.5 m/s2 + ACCEL_MIN = -3.5 # 3 m/s2 ACCEL_SCALE = max(ACCEL_MAX, -ACCEL_MIN) STEER_MAX = 1500 @@ -93,31 +93,43 @@ FINGERPRINTS = { 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 512: 6, 513: 6, 547: 8, 548: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 830: 7, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 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, 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, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1207: 8, 1227: 8, 1235: 8, 1263: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 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, 1596: 8, 1597: 8, 1600: 8, 1664: 8, 1728: 8, 1745: 8, 1779: 8 }], 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 + 35: 8, 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 }, #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 + 35: 8, 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 }, # 2020 Prius Prime 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, 643: 7, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 767: 4, 800: 8, 810: 2, 824: 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, 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, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 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, 1227: 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, 1595: 8, 1649: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 35: 8, 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, 643: 7, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 767: 4, 800: 8, 810: 2, 824: 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, 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, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 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, 1227: 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, 1595: 8, 1649: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, #2020 Prius Prime Limited { - 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, 824: 2, 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, 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, 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, 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, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2024: 8, 2026: 8, 2027: 8, 2029: 8, 2030: 8, 2031: 8 + 35: 8, 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, 824: 2, 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, 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, 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, 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, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2024: 8, 2026: 8, 2027: 8, 2029: 8, 2030: 8, 2031: 8 }, #2020 Central Europe Prime { - 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, 643: 7, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 767: 4, 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: 8, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 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, 1227: 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, 1592: 8, 1595: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8 + 35: 8, 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, 643: 7, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 767: 4, 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: 8, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 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, 1227: 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, 1592: 8, 1595: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8 }, #2017 German Prius { - 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, 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, 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, 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, 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, 1792: 8, 1767: 4, 1863: 8, 1904: 8, 1912: 8, 1984: 8, 1988: 8, 1990: 8, 1992: 8, 1996: 8, 1998: 8, 2002: 8, 2010: 8, 2015: 8, 2016: 8, 2018: 8, 2024: 8, 2026: 8, 2030: 8 + 35: 8, 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, 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, 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, 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, 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, 1792: 8, 1767: 4, 1863: 8, 1904: 8, 1912: 8, 1984: 8, 1988: 8, 1990: 8, 1992: 8, 1996: 8, 1998: 8, 2002: 8, 2010: 8, 2015: 8, 2016: 8, 2018: 8, 2024: 8, 2026: 8, 2030: 8 + }, + # Taiwan 2020 Prius 4.5 + { + 35: 8, 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, 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, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1593: 8, 1595: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8 + }, + # Taiwan Prius 4.5 + { + 35: 8, 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 }], #Corolla w/ added Pedal Support (512L and 513L) CAR.COROLLA: [{ 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 512: 6, 513: 6, 547: 8, 548: 8, 552: 4, 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, 900: 6, 902: 6, 905: 8, 911: 8, 916: 2, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 4, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1196: 8, 1227: 8, 1235: 8, 1279: 8, 1552: 8, 1553: 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, 1596: 8, 1597: 8, 1600: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2021: 8, 2022: 8, 2023: 8, 2024: 8 + }, + #2015 Corolla w/ select 2017 ECU's + { + 32: 4, 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 456: 8, 464: 8, 466: 8, 467: 8, 513: 6, 547: 8, 548: 8, 552: 4, 608: 8, 610: 5, 611: 7, 705: 8, 740: 5, 800: 8, 849: 4, 852: 1, 865: 8, 871: 2, 896: 8, 897: 8, 898: 8, 899: 8, 900: 6, 902: 6, 903: 8, 905: 8, 906: 5, 910: 8, 911: 8, 916: 2, 921: 8, 928: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 4, 956: 8, 976: 1, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1024: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1078: 8, 1079: 8, 1088: 8, 1090: 8, 1091: 8, 1161: 8, 1162: 8, 1163: 8, 1196: 8, 1217: 8, 1219: 8, 1222: 8, 1224: 8, 1235: 8, 1244: 8, 1245: 8, 1279: 8, 1552: 8, 1553: 8, 1555: 8, 1556: 8, 1557: 8, 1560: 8, 1561: 8, 1562: 8, 1564: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1574: 8, 1592: 8, 1596: 8, 1597: 8, 1600: 8, 1664: 8, 1761: 8, 1762: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 643: 7 }], CAR.LEXUS_RXH: [{ 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: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 810: 2, 812: 3, 814: 8, 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, 975: 6, 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, 1059: 1, 1063: 8, 1071: 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, 1264: 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, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1840: 8, 1848: 8, 1904: 8, 1912: 8, 1940: 8, 1941: 8, 1948: 8, 1949: 8, 1952: 8, 1956: 8, 1960: 8, 1964: 8, 1986: 8, 1990: 8, 1994: 8, 1998: 8, 2004: 8, 2012: 8 @@ -148,6 +160,10 @@ FINGERPRINTS = { { # 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 + }, + # 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 }], CAR.CAMRYH: [ #SE, LE and LE with Blindspot Monitor @@ -176,6 +192,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.HIGHLANDERH: [{ 36: 8, 37: 8, 170: 8, 180: 8, 296: 8, 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, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 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, 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, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 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, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 @@ -195,6 +215,10 @@ FINGERPRINTS = { # XLE, Limited, and AWD { 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 + }, + # 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 }], CAR.COROLLAH_TSS2: [ # 2019 Taiwan Altis Hybrid @@ -204,6 +228,10 @@ FINGERPRINTS = { # 2019 Chinese Levin 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, 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, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 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, 1600: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8 + }, + # 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 } ], CAR.SIENNA: [ @@ -213,8 +241,16 @@ FINGERPRINTS = { # XLE AWD 2018 { 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 + }, + { + # Canada 2018 Sienna LTD + 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, 800: 8, 818: 8, 822: 8, 824: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 891: 8, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 1, 918: 7, 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, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 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, 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 @@ -225,6 +261,10 @@ FINGERPRINTS = { }], CAR.LEXUS_CTH: [{ 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 + }, + # 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 }], } diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 503583f66..1b04d044d 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -1,12 +1,16 @@ from cereal import car from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car.volkswagen import volkswagencan -from selfdrive.car.volkswagen.values import DBC, CANBUS, MQB_LDW_MESSAGES, BUTTON_STATES, CarControllerParams +from selfdrive.car.volkswagen.values import DBC, CANBUS, MQB_LDW_MESSAGES, BUTTON_STATES, CarControllerParams, NetworkLocation from opendbc.can.packer import CANPacker - +from common.dp_common import common_controller_ctrl class CarController(): def __init__(self, dbc_name, CP, VM): + # dp + self.last_blinker_on = False + self.blinker_end_frame = 0. + self.apply_steer_last = 0 self.packer_pt = CANPacker(DBC[CP.carFingerprint]['pt']) @@ -17,10 +21,15 @@ class CarController(): self.graMsgSentCount = 0 self.graMsgStartFramePrev = 0 self.graMsgBusCounterPrev = 0 + + if CP.networkLocation == NetworkLocation.fwdCamera: + self.ext_can = CANBUS.pt + else: + self.ext_can = CANBUS.cam self.steer_rate_limited = False - def update(self, enabled, CS, frame, actuators, visual_alert, left_lane_visible, right_lane_visible, left_lane_depart, right_lane_depart): + def update(self, enabled, CS, frame, actuators, visual_alert, left_lane_visible, right_lane_visible, left_lane_depart, right_lane_depart, dragonconf): """ Controls thread """ P = CarControllerParams @@ -94,6 +103,20 @@ class CarController(): hcaEnabled = False apply_steer = 0 + # dp + if CS.out.stopSteering: + apply_steer = 0 + blinker_on = CS.out.leftBlinker or CS.out.rightBlinker + if not enabled: + self.blinker_end_frame = 0 + if self.last_blinker_on and not blinker_on: + self.blinker_end_frame = frame + dragonconf.dpSignalOffDelay + apply_steer = common_controller_ctrl(enabled, + dragonconf, + blinker_on or frame < self.blinker_end_frame, + apply_steer, CS.out.vEgo) + self.last_blinker_on = blinker_on + self.apply_steer_last = apply_steer idx = (frame / P.HCA_STEP) % 16 can_sends.append(volkswagencan.create_mqb_steering_control(self.packer_pt, CANBUS.pt, apply_steer, @@ -178,7 +201,7 @@ class CarController(): if self.graMsgSentCount == 0: self.graMsgStartFramePrev = frame idx = (CS.graMsgBusCounter + 1) % 16 - can_sends.append(volkswagencan.create_mqb_acc_buttons_control(self.packer_pt, CANBUS.pt, self.graButtonStatesToSend, CS, idx)) + can_sends.append(volkswagencan.create_mqb_acc_buttons_control(self.packer_pt, self.ext_can, self.graButtonStatesToSend, CS, idx)) self.graMsgSentCount += 1 if self.graMsgSentCount >= P.GRA_VBP_COUNT: self.graButtonStatesToSend = None diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index 833cae6f7..d9508b90c 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -4,7 +4,7 @@ from selfdrive.config import Conversions as CV from selfdrive.car.interfaces import CarStateBase from opendbc.can.parser import CANParser from opendbc.can.can_define import CANDefine -from selfdrive.car.volkswagen.values import DBC, CANBUS, TransmissionType, GearShifter, BUTTON_STATES, CarControllerParams +from selfdrive.car.volkswagen.values import DBC, CANBUS, TransmissionType, GearShifter, BUTTON_STATES, CarControllerParams, NetworkLocation class CarState(CarStateBase): def __init__(self, CP): @@ -17,7 +17,7 @@ class CarState(CarStateBase): self.hca_status_values = can_define.dv["LH_EPS_03"]["EPS_HCA_Status"] self.buttonStates = BUTTON_STATES.copy() - def update(self, pt_cp, cam_cp, trans_type): + def update(self, pt_cp, cam_cp, ext_cp, trans_type): ret = car.CarState.new_message() # Update vehicle speed and acceleration from ABS wheel speeds. ret.wheelSpeeds.fl = pt_cp.vl["ESP_19"]["ESP_VL_Radgeschw_02"] * CV.KPH_TO_MS @@ -27,8 +27,8 @@ class CarState(CarStateBase): ret.vEgoRaw = float(np.mean([ret.wheelSpeeds.fl, ret.wheelSpeeds.fr, ret.wheelSpeeds.rl, ret.wheelSpeeds.rr])) ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) - - ret.standstill = ret.vEgoRaw < 0.1 + #Fix stop and go acc self-resume +1 + ret.standstill = bool(pt_cp.vl["ESP_21"]["ESP_Haltebestaetigung"]) and ret.vEgoRaw < 0.01 # Update steering angle, rate, yaw rate, and driver input torque. VW send # the sign/direction in a separate signal so they must be recombined. @@ -86,8 +86,8 @@ class CarState(CarStateBase): # Refer to VW Self Study Program 890253: Volkswagen Driver Assist Systems, # pages 32-35. if self.CP.enableBsm: - ret.leftBlindspot = bool(pt_cp.vl["SWA_01"]["SWA_Infostufe_SWA_li"]) or bool(pt_cp.vl["SWA_01"]["SWA_Warnung_SWA_li"]) - ret.rightBlindspot = bool(pt_cp.vl["SWA_01"]["SWA_Infostufe_SWA_re"]) or bool(pt_cp.vl["SWA_01"]["SWA_Warnung_SWA_re"]) + ret.leftBlindspot = bool(ext_cp.vl["SWA_01"]["SWA_Infostufe_SWA_li"]) or bool(ext_cp.vl["SWA_01"]["SWA_Warnung_SWA_li"]) + ret.rightBlindspot = bool(ext_cp.vl["SWA_01"]["SWA_Infostufe_SWA_re"]) or bool(ext_cp.vl["SWA_01"]["SWA_Warnung_SWA_re"]) # Consume factory LDW data relevant for factory SWA (Lane Change Assist) # and capture it for forwarding to the blind spot radar controller @@ -102,8 +102,8 @@ class CarState(CarStateBase): # braking release bits are set. # Refer to VW Self Study Program 890253: Volkswagen Driver Assistance # Systems, chapter on Front Assist with Braking: Golf Family for all MQB - ret.stockFcw = bool(pt_cp.vl["ACC_10"]["AWV2_Freigabe"]) - ret.stockAeb = bool(pt_cp.vl["ACC_10"]["ANB_Teilbremsung_Freigabe"]) or bool(pt_cp.vl["ACC_10"]["ANB_Zielbremsung_Freigabe"]) + ret.stockFcw = bool(ext_cp.vl["ACC_10"]["AWV2_Freigabe"]) + ret.stockAeb = bool(ext_cp.vl["ACC_10"]["ANB_Teilbremsung_Freigabe"]) or bool(ext_cp.vl["ACC_10"]["ANB_Zielbremsung_Freigabe"]) # Update ACC radar status. accStatus = pt_cp.vl["TSK_06"]["TSK_Status"] @@ -122,7 +122,7 @@ class CarState(CarStateBase): # Update ACC setpoint. When the setpoint is zero or there's an error, the # radar sends a set-speed of ~90.69 m/s / 203mph. - ret.cruiseState.speed = pt_cp.vl["ACC_02"]["ACC_Wunschgeschw"] * CV.KPH_TO_MS + ret.cruiseState.speed = ext_cp.vl["ACC_02"]['ACC_Wunschgeschw'] * CV.KPH_TO_MS if ret.cruiseState.speed > 90: ret.cruiseState.speed = 0 @@ -185,6 +185,7 @@ class CarState(CarStateBase): ("EPS_VZ_Lenkmoment", "LH_EPS_03", 0), # Driver torque input sign ("EPS_HCA_Status", "LH_EPS_03", 3), # EPS HCA control status ("ESP_Tastung_passiv", "ESP_21", 0), # Stability control disabled + ("ESP_Haltebestaetigung", "ESP_21", 0), # prevents set point creep ("KBI_MFA_v_Einheit_02", "Einheiten_01", 0), # MPH vs KMH speed display ("KBI_Handbremse", "Kombi_01", 0), # Manual handbrake applied ("TSK_Status", "TSK_06", 0), # ACC engagement status from drivetrain coordinator @@ -230,10 +231,10 @@ class CarState(CarStateBase): ("BCM1_Rueckfahrlicht_Schalter", "Gateway_72", 0)] # Reverse light from BCM checks += [("Motor_14", 10)] # From J623 Engine control module - # TODO: Detect ACC radar bus location - signals += MqbExtraSignals.fwd_radar_signals - checks += MqbExtraSignals.fwd_radar_checks - # TODO: Detect BSM radar bus location + if CP.networkLocation == NetworkLocation.fwdCamera: + # Extended CAN devices other than the camera are here on CANBUS.pt + signals += MqbExtraSignals.fwd_radar_signals + checks += MqbExtraSignals.fwd_radar_checks if CP.enableBsm: signals += MqbExtraSignals.bsm_radar_signals checks += MqbExtraSignals.bsm_radar_checks @@ -257,7 +258,16 @@ class CarState(CarStateBase): ("LDW_02", 10) # From R242 Driver assistance camera ] - return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, CANBUS.cam) + if CP.networkLocation == NetworkLocation.gateway: + # Extended CAN devices other than the camera are here on CANBUS.cam + signals += MqbExtraSignals.fwd_radar_signals + checks += MqbExtraSignals.fwd_radar_checks + if CP.enableBsm: + signals += MqbExtraSignals.bsm_radar_signals + checks += MqbExtraSignals.bsm_radar_checks + + # TODO: Re-enable checks enforcement with CP.enableStockCamera + return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, CANBUS.cam, enforce_checks=False) class MqbExtraSignals: # Additional signal and message lists for optional or bus-portable controllers diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 55401af0f..52c823fb0 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -1,8 +1,9 @@ from cereal import car from selfdrive.swaglog import cloudlog -from selfdrive.car.volkswagen.values import CAR, BUTTON_STATES, TransmissionType, GearShifter +from selfdrive.car.volkswagen.values import CAR, BUTTON_STATES, TransmissionType, GearShifter, NetworkLocation from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase +from common.dp_common import common_interface_atl, common_interface_get_params_lqr EventName = car.CarEvent.EventName @@ -13,6 +14,15 @@ class CarInterface(CarInterfaceBase): self.displayMetricUnitsPrev = None self.buttonStatesPrev = BUTTON_STATES.copy() + + # timebomb_counter mod + self.cruise_enabled_prev = False + self.timebomb_counter = 0 + self.wheel_grabbed = False + self.timebomb_bypass_counter = 0 + + # Alias Extended CAN parser to PT/CAM parser, based on detected network location + self.cp_ext = self.cp if CP.networkLocation == NetworkLocation.fwdCamera else self.cp_cam @staticmethod def compute_gb(accel, speed): @@ -43,6 +53,12 @@ class CarInterface(CarInterfaceBase): ret.transmissionType = TransmissionType.manual cloudlog.info("Detected transmission type: %s", ret.transmissionType) + if 0xfd in fingerprint[1]: # ESP_21 present on bus 1, we're hooked up at the CAN gateway + ret.networkLocation = NetworkLocation.gateway + else: # We're hooked up at the LKAS camera + ret.networkLocation = NetworkLocation.fwdCamera + cloudlog.info("Detected network location: %s", ret.networkLocation) + # Global tuning defaults, can be overridden per-vehicle ret.steerRateCost = 1.0 @@ -135,11 +151,13 @@ class CarInterface(CarInterfaceBase): # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, tire_stiffness_factor=tire_stiffness_factor) + # dp + ret = common_interface_get_params_lqr(ret) return ret # returns a car.CarState - def update(self, c, can_strings): + def update(self, c, can_strings, dragonconf): buttonEvents = [] # Process the most recent CAN message traffic, and check for validity @@ -148,7 +166,10 @@ class CarInterface(CarInterfaceBase): self.cp.update_strings(can_strings) self.cp_cam.update_strings(can_strings) - ret = self.CS.update(self.cp, self.cp_cam, self.CP.transmissionType) + ret = self.CS.update(self.cp, self.cp_cam, self.cp_ext, self.CP.transmissionType) + # dp + self.dragonconf = dragonconf + ret.cruiseState.enabled = common_interface_atl(ret, dragonconf.dpAtl) ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False @@ -173,10 +194,42 @@ class CarInterface(CarInterfaceBase): if self.CS.parkingBrakeSet: events.add(EventName.parkBrake) + # Engagement and longitudinal control using stock ACC. Make sure OP is + # disengaged if stock ACC is disengaged. + if not ret.cruiseState.enabled: + events.add(EventName.pcmDisable) + # Attempt OP engagement only on rising edge of stock ACC engagement. + elif not self.cruise_enabled_prev: + events.add(EventName.pcmEnable) + + if dragonconf.dpVwTimebombAssist: + ret.stopSteering = False + if ret.cruiseState.enabled: + self.timebomb_counter += 1 + else: + self.timebomb_counter = 0 + self.timebomb_bypass_counter = 0 + + if self.timebomb_counter >= 33000: # 330*100 time in seconds until counter threshold for timebombWarn alert + if not self.wheel_grabbed: + events.add(EventName.timebombWarn) + if self.wheel_grabbed or ret.steeringPressed: + self.wheel_grabbed = True + ret.stopSteering = True + self.timebomb_bypass_counter += 1 + if self.timebomb_bypass_counter >= 300: # 3*100 time alloted for bypass + self.wheel_grabbed = False + self.timebomb_counter = 0 + self.timebomb_bypass_counter = 0 + events.add(EventName.timebombBypassed) + else: + events.add(EventName.timebombBypassing) + ret.events = events.to_msg() ret.buttonEvents = buttonEvents # update previous car states + self.cruise_enabled_prev = ret.cruiseState.enabled self.displayMetricUnitsPrev = self.CS.displayMetricUnits self.buttonStatesPrev = self.CS.buttonStates.copy() @@ -189,6 +242,7 @@ class CarInterface(CarInterfaceBase): c.hudControl.leftLaneVisible, c.hudControl.rightLaneVisible, c.hudControl.leftLaneDepart, - c.hudControl.rightLaneDepart) + c.hudControl.rightLaneDepart, + self.dragonconf) self.frame += 1 return can_sends diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index fcbf56ac1..2004493ef 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -26,6 +26,7 @@ class CANBUS: pt = 0 cam = 2 +NetworkLocation = car.CarParams.NetworkLocation TransmissionType = car.CarParams.TransmissionType GearShifter = car.CarState.GearShifter diff --git a/selfdrive/car/volkswagen/volkswagencan.py b/selfdrive/car/volkswagen/volkswagencan.py index 0e35d21d6..4c3149297 100644 --- a/selfdrive/car/volkswagen/volkswagencan.py +++ b/selfdrive/car/volkswagen/volkswagencan.py @@ -27,8 +27,8 @@ def create_mqb_hud_control(packer, bus, enabled, steering_pressed, hud_alert, le values = { "LDW_Status_LED_gelb": 1 if enabled and steering_pressed else 0, "LDW_Status_LED_gruen": 1 if enabled and not steering_pressed else 0, - "LDW_Lernmodus_links": 3 if left_lane_depart else 1 + left_lane_visible, - "LDW_Lernmodus_rechts": 3 if right_lane_depart else 1 + right_lane_visible, + "LDW_Lernmodus_links": 3 if enabled and left_lane_visible else 1 + left_lane_visible, + "LDW_Lernmodus_rechts": 3 if enabled and right_lane_visible else 1 + right_lane_visible, "LDW_Texte": hud_alert, "LDW_SW_Warnung_links": ldw_lane_warning_left, "LDW_SW_Warnung_rechts": ldw_lane_warning_right, diff --git a/selfdrive/common/SConscript b/selfdrive/common/SConscript index 8f6c1dc18..677ceaf0b 100644 --- a/selfdrive/common/SConscript +++ b/selfdrive/common/SConscript @@ -28,7 +28,7 @@ if arch == "aarch64": 'touch.c', ] _gpu_libs = ['gui', 'adreno_utils'] -elif arch == "larch64": +elif arch == "larch64" or arch == "jarch64": _gpu_libs = ["GLESv2"] else: _gpu_libs = ["GL"] diff --git a/selfdrive/common/params.cc b/selfdrive/common/params.cc index 45eac661b..88e9b3824 100644 --- a/selfdrive/common/params.cc +++ b/selfdrive/common/params.cc @@ -33,9 +33,9 @@ namespace { -const std::string default_params_path = Hardware::PC() ? util::getenv_default("HOME", "/.comma/params", "/data/params") +const std::string default_params_path = Hardware::PC() || Hardware::JETSON() ? util::getenv_default("HOME", "/.comma/params", "/data/params") : "/data/params"; -const std::string persistent_params_path = Hardware::PC() ? default_params_path : "/persist/comma/params"; +const std::string persistent_params_path = Hardware::PC() || Hardware::JETSON() ? default_params_path : "/persist/comma/params"; volatile sig_atomic_t params_do_exit = 0; void params_sig_handler(int signal) { @@ -217,6 +217,70 @@ std::unordered_map keys = { {"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START}, {"Offroad_NvmeMissing", CLEAR_ON_MANAGER_START}, {"ForcePowerDown", CLEAR_ON_MANAGER_START}, + // dp + {"dp_atl", PERSISTENT}, + {"dp_dashcamd", PERSISTENT}, + {"dp_auto_shutdown", PERSISTENT}, + {"dp_auto_shutdown_in", PERSISTENT}, + {"dp_updated", PERSISTENT}, + {"dp_logger", PERSISTENT}, + {"dp_athenad", PERSISTENT}, + {"dp_uploader", PERSISTENT}, + {"dp_hotspot_on_boot", PERSISTENT}, + {"dp_lateral_mode", PERSISTENT}, + {"dp_signal_off_delay", PERSISTENT}, + {"dp_lc_min_mph", PERSISTENT}, + {"dp_lc_auto_cont", PERSISTENT}, + {"dp_lc_auto_min_mph", PERSISTENT}, + {"dp_lc_auto_delay", PERSISTENT}, + {"dp_allow_gas", PERSISTENT}, + {"dp_following_profile_ctrl", PERSISTENT}, + {"dp_following_profile", PERSISTENT}, + {"dp_accel_profile_ctrl", PERSISTENT}, + {"dp_accel_profile", PERSISTENT}, + {"dp_gear_check", PERSISTENT}, + {"dp_speed_check", PERSISTENT}, + {"dp_temp_monitor", PERSISTENT}, + {"dp_ui_display_mode", PERSISTENT}, + {"dp_ui_speed", PERSISTENT}, + {"dp_ui_event", PERSISTENT}, + {"dp_ui_max_speed", PERSISTENT}, + {"dp_ui_face", PERSISTENT}, + {"dp_ui_lane", PERSISTENT}, + {"dp_ui_lead", PERSISTENT}, + {"dp_ui_dev", PERSISTENT}, + {"dp_ui_dev_mini", PERSISTENT}, + {"dp_ui_blinker", PERSISTENT}, + {"dp_ui_brightness", PERSISTENT}, + {"dp_ui_volume", PERSISTENT}, + {"dp_toyota_ldw", PERSISTENT}, + {"dp_toyota_sng", PERSISTENT}, + {"dp_toyota_zss", PERSISTENT}, + {"dp_toyota_disable_relay", PERSISTENT}, + {"dp_hkg_smart_mdps", PERSISTENT}, + {"dp_honda_eps_mod", PERSISTENT}, + {"dp_vw_panda", PERSISTENT}, + {"dp_vw_timebomb_assist", PERSISTENT}, + {"dp_fan_mode", PERSISTENT}, + {"dp_last_modified", PERSISTENT}, + {"dp_camera_offset", PERSISTENT}, + {"dp_path_offset", PERSISTENT}, + {"dp_locale", PERSISTENT}, + {"dp_reg", PERSISTENT}, + {"dp_sr_learner", PERSISTENT}, + {"dp_sr_custom", PERSISTENT}, + {"dp_sr_stock", PERSISTENT}, + {"dp_lqr", PERSISTENT}, + {"dp_reset_live_param_on_start", PERSISTENT}, + {"dp_appd", PERSISTENT}, + {"dp_jetson", PERSISTENT}, + {"dp_car_assigned", PERSISTENT}, + {"dp_car_list", PERSISTENT}, + {"dp_no_batt", PERSISTENT}, + {"dp_panda_fake_black", PERSISTENT}, + {"dp_panda_no_gps", PERSISTENT}, + {"dp_last_candidate", PERSISTENT}, + {"dp_debug", PERSISTENT}, }; } // namespace @@ -329,3 +393,7 @@ void Params::clearAll(ParamKeyType key_type) { } } } + +std::string Params::get_params_path() { + return default_params_path; +} \ No newline at end of file diff --git a/selfdrive/common/params.h b/selfdrive/common/params.h index 3d59f07b1..62ecd3c01 100644 --- a/selfdrive/common/params.h +++ b/selfdrive/common/params.h @@ -78,4 +78,5 @@ public: inline int putBool(const std::string &key, bool val) { return putBool(key.c_str(), val); } + std::string get_params_path(); }; diff --git a/selfdrive/common/swaglog.cc b/selfdrive/common/swaglog.cc index 80d2379d9..0cf5f410e 100644 --- a/selfdrive/common/swaglog.cc +++ b/selfdrive/common/swaglog.cc @@ -75,6 +75,8 @@ static void cloudlog_init() { cloudlog_bind_locked("device", "eon"); } else if (Hardware::TICI()) { cloudlog_bind_locked("device", "tici"); + } else if (Hardware::JETSON()) { + cloudlog_bind_locked("device", "jetson"); } else { cloudlog_bind_locked("device", "pc"); } diff --git a/selfdrive/common/version.h b/selfdrive/common/version.h index 5518dbc16..3e3a60093 100644 --- a/selfdrive/common/version.h +++ b/selfdrive/common/version.h @@ -1 +1 @@ -#define COMMA_VERSION "0.8.5-d4ab1f1e2-2021-06-07T22:13:55" +#define COMMA_VERSION "0.8.5-dp-4" diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 6608ce3c2..cd61b319b 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -32,7 +32,7 @@ STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees SIMULATION = "SIMULATION" in os.environ NOSENSOR = "NOSENSOR" in os.environ -IGNORE_PROCESSES = set(["rtshield", "uploader", "deleter", "loggerd", "logmessaged", "tombstoned", "logcatd", "proclogd", "clocksd", "updated", "timezoned", "manage_athenad"]) +IGNORE_PROCESSES = set(["rtshield", "uploader", "deleter", "loggerd", "logmessaged", "tombstoned", "logcatd", "proclogd", "clocksd", "updated", "timezoned", "manage_athenad", "dragonConf"]) ThermalStatus = log.DeviceState.ThermalStatus State = log.ControlsState.OpenpilotState @@ -45,6 +45,9 @@ EventName = car.CarEvent.EventName class Controls: def __init__(self, sm=None, pm=None, can_sock=None): + params = Params() + self.dp_jetson = params.get_bool('dp_jetson') + self.dp_panda_no_gps = params.get_bool('dp_panda_no_gps') config_realtime_process(4 if TICI else 3, Priority.CTRL_HIGH) # Setup sockets @@ -60,9 +63,13 @@ class Controls: self.sm = sm if self.sm is None: ignore = ['driverCameraState', 'managerState'] if SIMULATION else None + if self.dp_jetson: + ignore = ['driverCameraState'] if ignore is None else ignore + ['driverCameraState'] + if self.dp_panda_no_gps: + ignore = ['liveLocationKalman'] if ignore is None else ignore + ['liveLocationKalman'] self.sm = messaging.SubMaster(['deviceState', 'pandaState', 'modelV2', 'liveCalibration', 'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman', - 'managerState', 'liveParameters', 'radarState'] + self.camera_packets, + 'managerState', 'liveParameters', 'radarState', 'dragonConf'] + self.camera_packets, ignore_alive=ignore, ignore_avg_freq=['radarState', 'longitudinalPlan']) self.can_sock = can_sock @@ -80,7 +87,6 @@ class Controls: self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan']) # read params - params = Params() self.is_metric = params.get_bool("IsMetric") self.is_ldw_enabled = params.get_bool("IsLdwEnabled") self.enable_lte_onroad = params.get_bool("EnableLteOnroad") @@ -115,7 +121,9 @@ class Controls: self.LoC = LongControl(self.CP, self.CI.compute_gb) self.VM = VehicleModel(self.CP) - if self.CP.steerControlType == car.CarParams.SteerControlType.angle: + if params.get_bool('dp_lqr'): + self.LaC = LatControlLQR(self.CP) + elif self.CP.steerControlType == car.CarParams.SteerControlType.angle: self.LaC = LatControlAngle(self.CP) elif self.CP.lateralTuning.which() == 'pid': self.LaC = LatControlPID(self.CP) @@ -148,8 +156,8 @@ class Controls: self.startup_event = get_startup_event(car_recognized, controller_available, self.CP.fuzzyFingerprint, len(self.CP.carFw) > 0) - if not sounds_available: - self.events.add(EventName.soundsUnavailable, static=True) + # if not sounds_available: + # self.events.add(EventName.soundsUnavailable, static=True) if community_feature_disallowed and car_recognized: self.events.add(EventName.communityFeatureDisallowed, static=True) if not car_recognized: @@ -161,6 +169,11 @@ class Controls: self.rk = Ratekeeper(100, print_delay_threshold=None) self.prof = Profiler(False) # off by default + # dp + self.sm['dragonConf'].dpAtl = False + self.sm['dragonConf'].dpSrCustom = self.CP.steerRatio + self.sm['dragonConf'].dpSrLearner = True + def update_events(self, CS): """Compute carEvents from carState""" @@ -179,9 +192,9 @@ class Controls: return # Create events for battery, temperature, disk space, and memory - if self.sm['deviceState'].batteryPercent < 1 and self.sm['deviceState'].chargingError: - # at zero percent battery, while discharging, OP should not allowed - self.events.add(EventName.lowBattery) + # if self.sm['deviceState'].batteryPercent < 1 and self.sm['deviceState'].chargingError: + # # at zero percent battery, while discharging, OP should not allowed + # self.events.add(EventName.lowBattery) if self.sm['deviceState'].thermalStatus >= ThermalStatus.red: self.events.add(EventName.overheat) if self.sm['deviceState'].freeSpacePercent < 7: @@ -215,15 +228,15 @@ class Controls: self.events.add(EventName.laneChangeBlocked) else: if direction == LaneChangeDirection.left: - self.events.add(EventName.preLaneChangeLeft) + self.events.add(EventName.preLaneChangeLeftALC if self.sm['lateralPlan'].dpALCAllowed else EventName.preLaneChangeLeft) else: - self.events.add(EventName.preLaneChangeRight) + self.events.add(EventName.preLaneChangeRightALC if self.sm['lateralPlan'].dpALCAllowed else EventName.preLaneChangeRight) elif self.sm['lateralPlan'].laneChangeState in [LaneChangeState.laneChangeStarting, LaneChangeState.laneChangeFinishing]: self.events.add(EventName.laneChange) if self.can_rcv_error or not CS.canValid: - self.events.add(EventName.canError) + self.events.add(EventName.pcmDisable if self.sm['dragonConf'].dpAtl else EventName.canError) safety_mismatch = self.sm['pandaState'].safetyModel != self.CP.safetyModel or self.sm['pandaState'].safetyParam != self.CP.safetyParam if safety_mismatch or self.mismatch_counter >= 200: @@ -236,7 +249,7 @@ class Controls: self.events.add(EventName.radarFault) elif not self.sm.valid["pandaState"]: self.events.add(EventName.usbError) - elif not self.sm.all_alive_and_valid(): + elif not self.dp_jetson and not self.sm.all_alive_and_valid(): self.events.add(EventName.commIssue) if not self.logged_comm_issue: cloudlog.error(f"commIssue - valid: {self.sm.valid} - alive: {self.sm.alive}") @@ -245,8 +258,8 @@ class Controls: self.logged_comm_issue = False if not self.sm['lateralPlan'].mpcSolutionValid: - self.events.add(EventName.plannerError) - if not self.sm['liveLocationKalman'].sensorsOK and not NOSENSOR: + self.events.add(EventName.steerTempUnavailableUserOverride if self.sm['dragonConf'].dpAtl else EventName.plannerError) + if not self.dp_panda_no_gps and not self.sm['liveLocationKalman'].sensorsOK and not NOSENSOR: if self.sm.frame > 5 / DT_CTRL: # Give locationd some time to receive all the inputs self.events.add(EventName.sensorDataInvalid) if not self.sm['liveLocationKalman'].posenetOK: @@ -280,16 +293,16 @@ class Controls: # TODO: fix simulator if not SIMULATION: - if not NOSENSOR: + if not self.dp_panda_no_gps and not NOSENSOR: if not self.sm['liveLocationKalman'].gpsOK and (self.distance_traveled > 1000) and \ (not TICI or self.enable_lte_onroad): # Not show in first 1 km to allow for driving out of garage. This event shows after 5 minutes self.events.add(EventName.noGps) - if not self.sm.all_alive(self.camera_packets): + if not self.dp_jetson and not self.sm.all_alive(self.camera_packets): self.events.add(EventName.cameraMalfunction) if self.sm['modelV2'].frameDropPerc > 20: self.events.add(EventName.modeldLagging) - if self.sm['liveLocationKalman'].excessiveResets: + if not self.dp_panda_no_gps and self.sm['liveLocationKalman'].excessiveResets: self.events.add(EventName.localizerMalfunction) # Check if all manager processes are running @@ -298,7 +311,7 @@ class Controls: self.events.add(EventName.processNotRunning) # Only allow engagement with brake pressed when stopped behind another stopped car - if CS.brakePressed and self.sm['longitudinalPlan'].vTargetFuture >= STARTING_TARGET_SPEED \ + if not self.sm['dragonConf'].dpAtl and CS.brakePressed and self.sm['longitudinalPlan'].vTargetFuture >= STARTING_TARGET_SPEED \ and self.CP.openpilotLongitudinalControl and CS.vEgo < 0.3: self.events.add(EventName.noTarget) @@ -307,7 +320,7 @@ class Controls: # Update carState from CAN can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True) - CS = self.CI.update(self.CC, can_strs) + CS = self.CI.update(self.CC, can_strs, self.sm['dragonConf']) self.sm.update(0) @@ -330,7 +343,7 @@ class Controls: if not self.enabled: self.mismatch_counter = 0 - if not self.sm['pandaState'].controlsAllowed and self.enabled: + if not self.sm['dragonConf'].dpAtl and not self.sm['pandaState'].controlsAllowed and self.enabled: self.mismatch_counter += 1 self.distance_traveled += CS.vEgo * DT_CTRL @@ -421,6 +434,11 @@ class Controls: params = self.sm['liveParameters'] x = max(params.stiffnessFactor, 0.1) sr = max(params.steerRatio, 0.1) + if not self.sm['dragonConf'].dpSrLearner: + if self.sm['dragonConf'].dpSrCustom >= 10: + sr = self.sm['dragonConf'].dpSrCustom + else: + sr = self.CP.steerRatio self.VM.update_params(x, sr) lat_plan = self.sm['lateralPlan'] @@ -557,6 +575,7 @@ class Controls: controlsState.enabled = self.enabled controlsState.active = self.active controlsState.curvature = curvature + controlsState.angleSteers = CS.steeringAngleDeg controlsState.steeringAngleDesiredDeg = angle_steers_des controlsState.state = self.state controlsState.engageable = not self.events.any(ET.NO_ENTRY) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 62e9dab76..d7bd224f0 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -1,3 +1,5 @@ +# This Python file uses the following encoding: utf-8 +# -*- coding: utf-8 -*- from enum import IntEnum from typing import Dict, Union, Callable, Any @@ -6,6 +8,8 @@ import cereal.messaging as messaging from common.realtime import DT_CTRL from selfdrive.config import Conversions as CV from selfdrive.locationd.calibrationd import MIN_SPEED_FILTER +from common.i18n import events +_ = events() AlertSize = log.ControlsState.AlertSize AlertStatus = log.ControlsState.AlertStatus @@ -141,21 +145,21 @@ class Alert: class NoEntryAlert(Alert): def __init__(self, alert_text_2, audible_alert=AudibleAlert.chimeError, visual_alert=VisualAlert.none, duration_hud_alert=2.): - super().__init__("openpilot Unavailable", alert_text_2, AlertStatus.normal, + super().__init__(_("openpilot Unavailable"), alert_text_2, AlertStatus.normal, AlertSize.mid, Priority.LOW, visual_alert, audible_alert, .4, duration_hud_alert, 3.) class SoftDisableAlert(Alert): def __init__(self, alert_text_2): - super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2, + super().__init__(_("TAKE CONTROL IMMEDIATELY"), alert_text_2, AlertStatus.critical, AlertSize.full, Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), class ImmediateDisableAlert(Alert): - def __init__(self, alert_text_2, alert_text_1="TAKE CONTROL IMMEDIATELY"): + def __init__(self, alert_text_2, alert_text_1=_("TAKE CONTROL IMMEDIATELY")): super().__init__(alert_text_1, alert_text_2, AlertStatus.critical, AlertSize.full, Priority.HIGHEST, VisualAlert.steerRequired, @@ -180,8 +184,8 @@ def below_steer_speed_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: speed = int(round(CP.minSteerSpeed * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH))) unit = "km/h" if metric else "mph" return Alert( - "TAKE CONTROL", - "Steer Unavailable Below %d %s" % (speed, unit), + _("TAKE CONTROL"), + _("Steer Unavailable Below %(speed)d %(unit)s") % ({"speed": speed, "unit": unit}), AlertStatus.userPrompt, AlertSize.mid, Priority.MID, VisualAlert.steerRequired, AudibleAlert.none, 0., 0.4, .3) @@ -189,23 +193,23 @@ def calibration_incomplete_alert(CP: car.CarParams, sm: messaging.SubMaster, met speed = int(MIN_SPEED_FILTER * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)) unit = "km/h" if metric else "mph" return Alert( - "Calibration in Progress: %d%%" % sm['liveCalibration'].calPerc, - "Drive Above %d %s" % (speed, unit), + _("Calibration in Progress: %d%%") % sm['liveCalibration'].calPerc, + _("Drive Above %(speed)d %(unit)s") % ({"speed": speed, "unit": unit}), AlertStatus.normal, AlertSize.mid, Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2) def no_gps_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert: gps_integrated = sm['pandaState'].pandaType in [log.PandaState.PandaType.uno, log.PandaState.PandaType.dos] return Alert( - "Poor GPS reception", - "If sky is visible, contact support" if gps_integrated else "Check GPS antenna placement", + _("Poor GPS reception"), + _("If sky is visible, contact support") if gps_integrated else _("Check GPS antenna placement"), AlertStatus.normal, AlertSize.mid, Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2, creation_delay=300.) def wrong_car_mode_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert: - text = "Cruise Mode Disabled" + text = _("Cruise Mode Disabled") if CP.carName == "honda": - text = "Main Switch Off" + text = _("Main Switch Off") return NoEntryAlert(text, duration_hud_alert=0.) def startup_fuzzy_fingerprint_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert: @@ -222,7 +226,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.joystickDebug: { ET.PERMANENT: Alert( - "DEBUG ALERT", + _("DEBUG ALERT"), "", AlertStatus.userPrompt, AlertSize.mid, Priority.LOW, VisualAlert.none, AudibleAlert.none, .1, .1, .1), @@ -234,32 +238,32 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.startup: { ET.PERMANENT: Alert( - "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.), }, EventName.startupMaster: { ET.PERMANENT: Alert( - "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.), }, EventName.startupNoControl: { ET.PERMANENT: Alert( - "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.), }, EventName.startupNoCar: { ET.PERMANENT: Alert( - "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.), }, @@ -286,8 +290,8 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.invalidLkasSetting: { ET.PERMANENT: Alert( - "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), }, @@ -295,24 +299,24 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.communityFeatureDisallowed: { # LOW priority to overcome Cruise Error ET.PERMANENT: Alert( - "openpilot Not Available", - "Enable Community Features in Settings to Engage", + _("openpilot Not Available"), + _("Enable Community Features in Settings to Engage"), AlertStatus.normal, AlertSize.mid, Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), }, EventName.carUnrecognized: { ET.PERMANENT: Alert( - "Dashcam Mode", - "Car Unrecognized", + _("Dashcam Mode"), + _("Car Unrecognized"), AlertStatus.normal, AlertSize.mid, Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2), }, EventName.stockAeb: { ET.PERMANENT: Alert( - "BRAKE!", - "Stock AEB: Risk of Collision", + _("BRAKE!"), + _("Stock AEB: Risk of Collision"), AlertStatus.critical, AlertSize.full, Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 1., 2., 2.), ET.NO_ENTRY: NoEntryAlert("Stock AEB: Risk of Collision"), @@ -320,8 +324,8 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.stockFcw: { ET.PERMANENT: Alert( - "BRAKE!", - "Stock FCW: Risk of Collision", + _("BRAKE!"), + _("Stock FCW: Risk of Collision"), AlertStatus.critical, AlertSize.full, Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 1., 2., 2.), ET.NO_ENTRY: NoEntryAlert("Stock FCW: Risk of Collision"), @@ -329,16 +333,16 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.fcw: { ET.PERMANENT: Alert( - "BRAKE!", - "Risk of Collision", + _("BRAKE!"), + _("Risk of Collision"), AlertStatus.critical, AlertSize.full, Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.chimeWarningRepeat, 1., 2., 2.), }, EventName.ldw: { ET.PERMANENT: Alert( - "TAKE CONTROL", - "Lane Departure Detected", + _("TAKE CONTROL"), + _("Lane Departure Detected"), AlertStatus.userPrompt, AlertSize.mid, Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 2., 3.), }, @@ -347,7 +351,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.gasPressed: { ET.PRE_ENABLE: Alert( - "openpilot will not brake while gas pressed", + _("openpilot will not brake while gas pressed"), "", AlertStatus.normal, AlertSize.small, Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .0, .0, .1, creation_delay=1.), @@ -357,7 +361,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo ET.NO_ENTRY: NoEntryAlert("Vehicle Parameter Identification Failed"), ET.SOFT_DISABLE: SoftDisableAlert("Vehicle Parameter Identification Failed"), ET.WARNING: Alert( - "Vehicle Parameter Identification Failed", + _("Vehicle Parameter Identification Failed"), "", AlertStatus.normal, AlertSize.small, Priority.LOWEST, VisualAlert.steerRequired, AudibleAlert.none, .0, .0, .1), @@ -365,7 +369,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.steerTempUnavailableUserOverride: { ET.WARNING: Alert( - "Steering Temporarily Unavailable", + _("Steering Temporarily Unavailable"), "", AlertStatus.userPrompt, AlertSize.small, Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 1., 1.), @@ -373,7 +377,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.preDriverDistracted: { ET.WARNING: Alert( - "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), @@ -381,23 +385,23 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.promptDriverDistracted: { ET.WARNING: Alert( - "KEEP EYES ON ROAD", - "Driver Distracted", + _("KEEP EYES ON ROAD"), + _("Driver Distracted"), AlertStatus.userPrompt, AlertSize.mid, Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1), }, EventName.driverDistracted: { ET.WARNING: Alert( - "DISENGAGE IMMEDIATELY", - "Driver Distracted", + _("DISENGAGE IMMEDIATELY"), + _("Driver Distracted"), AlertStatus.critical, AlertSize.full, Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), }, EventName.preDriverUnresponsive: { ET.WARNING: Alert( - "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), @@ -405,40 +409,40 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.promptDriverUnresponsive: { ET.WARNING: Alert( - "TOUCH STEERING WHEEL", - "Driver Unresponsive", + _("TOUCH STEERING WHEEL"), + _("Driver Unresponsive"), AlertStatus.userPrompt, AlertSize.mid, Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1), }, EventName.driverUnresponsive: { ET.WARNING: Alert( - "DISENGAGE IMMEDIATELY", - "Driver Unresponsive", + _("DISENGAGE IMMEDIATELY"), + _("Driver Unresponsive"), AlertStatus.critical, AlertSize.full, Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), }, EventName.driverMonitorLowAcc: { ET.WARNING: Alert( - "CHECK DRIVER FACE VISIBILITY", - "Driver Monitoring Uncertain", + _("CHECK DRIVER FACE VISIBILITY"), + _("Driver Monitoring Uncertain"), AlertStatus.normal, AlertSize.mid, Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .4, 0., 1.5), }, EventName.manualRestart: { ET.WARNING: Alert( - "TAKE CONTROL", - "Resume Driving Manually", + _("TAKE CONTROL"), + _("Resume Driving Manually"), AlertStatus.userPrompt, AlertSize.mid, Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), }, EventName.resumeRequired: { ET.WARNING: Alert( - "STOPPED", - "Press Resume to Move", + _("STOPPED"), + _("Press Resume to Move"), AlertStatus.userPrompt, AlertSize.mid, Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), }, @@ -449,54 +453,54 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.preLaneChangeLeft: { ET.WARNING: Alert( - "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), }, EventName.preLaneChangeRight: { ET.WARNING: Alert( - "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), }, EventName.laneChangeBlocked: { ET.WARNING: Alert( - "Car Detected in Blindspot", - "Monitor Other Vehicles", + _("Car Detected in Blindspot"), + _("Monitor Other Vehicles"), AlertStatus.userPrompt, AlertSize.mid, Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, .1, .1, .1), }, EventName.laneChange: { ET.WARNING: Alert( - "Changing Lane", - "Monitor Other Vehicles", + _("Changing Lane"), + _("Monitor Other Vehicles"), AlertStatus.normal, AlertSize.mid, Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1), }, EventName.steerSaturated: { ET.WARNING: Alert( - "TAKE CONTROL", - "Turn Exceeds Steering Limit", + _("TAKE CONTROL"), + _("Turn Exceeds Steering Limit"), AlertStatus.userPrompt, AlertSize.mid, Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 1., 1.), }, EventName.fanMalfunction: { - ET.PERMANENT: NormalPermanentAlert("Fan Malfunction", "Contact Support"), + ET.PERMANENT: NormalPermanentAlert(_("Fan Malfunction"), _("Contact Support")), }, EventName.cameraMalfunction: { - ET.PERMANENT: NormalPermanentAlert("Camera Malfunction", "Contact Support"), + ET.PERMANENT: NormalPermanentAlert(_("Camera Malfunction"), _("Contact Support")), }, EventName.gpsMalfunction: { - ET.PERMANENT: NormalPermanentAlert("GPS Malfunction", "Contact Support"), + ET.PERMANENT: NormalPermanentAlert(_("GPS Malfunction"), _("Contact Support")), }, EventName.localizerMalfunction: { @@ -523,17 +527,17 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.brakeHold: { ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), - ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"), + ET.NO_ENTRY: NoEntryAlert(_("Brake Hold Active")), }, EventName.parkBrake: { ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), - ET.NO_ENTRY: NoEntryAlert("Park Brake Engaged"), + ET.NO_ENTRY: NoEntryAlert(_("Park Brake Engaged")), }, EventName.pedalPressed: { ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), - ET.NO_ENTRY: NoEntryAlert("Pedal Pressed During Attempt", + ET.NO_ENTRY: NoEntryAlert(_("Pedal Pressed During Attempt"), visual_alert=VisualAlert.brakePressed), }, @@ -544,36 +548,36 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.wrongCruiseMode: { ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), - ET.NO_ENTRY: NoEntryAlert("Enable Adaptive Cruise"), + ET.NO_ENTRY: NoEntryAlert(_("Enable Adaptive Cruise")), }, EventName.steerTempUnavailable: { - ET.SOFT_DISABLE: SoftDisableAlert("Steering Temporarily Unavailable"), - ET.NO_ENTRY: NoEntryAlert("Steering Temporarily Unavailable", + ET.SOFT_DISABLE: SoftDisableAlert(_("Steering Temporarily Unavailable")), + ET.NO_ENTRY: NoEntryAlert(_("Steering Temporarily Unavailable"), duration_hud_alert=0.), }, EventName.outOfSpace: { ET.PERMANENT: Alert( - "Out of Storage", + _("Out of Storage"), "", AlertStatus.normal, AlertSize.small, Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), - ET.NO_ENTRY: NoEntryAlert("Out of Storage Space", + ET.NO_ENTRY: NoEntryAlert(_("Out of Storage Space"), duration_hud_alert=0.), }, EventName.belowEngageSpeed: { - ET.NO_ENTRY: NoEntryAlert("Speed Too Low"), + ET.NO_ENTRY: NoEntryAlert(_("Speed Too Low")), }, EventName.sensorDataInvalid: { ET.PERMANENT: Alert( - "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, creation_delay=1.), - ET.NO_ENTRY: NoEntryAlert("No Data from Device Sensors"), + ET.NO_ENTRY: NoEntryAlert(_("No Data from Device Sensors")), }, EventName.noGps: { @@ -581,107 +585,107 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo }, EventName.soundsUnavailable: { - ET.PERMANENT: NormalPermanentAlert("Speaker not found", "Reboot your Device"), - ET.NO_ENTRY: NoEntryAlert("Speaker not found"), + ET.PERMANENT: NormalPermanentAlert(_("Speaker not found"), _("Reboot your Device")), + ET.NO_ENTRY: NoEntryAlert(_("Speaker not found")), }, EventName.tooDistracted: { - ET.NO_ENTRY: NoEntryAlert("Distraction Level Too High"), + ET.NO_ENTRY: NoEntryAlert(_("Distraction Level Too High")), }, EventName.overheat: { ET.PERMANENT: Alert( - "System Overheated", + _("System Overheated"), "", AlertStatus.normal, AlertSize.small, Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), - ET.SOFT_DISABLE: SoftDisableAlert("System Overheated"), - ET.NO_ENTRY: NoEntryAlert("System Overheated"), + ET.SOFT_DISABLE: SoftDisableAlert(_("System Overheated")), + ET.NO_ENTRY: NoEntryAlert(_("System Overheated")), }, EventName.wrongGear: { - ET.SOFT_DISABLE: SoftDisableAlert("Gear not D"), - ET.NO_ENTRY: NoEntryAlert("Gear not D"), + ET.SOFT_DISABLE: SoftDisableAlert(_("Gear not D")), + ET.NO_ENTRY: NoEntryAlert(_("Gear not D")), }, EventName.calibrationInvalid: { - ET.PERMANENT: NormalPermanentAlert("Calibration Invalid", "Remount Device and Recalibrate"), - ET.SOFT_DISABLE: SoftDisableAlert("Calibration Invalid: Remount Device & Recalibrate"), - ET.NO_ENTRY: NoEntryAlert("Calibration Invalid: Remount Device & Recalibrate"), + ET.PERMANENT: NormalPermanentAlert(_("Calibration Invalid"), _("Remount Device and Recalibrate")), + ET.SOFT_DISABLE: SoftDisableAlert(_("Calibration Invalid: Remount Device & Recalibrate")), + ET.NO_ENTRY: NoEntryAlert(_("Calibration Invalid: Remount Device & Recalibrate")), }, EventName.calibrationIncomplete: { ET.PERMANENT: calibration_incomplete_alert, - ET.SOFT_DISABLE: SoftDisableAlert("Calibration in Progress"), - ET.NO_ENTRY: NoEntryAlert("Calibration in Progress"), + ET.SOFT_DISABLE: SoftDisableAlert(_("Calibration in Progress")), + ET.NO_ENTRY: NoEntryAlert(_("Calibration in Progress")), }, EventName.doorOpen: { - ET.SOFT_DISABLE: SoftDisableAlert("Door Open"), - ET.NO_ENTRY: NoEntryAlert("Door Open"), + ET.SOFT_DISABLE: SoftDisableAlert(_("Door Open")), + ET.NO_ENTRY: NoEntryAlert(_("Door Open")), }, EventName.seatbeltNotLatched: { - ET.SOFT_DISABLE: SoftDisableAlert("Seatbelt Unlatched"), - ET.NO_ENTRY: NoEntryAlert("Seatbelt Unlatched"), + ET.SOFT_DISABLE: SoftDisableAlert(_("Seatbelt Unlatched")), + ET.NO_ENTRY: NoEntryAlert(_("Seatbelt Unlatched")), }, EventName.espDisabled: { - ET.SOFT_DISABLE: SoftDisableAlert("ESP Off"), - ET.NO_ENTRY: NoEntryAlert("ESP Off"), + ET.SOFT_DISABLE: SoftDisableAlert(_("ESP Off")), + ET.NO_ENTRY: NoEntryAlert(_("ESP Off")), }, EventName.lowBattery: { - ET.SOFT_DISABLE: SoftDisableAlert("Low Battery"), - ET.NO_ENTRY: NoEntryAlert("Low Battery"), + ET.SOFT_DISABLE: SoftDisableAlert(_("Low Battery")), + ET.NO_ENTRY: NoEntryAlert(_("Low Battery")), }, EventName.commIssue: { - ET.SOFT_DISABLE: SoftDisableAlert("Communication Issue between Processes"), - ET.NO_ENTRY: NoEntryAlert("Communication Issue between Processes", + ET.SOFT_DISABLE: SoftDisableAlert(_("Communication Issue between Processes")), + ET.NO_ENTRY: NoEntryAlert(_("Communication Issue between Processes"), audible_alert=AudibleAlert.chimeDisengage), }, EventName.processNotRunning: { - ET.NO_ENTRY: NoEntryAlert("System Malfunction: Reboot Your Device", + ET.NO_ENTRY: NoEntryAlert(_("System Malfunction: Reboot Your Device"), audible_alert=AudibleAlert.chimeDisengage), }, EventName.radarFault: { - ET.SOFT_DISABLE: SoftDisableAlert("Radar Error: Restart the Car"), - ET.NO_ENTRY : NoEntryAlert("Radar Error: Restart the Car"), + ET.SOFT_DISABLE: SoftDisableAlert(_("Radar Error: Restart the Car")), + ET.NO_ENTRY : NoEntryAlert(_("Radar Error: Restart the Car")), }, EventName.modeldLagging: { - ET.SOFT_DISABLE: SoftDisableAlert("Driving model lagging"), - ET.NO_ENTRY : NoEntryAlert("Driving model lagging"), + ET.SOFT_DISABLE: SoftDisableAlert(_("Driving model lagging")), + ET.NO_ENTRY : NoEntryAlert(_("Driving model lagging")), }, EventName.posenetInvalid: { - ET.SOFT_DISABLE: SoftDisableAlert("Model Output Uncertain"), - ET.NO_ENTRY: NoEntryAlert("Model Output Uncertain"), + ET.SOFT_DISABLE: SoftDisableAlert(_("Model Output Uncertain")), + ET.NO_ENTRY: NoEntryAlert(_("Model Output Uncertain")), }, EventName.deviceFalling: { - ET.SOFT_DISABLE: SoftDisableAlert("Device Fell Off Mount"), - ET.NO_ENTRY: NoEntryAlert("Device Fell Off Mount"), + ET.SOFT_DISABLE: SoftDisableAlert(_("Device Fell Off Mount")), + ET.NO_ENTRY: NoEntryAlert(_("Device Fell Off Mount")), }, EventName.lowMemory: { - ET.SOFT_DISABLE: SoftDisableAlert("Low Memory: Reboot Your Device"), - ET.PERMANENT: NormalPermanentAlert("Low Memory", "Reboot your Device"), - ET.NO_ENTRY : NoEntryAlert("Low Memory: Reboot Your Device", + ET.SOFT_DISABLE: SoftDisableAlert(_("Low Memory: Reboot Your Device")), + ET.PERMANENT: NormalPermanentAlert(_("Low Memory"), _("Reboot your Device")), + ET.NO_ENTRY : NoEntryAlert(_("Low Memory: Reboot Your Device"), audible_alert=AudibleAlert.chimeDisengage), }, EventName.accFaulted: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Faulted"), - ET.PERMANENT: NormalPermanentAlert("Cruise Faulted", ""), - ET.NO_ENTRY: NoEntryAlert("Cruise Faulted"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert(_("Cruise Faulted")), + ET.PERMANENT: NormalPermanentAlert(_("Cruise Faulted"), ""), + ET.NO_ENTRY: NoEntryAlert(_("Cruise Faulted")), }, EventName.controlsMismatch: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Mismatch"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert(_("Controls Mismatch")), }, EventName.roadCameraError: { @@ -706,97 +710,154 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo }, EventName.canError: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Error: Check Connections"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert(_("CAN Error: Check Connections")), ET.PERMANENT: Alert( - "CAN Error: Check Connections", + _("CAN Error: Check Connections"), "", AlertStatus.normal, AlertSize.small, Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2, creation_delay=1.), - ET.NO_ENTRY: NoEntryAlert("CAN Error: Check Connections"), + ET.NO_ENTRY: NoEntryAlert(_("CAN Error: Check Connections")), }, EventName.steerUnavailable: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("LKAS Fault: Restart the Car"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert(_("LKAS Fault: Restart the Car")), ET.PERMANENT: Alert( - "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), - ET.NO_ENTRY: NoEntryAlert("LKAS Fault: Restart the Car"), + ET.NO_ENTRY: NoEntryAlert(_("LKAS Fault: Restart the Car")), }, EventName.brakeUnavailable: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Fault: Restart the Car"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert(_("Cruise Fault: Restart the Car")), ET.PERMANENT: Alert( - "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), - ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"), + ET.NO_ENTRY: NoEntryAlert(_("Cruise Fault: Restart the Car")), }, EventName.reverseGear: { ET.PERMANENT: Alert( - "Reverse\nGear", + _("Reverse\nGear"), "", AlertStatus.normal, AlertSize.full, Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2, creation_delay=0.5), - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Reverse Gear"), - ET.NO_ENTRY: NoEntryAlert("Reverse Gear"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert(_("Reverse Gear")), + ET.NO_ENTRY: NoEntryAlert(_("Reverse Gear")), }, EventName.cruiseDisabled: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Is Off"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert(_("Cruise Is Off")), }, EventName.plannerError: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Planner Solution Error"), - ET.NO_ENTRY: NoEntryAlert("Planner Solution Error"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert(_("Planner Solution Error")), + ET.NO_ENTRY: NoEntryAlert(_("Planner Solution Error")), }, EventName.relayMalfunction: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Harness Malfunction"), - ET.PERMANENT: NormalPermanentAlert("Harness Malfunction", "Check Hardware"), - ET.NO_ENTRY: NoEntryAlert("Harness Malfunction"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert(_("Harness Malfunction")), + ET.PERMANENT: NormalPermanentAlert(_("Harness Malfunction"), _("Check Hardware")), + ET.NO_ENTRY: NoEntryAlert(_("Harness Malfunction")), }, EventName.noTarget: { ET.IMMEDIATE_DISABLE: Alert( - "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.), - ET.NO_ENTRY : NoEntryAlert("No Close Lead Car"), + ET.NO_ENTRY : NoEntryAlert(_("No Close Lead Car")), }, EventName.speedTooLow: { ET.IMMEDIATE_DISABLE: Alert( - "openpilot Canceled", - "Speed too low", + _("openpilot Canceled"), + _("Speed too low"), AlertStatus.normal, AlertSize.mid, Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), }, EventName.speedTooHigh: { ET.WARNING: Alert( - "Speed Too High", - "Model uncertain at this speed", + _("Speed Too High"), + _("Model uncertain at this speed"), AlertStatus.normal, AlertSize.mid, Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), ET.NO_ENTRY: Alert( - "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.), }, EventName.lowSpeedLockout: { ET.PERMANENT: Alert( - "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), - ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"), + ET.NO_ENTRY: NoEntryAlert(_("Cruise Fault: Restart the Car")), }, + # dp + EventName.preLaneChangeLeftALC: { + ET.WARNING: Alert( + _("Left ALC will start in 3s"), + _("Monitor Other Vehicles"), + AlertStatus.normal, AlertSize.mid, + Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning2, .1, .1, .1, alert_rate=0.75), + }, + + EventName.preLaneChangeRightALC: { + ET.WARNING: Alert( + _("Right ALC will start in 3s"), + _("Monitor Other Vehicles"), + AlertStatus.normal, AlertSize.mid, + Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning2, .1, .1, .1, alert_rate=0.75), + }, + + EventName.manualSteeringRequired: { + ET.WARNING: Alert( + _("STEERING REQUIRED: Lane Keeping OFF"), + "", + AlertStatus.normal, AlertSize.small, + Priority.LOW, VisualAlert.none, AudibleAlert.none, .0, .1, .1, alert_rate=0.25), + }, + + EventName.manualSteeringRequiredBlinkersOn: { + ET.WARNING: Alert( + _("STEERING REQUIRED: Blinkers ON"), + "", + AlertStatus.normal, AlertSize.small, + Priority.LOW, VisualAlert.none, AudibleAlert.none, .0, .1, .1, alert_rate=0.25), + }, + + # timebomb + EventName.timebombWarn: { + ET.WARNING: Alert( + _("WARNING"), + _("Grab wheel to start bypass"), + AlertStatus.normal, AlertSize.mid, + Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3.), + }, + + EventName.timebombBypassing: { + ET.WARNING: Alert( + _("BYPASSING"), + _("HOLD WHEEL"), + AlertStatus.normal, AlertSize.mid, + Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3.), + }, + + EventName.timebombBypassed: { + ET.WARNING: Alert( + _("Bypassed!"), + _("Release wheel when ready"), + AlertStatus.normal, AlertSize.mid, + Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, 3., 2., 3.), + }, } diff --git a/selfdrive/controls/lib/lane_planner.py b/selfdrive/controls/lib/lane_planner.py index 0c55e101d..a2f5c0c4c 100644 --- a/selfdrive/controls/lib/lane_planner.py +++ b/selfdrive/controls/lib/lane_planner.py @@ -41,6 +41,18 @@ class LanePlanner: self.camera_offset = -CAMERA_OFFSET if wide_camera else CAMERA_OFFSET self.path_offset = -PATH_OFFSET if wide_camera else PATH_OFFSET + self.dp_camera_offset = None + self.dp_path_offset = None + + def update_dp_set_offsets(self, camera_offset, path_offset): + if self.dp_camera_offset != camera_offset: + self.dp_camera_offset = camera_offset + self.camera_offset = camera_offset / 100 + + if self.dp_path_offset != path_offset: + self.dp_path_offset = path_offset + self.path_offset = path_offset / 100 + def parse_model(self, md): if len(md.laneLines) == 4 and len(md.laneLines[0].t) == TRAJECTORY_SIZE: self.ll_t = (np.array(md.laneLines[1].t) + np.array(md.laneLines[2].t))/2 diff --git a/selfdrive/controls/lib/lateral_planner.py b/selfdrive/controls/lib/lateral_planner.py index f92c6c5e9..e88fbde11 100644 --- a/selfdrive/controls/lib/lateral_planner.py +++ b/selfdrive/controls/lib/lateral_planner.py @@ -67,6 +67,13 @@ class LateralPlanner(): self.t_idxs = np.arange(TRAJECTORY_SIZE) self.y_pts = np.zeros(TRAJECTORY_SIZE) + # dp + self.dp_lc_auto_allowed = False + self.dp_lc_auto_timer = None + self.dp_lc_auto_delay = 2. + self.dp_lc_auto_cont = False + self.dp_lc_auto_completed = False + def setup_mpc(self): self.libmpc = libmpc_py.libmpc self.libmpc.init() @@ -87,6 +94,7 @@ class LateralPlanner(): v_ego = sm['carState'].vEgo active = sm['controlsState'].active measured_curvature = sm['controlsState'].curvature + self.LP.update_dp_set_offsets(sm['dragonConf'].dpCameraOffset, sm['dragonConf'].dpPathOffset) md = sm['modelV2'] self.LP.parse_model(sm['modelV2']) @@ -99,7 +107,7 @@ class LateralPlanner(): # 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 < (sm['dragonConf'].dpLcMinMph * CV.MPH_TO_MS) if (not active) or (self.lane_change_timer > LANE_CHANGE_TIME_MAX): self.lane_change_state = LaneChangeState.off @@ -110,6 +118,20 @@ class LateralPlanner(): self.lane_change_state = LaneChangeState.preLaneChange self.lane_change_ll_prob = 1.0 + # dp alc + cur_time = sec_since_boot() + if not below_lane_change_speed and sm['dragonConf'].dpLateralMode == 2 and v_ego >= (sm['dragonConf'].dpLcAutoMinMph * CV.MPH_TO_MS): + # we allow auto lc when speed reached dragon_auto_lc_min_mph + self.dp_lc_auto_allowed = True + else: + # if too slow, we reset all the variables + self.dp_lc_auto_allowed = False + self.dp_lc_auto_timer = None + + # disable auto lc when continuous is off and already did auto lc once + if self.dp_lc_auto_allowed and not sm['dragonConf'].dpLcAutoCont and self.dp_lc_auto_completed: + self.dp_lc_auto_allowed = False + # LaneChangeState.preLaneChange elif self.lane_change_state == LaneChangeState.preLaneChange: # Set lane change direction @@ -127,6 +149,19 @@ class LateralPlanner(): blindspot_detected = ((sm['carState'].leftBlindspot and self.lane_change_direction == LaneChangeDirection.left) or (sm['carState'].rightBlindspot and self.lane_change_direction == LaneChangeDirection.right)) + # dp alc + if self.dp_lc_auto_allowed: + if self.dp_lc_auto_timer is None: + self.dp_lc_auto_timer = cur_time + sm['dragonConf'].dpLcAutoDelay + elif cur_time >= self.dp_lc_auto_timer: + # if timer is up, we set torque_applied to True to fake user input + torque_applied = True + self.dp_lc_auto_completed = True + + # we reset the timers when torque is applied regardless + if torque_applied and not blindspot_detected: + self.dp_lc_auto_timer = None + if not one_blinker or below_lane_change_speed: self.lane_change_state = LaneChangeState.off elif torque_applied and not blindspot_detected: @@ -151,11 +186,17 @@ class LateralPlanner(): elif self.lane_change_ll_prob > 0.99: self.lane_change_state = LaneChangeState.off + # dp when finishing, we reset timer to none. + self.dp_lc_auto_timer = None + if self.lane_change_state in [LaneChangeState.off, LaneChangeState.preLaneChange]: self.lane_change_timer = 0.0 else: self.lane_change_timer += DT_MDL + if self.prev_one_blinker and not one_blinker: + self.dp_lc_auto_completed = False + self.prev_one_blinker = one_blinker self.desire = DESIRES[self.lane_change_direction][self.lane_change_state] @@ -231,7 +272,7 @@ class LateralPlanner(): def publish(self, sm, pm): plan_solution_valid = self.solution_invalid_cnt < 2 plan_send = messaging.new_message('lateralPlan') - plan_send.valid = sm.all_alive_and_valid(service_list=['carState', 'controlsState', 'modelV2']) + plan_send.valid = sm.all_alive_and_valid(service_list=['carState', 'controlsState', 'modelV2', 'dragonConf']) plan_send.lateralPlan.laneWidth = float(self.LP.lane_width) plan_send.lateralPlan.dPathPoints = [float(x) for x in self.y_pts] plan_send.lateralPlan.lProb = float(self.LP.lll_prob) @@ -248,6 +289,7 @@ class LateralPlanner(): plan_send.lateralPlan.desire = self.desire plan_send.lateralPlan.laneChangeState = self.lane_change_state plan_send.lateralPlan.laneChangeDirection = self.lane_change_direction + plan_send.lateralPlan.dpALCAllowed = self.dp_lc_auto_allowed pm.send('lateralPlan', plan_send) diff --git a/selfdrive/controls/lib/long_mpc.py b/selfdrive/controls/lib/long_mpc.py index 0e51d521d..44a688aff 100644 --- a/selfdrive/controls/lib/long_mpc.py +++ b/selfdrive/controls/lib/long_mpc.py @@ -59,7 +59,7 @@ class LongitudinalMpc(): self.cur_state[0].v_ego = v self.cur_state[0].a_ego = a - def update(self, CS, lead): + def update(self, CS, lead, dp_following_distance=1.8): v_ego = CS.vEgo # Setup current mpc state @@ -94,7 +94,7 @@ class LongitudinalMpc(): # Calculate mpc t = sec_since_boot() - self.n_its = self.libmpc.run_mpc(self.cur_state, self.mpc_solution, self.a_lead_tau, a_lead) + self.n_its = self.libmpc.run_mpc(self.cur_state, self.mpc_solution, self.a_lead_tau, a_lead, dp_following_distance) self.duration = int((sec_since_boot() - t) * 1e9) # Get solution. MPC timestep is 0.2 s, so interpolation to 0.05 s is needed 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/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 2f18a753c..b8a4fba02 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -32,6 +32,49 @@ _A_CRUISE_MAX_BP = [0., 6.4, 22.5, 40.] _A_TOTAL_MAX_V = [1.7, 3.2] _A_TOTAL_MAX_BP = [20., 40.] +# dp +DP_FOLLOWING_DIST = { + 0: 1.8, + 1: 1.5, + 2: 1.2, +} + +DP_ACCEL_ECO = 0 +DP_ACCEL_NORMAL = 1 +DP_ACCEL_SPORT = 2 + +# accel profile by @arne182 +_DP_CRUISE_MIN_V = [-2.0, -1.5, -1.0, -0.7, -0.5] +_DP_CRUISE_MIN_V_ECO = [-1.0, -0.7, -0.6, -0.5, -0.3] +_DP_CRUISE_MIN_V_SPORT = [-3.0, -2.6, -2.3, -2.0, -1.0] +_DP_CRUISE_MIN_V_FOLLOWING = [-4.0, -4.0, -3.5, -2.5, -2.0] +_DP_CRUISE_MIN_BP = [0.0, 5.0, 10.0, 20.0, 55.0] + +_DP_CRUISE_MAX_V = [2.0, 2.0, 1.5, .5, .3] +_DP_CRUISE_MAX_V_ECO = [0.8, 0.9, 1.0, 0.4, 0.2] +_DP_CRUISE_MAX_V_SPORT = [3.0, 3.5, 3.0, 2.0, 2.0] +_DP_CRUISE_MAX_V_FOLLOWING = [1.6, 1.4, 1.4, .7, .3] +_DP_CRUISE_MAX_BP = [0., 5., 10., 20., 55.] + +# Lookup table for turns +_DP_TOTAL_MAX_V = [3.3, 3.0, 3.9] +_DP_TOTAL_MAX_BP = [0., 25., 55.] + +def dp_calc_cruise_accel_limits(v_ego, following, dp_profile): + if following: + a_cruise_min = interp(v_ego, _DP_CRUISE_MIN_BP, _DP_CRUISE_MIN_V_FOLLOWING) + a_cruise_max = interp(v_ego, _DP_CRUISE_MAX_BP, _DP_CRUISE_MAX_V_FOLLOWING) + else: + if dp_profile == DP_ACCEL_ECO: + a_cruise_min = interp(v_ego, _DP_CRUISE_MIN_BP, _DP_CRUISE_MIN_V_ECO) + a_cruise_max = interp(v_ego, _DP_CRUISE_MAX_BP, _DP_CRUISE_MAX_V_ECO) + elif dp_profile == DP_ACCEL_SPORT: + a_cruise_min = interp(v_ego, _DP_CRUISE_MIN_BP, _DP_CRUISE_MIN_V_SPORT) + a_cruise_max = interp(v_ego, _DP_CRUISE_MAX_BP, _DP_CRUISE_MAX_V_SPORT) + else: + a_cruise_min = interp(v_ego, _DP_CRUISE_MIN_BP, _DP_CRUISE_MIN_V) + a_cruise_max = interp(v_ego, _DP_CRUISE_MAX_BP, _DP_CRUISE_MAX_V) + return np.vstack([a_cruise_min, a_cruise_max]) def calc_cruise_accel_limits(v_ego, following): a_cruise_min = interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V) @@ -83,6 +126,13 @@ class Planner(): self.params = Params() self.first_loop = True + # dp + self.dp_accel_profile_ctrl = False + self.dp_accel_profile = DP_ACCEL_ECO + self.dp_following_profile_ctrl = False + self.dp_following_profile = 0 + self.dp_following_dist = 1.8 # default val + def choose_solution(self, v_cruise_setpoint, enabled): if enabled: solutions = {'cruise': self.v_cruise} @@ -128,9 +178,21 @@ class Planner(): self.v_acc_start = self.v_acc_next self.a_acc_start = self.a_acc_next + # dp + self.dp_accel_profile_ctrl = sm['dragonConf'].dpAccelProfileCtrl + self.dp_accel_profile = sm['dragonConf'].dpAccelProfile + self.dp_following_profile_ctrl = sm['dragonConf'].dpAccelProfileCtrl + self.dp_following_profile = sm['dragonConf'].dpFollowingProfile + self.dp_following_dist = DP_FOLLOWING_DIST[0 if not self.dp_following_profile_ctrl else self.dp_following_profile] + + # dp - slow on curve from 0.7.6.1 # Calculate speed for normal cruise control - if enabled and not self.first_loop and not sm['carState'].gasPressed: - accel_limits = [float(x) for x in calc_cruise_accel_limits(v_ego, following)] + pedal_pressed = sm['carState'].gasPressed or sm['carState'].brakePressed + if enabled and not self.first_loop and not pedal_pressed: + if not self.dp_accel_profile_ctrl: + accel_limits = [float(x) for x in calc_cruise_accel_limits(v_ego, following)] + else: + accel_limits = [float(x) for x in dp_calc_cruise_accel_limits(v_ego, following, self.dp_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'].steeringAngleDeg, accel_limits, self.CP) @@ -158,12 +220,15 @@ class Planner(): self.a_acc_start = reset_accel self.v_cruise = reset_speed self.a_cruise = reset_accel + # dp reset + self.v_model = reset_speed + self.a_model = reset_accel self.mpc1.set_cur_state(self.v_acc_start, self.a_acc_start) self.mpc2.set_cur_state(self.v_acc_start, self.a_acc_start) - self.mpc1.update(sm['carState'], lead_1) - self.mpc2.update(sm['carState'], lead_2) + self.mpc1.update(sm['carState'], lead_1, self.dp_following_dist) + self.mpc2.update(sm['carState'], lead_2, self.dp_following_dist) self.choose_solution(v_cruise_setpoint, enabled) diff --git a/selfdrive/controls/lib/vehicle_model.py b/selfdrive/controls/lib/vehicle_model.py index a0b1dddfd..ae6ada314 100755 --- a/selfdrive/controls/lib/vehicle_model.py +++ b/selfdrive/controls/lib/vehicle_model.py @@ -18,6 +18,7 @@ import numpy as np from numpy.linalg import solve from cereal import car +from common.params import Params class VehicleModel: def __init__(self, CP: car.CarParams): diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index 235bafc41..a73699f69 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -26,7 +26,7 @@ def plannerd_thread(sm=None, pm=None): lateral_planner = LateralPlanner(CP, use_lanelines=use_lanelines, wide_camera=wide_camera) if sm is None: - sm = messaging.SubMaster(['carState', 'controlsState', 'radarState', 'modelV2'], + sm = messaging.SubMaster(['carState', 'controlsState', 'radarState', 'modelV2', 'dragonConf'], poll=['radarState', 'modelV2'], ignore_avg_freq=['radarState']) if pm is None: diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index 244d02d23..c8026af07 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -199,7 +199,7 @@ def radard_thread(sm=None, pm=None, can_sock=None): RD = RadarD(CP.radarTimeStep, RI.delay) # TODO: always log leads once we can hide them conditionally - enable_lead = CP.openpilotLongitudinalControl or not CP.radarOffCan + enable_lead = True #CP.openpilotLongitudinalControl or not CP.radarOffCan while 1: can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True) diff --git a/selfdrive/crash.py b/selfdrive/crash.py index f85d7c0e6..7edc25258 100644 --- a/selfdrive/crash.py +++ b/selfdrive/crash.py @@ -22,6 +22,6 @@ def bind_extra(**kwargs) -> None: sentry_sdk.set_tag(k, v) def init() -> None: - sentry_sdk.init("https://a8dc76b5bfb34908a601d67e2aa8bcf9@o33823.ingest.sentry.io/77924", + sentry_sdk.init("https://980a0cba712a4c3593c33c78a12446e1:fecab286bcaf4dba8b04f7cff0188e2d@sentry.io/1488600", default_integrations=False, integrations=[ThreadingIntegration(propagate_hub=True)], release=version) diff --git a/selfdrive/dragonpilot/HOWTO-APPD.md b/selfdrive/dragonpilot/HOWTO-APPD.md new file mode 100644 index 000000000..2a105088a --- /dev/null +++ b/selfdrive/dragonpilot/HOWTO-APPD.md @@ -0,0 +1,10 @@ +What is appd +------ +Appd is a service that runs specific android apps when on road, and then close the when offroad. + +How to use appd +------ +1. Create a folder: /sdcard/appd/ +2. Place apks in /sdcard/appd/ +3. Copy /data/openpilot/dragonpilot/appd_example.json over to /sdcard/appd/ and rename to appd.json +4. Update appd.json as per example. \ No newline at end of file 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.py b/selfdrive/dragonpilot/appd.py new file mode 100644 index 000000000..245bc217a --- /dev/null +++ b/selfdrive/dragonpilot/appd.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3.8 +import subprocess +import os +import json + +FILE = '/sdcard/appd/appd.json' + +class Appd(): + + def __init__(self): + self.started = False + + if os.path.exists(FILE): + with open(FILE) as f: + self.app_data = json.load(f) + else: + self.app_data = None + + def run(self, started): + if self.app_data is not None: + if started: + if not self.started: + self.started = True + self.onroad() + else: + if self.started: + self.started = False + self.offroad() + + def onroad(self): + for app in self.app_data: + if not self.installed(app['app']) and os.path.exists(app['apk']): + self.system("pm install -r %s" % app['apk']) + for cmd in app['onroad_cmd']: + self.system(cmd) + + def offroad(self): + for app in self.app_data: + if self.installed(app['app']): + for cmd in app['offroad_cmd']: + self.system(cmd) + + def installed(self, app_name): + try: + result = subprocess.check_output(["dumpsys", "package", app_name, "|", "grep", "versionName"], encoding='utf8') + if len(result) > 12: + return True + except: + pass + return False + + def system(self, cmd): + try: + subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) + except: + pass \ No newline at end of file diff --git a/selfdrive/dragonpilot/appd_example.json b/selfdrive/dragonpilot/appd_example.json new file mode 100644 index 000000000..5e8f4cdb6 --- /dev/null +++ b/selfdrive/dragonpilot/appd_example.json @@ -0,0 +1,28 @@ +[ + { + "app": "lan.rick.pandagpsservice", + "apk": "/sdcard/appd/lan.rick.pandagpsservice.apk", + "offroad_cmd": [ + "pkill lan.rick.pandagpsservice", + "LD_LIBRARY_PATH= appops set lan.rick.pandagpsservice android:mock_location deny" + ], + "onroad_cmd": [ + "LD_LIBRARY_PATH= appops set lan.rick.pandagpsservice android:mock_location allow", + "am startservice lan.rick.pandagpsservice/lan.rick.pandagpsservice.MainService" + ] + }, + { + "app": "com.tomtom.speedcams.android.map", + "apk": "/sdcard/appd/com.tomtom.speedcams.android.map.apk", + "offroad_cmd": [ + "pkill com.tomtom.speedcams.android.map" + ], + "onroad_cmd": [ + "LD_LIBRARY_PATH= appops set com.tomtom.speedcams.android.map android.permission.ACCESS_FINE_LOCATION allow", + "LD_LIBRARY_PATH= appops set com.tomtom.speedcams.android.map android.permission.ACCESS_COARSE_LOCATION allow", + "LD_LIBRARY_PATH= appops set com.tomtom.speedcams.android.map android.permission.READ_EXTERNAL_STORAGE allow", + "LD_LIBRARY_PATH= appops set com.tomtom.speedcams.android.map android.permission.WRITE_EXTERNAL_STORAGE allow", + "am start -n com.tomtom.speedcams.android.map/com.tomtom.speedcams.android.activities.SpeedCamActivity" + ] + } +] \ No newline at end of file diff --git a/selfdrive/dragonpilot/dashcamd.py b/selfdrive/dragonpilot/dashcamd.py new file mode 100644 index 000000000..3f0fa4f2a --- /dev/null +++ b/selfdrive/dragonpilot/dashcamd.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3.7 +import os +import datetime +from common.realtime import sec_since_boot + +DASHCAM_VIDEOS_PATH = '/sdcard/dashcam/' +DASHCAM_DURATION = 180 # max is 180 +DASHCAM_BIT_RATES = 4000000 # max is 4000000 +DASHCAM_MAX_SIZE_PER_FILE = DASHCAM_BIT_RATES/8*DASHCAM_DURATION # 4Mbps / 8 * 180 = 90MB per 180 seconds +DASHCAM_FREESPACE_LIMIT = 15 # we start cleaning up footage when freespace is below 15% +DASHCAM_KEPT = DASHCAM_MAX_SIZE_PER_FILE * 240 # 12 hrs of video = 21GB + +class Dashcamd(): + def __init__(self): + self.dashcam_folder_exists = False + self.dashcam_mkdir_retry = 0 + self.dashcam_next_time = 0 + self.started = False + self.free_space_percent = 100 + + def run(self, started, free_space_percent): + self.started = started + self.free_space_percent = free_space_percent + self.make_folder() + if self.dashcam_folder_exists: + self.record() + self.clean_up() + + def stop(self): + os.system("killall -SIGINT screenrecord") + self.dashcam_next_time = 0 + + def make_folder(self): + if not self.dashcam_folder_exists and self.dashcam_mkdir_retry <= 5: + # create dashcam folder if not exist + try: + if not os.path.exists(DASHCAM_VIDEOS_PATH): + os.makedirs(DASHCAM_VIDEOS_PATH) + else: + self.dashcam_folder_exists = True + except OSError: + self.dashcam_folder_exists = False + self.dashcam_mkdir_retry += 1 + + def record(self): + # start recording + if self.started: + ts = sec_since_boot() + if ts >= self.dashcam_next_time: + now = datetime.datetime.now() + file_name = now.strftime("%Y-%m-%d_%H-%M-%S") + os.system("LD_LIBRARY_PATH= screenrecord --bit-rate %s --time-limit %s %s%s.mp4 &" % (DASHCAM_BIT_RATES, DASHCAM_DURATION, DASHCAM_VIDEOS_PATH, file_name)) + self.dashcam_next_time = ts + DASHCAM_DURATION - 1 + else: + self.dashcam_next_time = 0 + + def clean_up(self): + # clean up + if (self.free_space_percent < DASHCAM_FREESPACE_LIMIT) or (self.get_used_spaces() > DASHCAM_KEPT): + try: + files = [f for f in sorted(os.listdir(DASHCAM_VIDEOS_PATH)) if os.path.isfile(DASHCAM_VIDEOS_PATH + f)] + os.system("rm -fr %s &" % (DASHCAM_VIDEOS_PATH + files[0])) + except (IndexError, FileNotFoundError, OSError): + pass + + def get_used_spaces(self): + try: + val = sum(os.path.getsize(DASHCAM_VIDEOS_PATH + f) for f in os.listdir(DASHCAM_VIDEOS_PATH) if os.path.isfile(DASHCAM_VIDEOS_PATH + f)) + except (IndexError, FileNotFoundError, OSError): + val = 0 + return val diff --git a/selfdrive/dragonpilot/gpxd.py b/selfdrive/dragonpilot/gpxd.py new file mode 100644 index 000000000..0bc1406a1 --- /dev/null +++ b/selfdrive/dragonpilot/gpxd.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3.7 +''' +GPS cord converter: https://gist.github.com/jp1017/71bd0976287ce163c11a7cb963b04dd8 +''' +import cereal.messaging as messaging +import os +import time +import datetime +import signal +import threading +import math +import zipfile + +pi = 3.1415926535897932384626 +x_pi = 3.14159265358979324 * 3000.0 / 180.0 +a = 6378245.0 +ee = 0.00669342162296594323 + +GPX_LOG_PATH = '/sdcard/gpx_logs/' + +LOG_DELAY = 0.1 # secs, lower for higher accuracy, 0.1 seems fine +LOG_LENGTH = 60 # mins, higher means it keeps more data in the memory, will take more time to write into a file too. +LOST_SIGNAL_COUNT_LENGTH = 30 # secs, if we lost signal for this long, perform output to data +MIN_MOVE_SPEED_KMH = 5 # km/h, min speed to trigger logging + +# do not change +LOST_SIGNAL_COUNT_MAX = LOST_SIGNAL_COUNT_LENGTH / LOG_DELAY # secs, +LOGS_PER_FILE = LOG_LENGTH * 60 / LOG_DELAY # e.g. 3 * 60 / 0.1 = 1800 points per file +MIN_MOVE_SPEED_MS = MIN_MOVE_SPEED_KMH / 3.6 + +class WaitTimeHelper: + ready_event = threading.Event() + shutdown = False + + def __init__(self): + signal.signal(signal.SIGTERM, self.graceful_shutdown) + signal.signal(signal.SIGINT, self.graceful_shutdown) + signal.signal(signal.SIGHUP, self.graceful_shutdown) + + def graceful_shutdown(self, signum, frame): + self.shutdown = True + self.ready_event.set() + +def main(): + # init + sm = messaging.SubMaster(['gpsLocationExternal']) + log_count = 0 + logs = list() + lost_signal_count = 0 + wait_helper = WaitTimeHelper() + started_time = datetime.datetime.utcnow().isoformat() + # outside_china_checked = False + # outside_china = False + while True: + sm.update() + if sm.updated['gpsLocationExternal']: + gps = sm['gpsLocationExternal'] + + # do not log when no fix or accuracy is too low, add lost_signal_count + if gps.flags % 2 == 0 or gps.accuracy > 5.: + if log_count > 0: + lost_signal_count += 1 + else: + lng = gps.longitude + lat = gps.latitude + # if not outside_china_checked: + # outside_china = out_of_china(lng, lat) + # outside_china_checked = True + # if not outside_china: + # lng, lat = wgs84togcj02(lng, lat) + logs.append([datetime.datetime.utcfromtimestamp(gps.timestamp*0.001).isoformat(), lat, lng, gps.altitude]) + log_count += 1 + lost_signal_count = 0 + ''' + write to log if + 1. reach per file limit + 2. lost signal for a certain time (e.g. under cover car park?) + ''' + if log_count > 0 and (log_count >= LOGS_PER_FILE or lost_signal_count >= LOST_SIGNAL_COUNT_MAX): + # output + to_gpx(logs, started_time) + lost_signal_count = 0 + log_count = 0 + logs.clear() + started_time = datetime.datetime.utcnow().isoformat() + + time.sleep(LOG_DELAY) + if wait_helper.shutdown: + break + # when process end, we store any logs. + if log_count > 0: + to_gpx(logs, started_time) + +''' +check to see if it's in china +''' +def out_of_china(lng, lat): + if lng < 72.004 or lng > 137.8347: + return True + elif lat < 0.8293 or lat > 55.8271: + return True + return False + +def transform_lat(lng, lat): + ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * math.sqrt(abs(lng)) + ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 * math.sin(2.0 * lng * pi)) * 2.0 / 3.0 + ret += (20.0 * math.sin(lat * pi) + 40.0 * math.sin(lat / 3.0 * pi)) * 2.0 / 3.0 + ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 * math.sin(lat * pi / 30.0)) * 2.0 / 3.0 + return ret + +def transform_lng(lng, lat): + ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * math.sqrt(abs(lng)) + ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 * math.sin(2.0 * lng * pi)) * 2.0 / 3.0 + ret += (20.0 * math.sin(lng * pi) + 40.0 * math.sin(lng / 3.0 * pi)) * 2.0 / 3.0 + ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 * math.sin(lng / 30.0 * pi)) * 2.0 / 3.0 + return ret + +''' +Convert wgs84 to gcj02 ( +''' +def wgs84togcj02(lng, lat): + if out_of_china(lng, lat): + return lng, lat + dlat = transform_lat(lng - 105.0, lat - 35.0) + dlng = transform_lng(lng - 105.0, lat - 35.0) + radlat = lat / 180.0 * pi + magic = math.sin(radlat) + magic = 1 - ee * magic * magic + sqrtmagic = math.sqrt(magic) + dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi) + dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi) + mglat = lat + dlat + mglng = lng + dlng + return mglng, mglat + +''' +write logs to a gpx file and zip it +''' +def to_gpx(logs, timestamp): + if len(logs) > 0: + if not os.path.exists(GPX_LOG_PATH): + os.makedirs(GPX_LOG_PATH) + filename = timestamp.replace(':','-') + str = '' + str += "\n" + str += "\n" + str += "\t\n" + str += "\t\t\n" + for trkpt in logs: + str += "\t\t\t\n" % (trkpt[0], trkpt[1], trkpt[2], trkpt[3]) + str += "\t\t\n" + str += "\t\n" + str += "\n" + try: + zi = zipfile.ZipInfo('%sZ.gpx' % filename, time.localtime()) + zi.compress_type = zipfile.ZIP_DEFLATED + zf = zipfile.ZipFile('%s%sZ.zip' % (GPX_LOG_PATH, filename), mode='w') + zf.writestr(zi, str) + zf.close() + except: + pass + +if __name__ == "__main__": + main() diff --git a/selfdrive/dragonpilot/systemd.py b/selfdrive/dragonpilot/systemd.py new file mode 100644 index 000000000..ce3cc8df3 --- /dev/null +++ b/selfdrive/dragonpilot/systemd.py @@ -0,0 +1,296 @@ +#!/usr/bin/env python3 +''' +This is a service that broadcast dp config values to openpilot's messaging queues +''' +import cereal.messaging as messaging +import time + +from common.dp_conf import confs, get_struct_name, to_struct_val +from common.params import Params, put_nonblocking +import subprocess +import re +import os +from selfdrive.hardware import HARDWARE +params = Params() +from common.realtime import sec_since_boot +from common.i18n import get_locale +from common.dp_common import param_get, get_last_modified +from common.dp_time import LAST_MODIFIED_SYSTEMD +from selfdrive.dragonpilot.dashcamd import Dashcamd +from selfdrive.dragonpilot.appd import Appd +from selfdrive.hardware import EON + +PARAM_PATH = params.get_params_path() + '/d/' + +DELAY = 0.5 # 2hz +HERTZ = 1/DELAY + +last_modified_confs = {} + +def confd_thread(): + sm = messaging.SubMaster(['deviceState']) + pm = messaging.PubMaster(['dragonConf']) + + last_dp_msg = None + frame = 0 + update_params = False + modified = None + last_modified = None + last_modified_check = None + started = False + free_space = 1 + battery_percent = 0 + overheat = False + last_charging_ctrl = False + last_started = False + dashcamd = Dashcamd() + appd = Appd() + dashcam_recorded = False + last_dashcam_recorded = False + + while True: + start_sec = sec_since_boot() + msg = messaging.new_message('dragonConf') + if last_dp_msg is not None: + msg.dragonConf = last_dp_msg + + ''' + =================================================== + load thermald data every 3 seconds + =================================================== + ''' + if frame % (HERTZ * 3) == 0: + started, free_space, battery_percent, overheat = pull_thermald(frame, sm, started, free_space, battery_percent, overheat) + setattr(msg.dragonConf, get_struct_name('dp_thermal_started'), started) + setattr(msg.dragonConf, get_struct_name('dp_thermal_overheat'), overheat) + ''' + =================================================== + hotspot on boot + we do it after 30 secs just in case + =================================================== + ''' + if frame == (HERTZ * 30) and param_get("dp_hotspot_on_boot", "bool", False): + os.system("service call wifi 37 i32 0 i32 1 &") + ''' + =================================================== + check dp_last_modified every second + =================================================== + ''' + if not update_params: + last_modified_check, modified = get_last_modified(LAST_MODIFIED_SYSTEMD, last_modified_check, modified) + if last_modified != modified: + update_params = True + last_modified = modified + ''' + =================================================== + conditionally set update_params to true + =================================================== + ''' + # force updating param when `started` changed + if last_started != started: + update_params = True + + if frame == 0: + update_params = True + ''' + =================================================== + conditionally update dp param base on stock param + =================================================== + ''' + # if update_params and params.get("LaneChangeEnabled") == b"1": + # params.put("dp_steering_on_signal", "0") + ''' + =================================================== + push param vals to message + =================================================== + ''' + if update_params: + msg = update_conf_all(confs, msg, frame == 0) + update_params = False + ''' + =================================================== + push once + =================================================== + ''' + if frame == 0: + setattr(msg.dragonConf, get_struct_name('dp_locale'), get_locale()) + if (not os.path.isfile("/data/params/d/GithubSshKeys") or params.get("GithubSshKeys") == '') and \ + os.path.isfile("/data/data/com.termux/files/home/setup_keys"): + os.system("cp /data/data/com.termux/files/home/setup_keys /data/params/d/GithubSshKeys") + + ''' + =================================================== + push ip addr every 10 secs + =================================================== + ''' + if frame % (HERTZ * 10) == 0: + msg = update_ip(msg) + ''' + =================================================== + update msg based on some custom logic + =================================================== + ''' + msg = update_custom_logic(msg) + ''' + =================================================== + battery ctrl every 30 secs + PowerMonitor in thermald turns back on every mins + so lets turn it off more frequent + =================================================== + ''' + # if frame % (HERTZ * 30) == 0: + # last_charging_ctrl = process_charging_ctrl(msg, last_charging_ctrl, battery_percent) + ''' + =================================================== + dashcam + =================================================== + ''' + if msg.dragonConf.dpDashcamd: + if frame % HERTZ == 0: + dashcamd.run(started, free_space) + dashcam_recorded = True + if not started: + dashcam_recorded = False + else: + dashcam_recorded = False + + if not dashcam_recorded and last_dashcam_recorded: + dashcamd.stop() + + last_dashcam_recorded = dashcam_recorded + ''' + =================================================== + appd + =================================================== + ''' + if msg.dragonConf.dpAppd: + appd.run(started) + ''' + =================================================== + finalise + =================================================== + ''' + last_dp_msg = msg.dragonConf + last_started = started + pm.send('dragonConf', msg) + frame += 1 + sleep = DELAY-(sec_since_boot() - start_sec) + if sleep > 0: + time.sleep(sleep) + +def update_conf(msg, conf, first_run = False): + conf_type = conf.get('conf_type') + + # skip checking since modified date time hasn't been changed. + if (last_modified_confs.get(conf['name'])) is not None and last_modified_confs.get(conf['name']) == os.stat(PARAM_PATH + conf['name']).st_mtime: + return msg + + if 'param' in conf_type and 'struct' in conf_type: + update_this_conf = True + + if not first_run: + update_once = conf.get('update_once') + if update_once is not None and update_once is True: + return msg + if update_this_conf: + update_this_conf = check_dependencies(msg, conf) + + if update_this_conf: + msg = set_message(msg, conf) + if os.path.isfile(PARAM_PATH + conf['name']): + last_modified_confs[conf['name']] = os.stat(PARAM_PATH + conf['name']).st_mtime + return msg + +def update_conf_all(confs, msg, first_run = False): + for conf in confs: + msg = update_conf(msg, conf, first_run) + return msg + +def process_charging_ctrl(msg, last_charging_ctrl, battery_percent): + charging_ctrl = msg.dragonConf.dpChargingCtrl + if last_charging_ctrl != charging_ctrl: + HARDWARE.set_battery_charging(True) + if charging_ctrl: + if battery_percent >= msg.dragonConf.dpDischargingAt and HARDWARE.get_battery_charging(): + HARDWARE.set_battery_charging(False) + elif battery_percent <= msg.dragonConf.dpChargingAt and not HARDWARE.get_battery_charging(): + HARDWARE.set_battery_charging(True) + return charging_ctrl + + +def pull_thermald(frame, sm, started, free_space, battery_percent, overheat): + sm.update(0) + if sm.updated['deviceState']: + started = sm['deviceState'].started + free_space = sm['deviceState'].freeSpacePercent + battery_percent = sm['deviceState'].batteryPercent + overheat = sm['deviceState'].thermalStatus >= 2 + return started, free_space, battery_percent, overheat + +def update_custom_logic(msg): + if msg.dragonConf.dpAtl: + msg.dragonConf.dpAllowGas = True + msg.dragonConf.dpFollowingProfileCtrl = False + msg.dragonConf.dpAccelProfileCtrl = False + msg.dragonConf.dpGearCheck = False + if msg.dragonConf.dpLcMinMph > msg.dragonConf.dpLcAutoMinMph: + put_nonblocking('dp_lc_auto_min_mph', str(msg.dragonConf.dpLcMinMph)) + msg.dragonConf.dpLcAutoMinMph = msg.dragonConf.dpLcMinMph + # if msg.dragonConf.dpSrCustom <= 4.99 and msg.dragonConf.dpSrStock > 0: + # put_nonblocking('dp_sr_custom', str(msg.dragonConf.dpSrStock)) + # msg.dragonConf.dpSrCustom = msg.dragonConf.dpSrStock + # if msg.dragonConf.dpAppWaze or msg.dragonConf.dpAppHr: + # msg.dragonConf.dpDrivingUi = False + # if not msg.dragonConf.dpDriverMonitor: + # msg.dragonConf.dpUiFace = False + return msg + + +def update_ip(msg): + val = 'N/A' + if EON: + try: + result = subprocess.check_output(["ifconfig", "wlan0"], encoding='utf8') + val = re.findall(r"inet addr:((\d+\.){3}\d+)", result)[0][0] + except: + pass + setattr(msg.dragonConf, get_struct_name('dp_ip_addr'), val) + return msg + + +def set_message(msg, conf): + val = params.get(conf['name'], encoding='utf8') + if val is not None: + val = val.rstrip('\x00') + else: + val = conf.get('default') + params.put(conf['name'], str(val)) + struct_val = to_struct_val(conf['name'], val) + orig_val = struct_val + if struct_val is not None: + if conf.get('min') is not None: + struct_val = max(struct_val, conf.get('min')) + if conf.get('max') is not None: + struct_val = min(struct_val, conf.get('max')) + if orig_val != struct_val: + params.put(conf['name'], str(struct_val)) + setattr(msg.dragonConf, get_struct_name(conf['name']), struct_val) + return msg + +def check_dependencies(msg, conf): + passed = True + # if has dependency and the depend param val is not in depend_vals, we dont update that conf val + # this should reduce chance of reading unnecessary params + dependencies = conf.get('depends') + if dependencies is not None: + for dependency in dependencies: + if getattr(msg.dragonConf, get_struct_name(dependency['name'])) not in dependency['vals']: + passed = False + break + return passed + +def main(): + confd_thread() + +if __name__ == "__main__": + main() diff --git a/selfdrive/hardware/__init__.py b/selfdrive/hardware/__init__.py index 3babf1bb5..3af462eac 100644 --- a/selfdrive/hardware/__init__.py +++ b/selfdrive/hardware/__init__.py @@ -5,15 +5,19 @@ from selfdrive.hardware.base import HardwareBase from selfdrive.hardware.eon.hardware import Android from selfdrive.hardware.tici.hardware import Tici from selfdrive.hardware.pc.hardware import Pc +from selfdrive.hardware.jetson.hardware import Jetson EON = os.path.isfile('/EON') TICI = os.path.isfile('/TICI') -PC = not (EON or TICI) +JETSON = os.path.isfile('/JETSON') +PC = not (EON or TICI or JETSON) if EON: HARDWARE = cast(HardwareBase, Android()) elif TICI: HARDWARE = cast(HardwareBase, Tici()) +elif JETSON: + HARDWARE = cast(HardwareBase, Jetson()) else: HARDWARE = cast(HardwareBase, Pc()) diff --git a/selfdrive/hardware/base.h b/selfdrive/hardware/base.h index d9ce5c48c..3c6590e25 100644 --- a/selfdrive/hardware/base.h +++ b/selfdrive/hardware/base.h @@ -22,4 +22,5 @@ public: static bool PC() { return false; } static bool EON() { return false; } static bool TICI() { return false; } + static bool JETSON() { return false; } }; diff --git a/selfdrive/hardware/hw.h b/selfdrive/hardware/hw.h index 8112ba1c6..e1a5c8761 100644 --- a/selfdrive/hardware/hw.h +++ b/selfdrive/hardware/hw.h @@ -8,6 +8,9 @@ #elif QCOM2 #include "selfdrive/hardware/tici/hardware.h" #define Hardware HardwareTici +#elif XNX +#include "selfdrive/hardware/jetson/hardware.h" +#define Hardware HardwareJetson #else class HardwarePC : public HardwareNone { public: diff --git a/selfdrive/hardware/jetson/__init__.py b/selfdrive/hardware/jetson/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/selfdrive/hardware/jetson/hardware.h b/selfdrive/hardware/jetson/hardware.h new file mode 100644 index 000000000..bdfeb9517 --- /dev/null +++ b/selfdrive/hardware/jetson/hardware.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "selfdrive/common/util.h" +#include "selfdrive/hardware/base.h" + +class HardwareJetson : public HardwareNone { +public: + + static bool JETSON() { return true; } + + static void reboot() { std::system("sudo reboot"); }; + static void poweroff() { std::system("sudo poweroff"); }; +}; diff --git a/selfdrive/hardware/jetson/hardware.py b/selfdrive/hardware/jetson/hardware.py new file mode 100644 index 000000000..e5ece83cf --- /dev/null +++ b/selfdrive/hardware/jetson/hardware.py @@ -0,0 +1,91 @@ +import random +import os + +from cereal import log +from selfdrive.hardware.base import HardwareBase, ThermalConfig + +NetworkType = log.DeviceState.NetworkType +NetworkStrength = log.DeviceState.NetworkStrength + + +class Jetson(HardwareBase): + + + def get_os_version(self): + return None + + def get_device_type(self): + return "jetson" + + def get_sound_card_online(self): + return True + + def reboot(self, reason=None): + os.system("sudo reboot") + + def uninstall(self): + print("uninstall") + + def get_imei(self, slot): + return "%015d" % random.randint(0, 1 << 32) + + def get_serial(self): + return "cccccccc" + + def get_subscriber_info(self): + return "" + + def get_network_type(self): + return NetworkType.wifi + + def get_sim_info(self): + return { + 'sim_id': '', + 'mcc_mnc': None, + 'network_type': ["Unknown"], + 'sim_state': ["ABSENT"], + 'data_connected': False + } + + def get_network_strength(self, network_type): + return NetworkStrength.unknown + + def get_battery_capacity(self): + return 100 + + def get_battery_status(self): + return "" + + def get_battery_current(self): + return 0 + + def get_battery_voltage(self): + return 0 + + def get_battery_charging(self): + return True + + def set_battery_charging(self, on): + pass + + def get_usb_present(self): + return False + + def get_current_power_draw(self): + return 0 + + def shutdown(self): + os.system("sudo poweroff") + + def get_thermal_config(self): + return ThermalConfig(cpu=((None,), 1), gpu=((None,), 1), mem=(None, 1), bat=(None, 1), ambient=(None, 1)) + + def set_screen_brightness(self, percentage): + pass + + def set_power_save(self, enabled): + if enabled: + os.system("sudo nvpmodel -m 3") + else: + os.system("sudo echo 5000 > /sys/devices/c250000.i2c/i2c-7/7-0040/iio:device0/crit_current_limit_0") + os.system("sudo nvpmodel -m 2 && sudo jetson_clocks") diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py index e297be3ae..9634f2433 100755 --- a/selfdrive/locationd/paramsd.py +++ b/selfdrive/locationd/paramsd.py @@ -87,7 +87,7 @@ def main(sm=None, pm=None): min_sr, max_sr = 0.5 * CP.steerRatio, 2.0 * CP.steerRatio - params = params_reader.get("LiveParameters") + params = params_reader.get("LiveParameters") if not params_reader.get_bool('dp_reset_live_param_on_start') else None # Check if car model matches if params is not None: diff --git a/selfdrive/loggerd/config.py b/selfdrive/loggerd/config.py index 3f82b9f8b..687be3e4d 100644 --- a/selfdrive/loggerd/config.py +++ b/selfdrive/loggerd/config.py @@ -1,10 +1,10 @@ import os from pathlib import Path -from selfdrive.hardware import PC +from selfdrive.hardware import PC, JETSON if os.environ.get('LOGGERD_ROOT', False): ROOT = os.environ['LOGGERD_ROOT'] -elif PC: +elif PC or JETSON: ROOT = os.path.join(str(Path.home()), ".comma", "media", "0", "realdata") else: ROOT = '/data/media/0/realdata/' diff --git a/selfdrive/loggerd/logger.h b/selfdrive/loggerd/logger.h index 7a6524004..dafb61e51 100644 --- a/selfdrive/loggerd/logger.h +++ b/selfdrive/loggerd/logger.h @@ -16,7 +16,7 @@ #include "selfdrive/hardware/hw.h" const std::string LOG_ROOT = - Hardware::PC() ? util::getenv_default("HOME", "/.comma/media/0/realdata", "/data/media/0/realdata") + (Hardware::PC() || Hardware::JETSON()) ? util::getenv_default("HOME", "/.comma/media/0/realdata", "/data/media/0/realdata") : "/data/media/0/realdata"; #define LOGGER_MAX_HANDLES 16 diff --git a/selfdrive/loggerd/loggerd.cc b/selfdrive/loggerd/loggerd.cc index 9a6420590..123474cd9 100644 --- a/selfdrive/loggerd/loggerd.cc +++ b/selfdrive/loggerd/loggerd.cc @@ -357,7 +357,7 @@ int main(int argc, char** argv) { encoder_threads.push_back(std::thread(encoder_thread, LOG_CAMERA_ID_FCAMERA)); s.rotate_state[LOG_CAMERA_ID_FCAMERA].enabled = true; - if (!Hardware::PC() && Params().getBool("RecordFront")) { + if (!Hardware::PC() && !Hardware::JETSON() && Params().getBool("RecordFront")) { encoder_threads.push_back(std::thread(encoder_thread, LOG_CAMERA_ID_DCAMERA)); s.rotate_state[LOG_CAMERA_ID_DCAMERA].enabled = true; } diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py index 9206b4315..649fd5eb6 100644 --- a/selfdrive/loggerd/uploader.py +++ b/selfdrive/loggerd/uploader.py @@ -195,8 +195,7 @@ def uploader_fn(exit_event): dongle_id = params.get("DongleId", encoding='utf8') if dongle_id is None: - cloudlog.info("uploader missing dongle_id") - raise Exception("uploader can't start without dongle id") + return if TICI and not Path("/data/media").is_mount(): cloudlog.warning("NVME not mounted") diff --git a/selfdrive/manager.py b/selfdrive/manager.py new file mode 100755 index 000000000..e69de29bb diff --git a/selfdrive/manager/build.py b/selfdrive/manager/build.py index 5d6f008ef..553f564cf 100755 --- a/selfdrive/manager/build.py +++ b/selfdrive/manager/build.py @@ -5,6 +5,7 @@ import sys import time import textwrap from pathlib import Path +import re # NOTE: Do NOT import anything here that needs be built (e.g. params) from common.basedir import BASEDIR @@ -74,10 +75,16 @@ def build(spinner, dirty=False): add_file_handler(cloudlog) cloudlog.error("scons build failed\n" + error_s) + try: + result = subprocess.check_output(["ifconfig", "wlan0"], encoding='utf8') + ip = re.findall(r"inet addr:((\d+\.){3}\d+)", result)[0][0] + except: + ip = 'N/A' + # Show TextWindow spinner.close() error_s = "\n \n".join(["\n".join(textwrap.wrap(e, 65)) for e in errors]) - with TextWindow("openpilot failed to build\n \n" + error_s) as t: + with TextWindow(("openpilot failed to build (IP: %s)\n \n" % ip) + error_s) as t: t.wait_for_exit() exit(1) else: diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index e97792f7c..4957df71d 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -12,7 +12,7 @@ from common.basedir import BASEDIR from common.params import Params, ParamKeyType from common.text_window import TextWindow from selfdrive.boardd.set_time import set_time -from selfdrive.hardware import HARDWARE, PC, TICI +from selfdrive.hardware import HARDWARE, PC, TICI, EON from selfdrive.manager.helpers import unblock_stdout from selfdrive.manager.process import ensure_running from selfdrive.manager.process_config import managed_processes @@ -21,6 +21,8 @@ from selfdrive.swaglog import cloudlog, add_file_handler from selfdrive.version import dirty, get_git_commit, version, origin, branch, commit, \ terms_version, training_version, comma_remote, \ get_git_branch, get_git_remote +from common.dp_conf import init_params_vals + def manager_init(): @@ -48,6 +50,10 @@ def manager_init(): if params.get(k) is None: params.put(k, v) + # dp init params + init_params_vals(params) + dp_reg = params.get_bool('dp_reg') + # is this dashcam? if os.getenv("PASSIVE") is not None: params.put_bool("Passive", bool(int(os.getenv("PASSIVE")))) @@ -65,6 +71,13 @@ def manager_init(): except PermissionError: print("WARNING: failed to make /dev/shm") + # dp - make sure libmessaging_shared.so is working + if EON: + os.chmod(BASEDIR, 0o755) + os.chmod("/dev/shm", 0o777) + os.chmod(os.path.join(BASEDIR, "cereal"), 0o755) + os.chmod(os.path.join(BASEDIR, "cereal", "libmessaging_shared.so"), 0o755) + # set version params params.put("Version", version) params.put("TermsVersion", terms_version) @@ -111,12 +124,43 @@ def manager_thread(): cloudlog.info("manager start") cloudlog.info({"environ": os.environ}) - # save boot log - subprocess.call("./bootlog", cwd=os.path.join(BASEDIR, "selfdrive/loggerd")) - params = Params() + dp_reg = params.get_bool('dp_reg') + dp_appd = params.get_bool('dp_appd') + dp_updated = params.get_bool('dp_updated') + dp_logger = params.get_bool('dp_logger') + dp_athenad = params.get_bool('dp_athenad') + dp_uploader = params.get_bool('dp_uploader') + dp_dashcamd = params.get_bool('dp_dashcamd') + dp_panda_no_gps = params.get_bool('dp_panda_no_gps') + if params.get_bool('dp_atl'): + dp_reg = False + if not dp_reg: + dp_logger = False + dp_athenad = False + dp_uploader = False + # save boot log + if dp_logger: + subprocess.call("./bootlog", cwd=os.path.join(BASEDIR, "selfdrive/loggerd")) + ignore = [] + if not dp_appd: + ignore += ['appd'] + if dp_panda_no_gps: + ignore += ['ubloxd'] + if not dp_dashcamd: + ignore += ['dashcamd'] + if not dp_updated: + ignore += ['updated'] + if not dp_logger: + ignore += ['logcatd', 'loggerd', 'proclogd', 'logmessaged', 'tombstoned'] + if not dp_athenad: + ignore += ['manage_athenad'] + if not dp_uploader or not dp_reg: + ignore += ['uploader'] + if not dp_athenad and not dp_uploader: + ignore += ['deleter'] if params.get("DongleId", encoding='utf8') == UNREGISTERED_DONGLE_ID: ignore += ["manage_athenad", "uploader"] if os.getenv("NOBOARD") is not None: diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 9ed6d9f87..d6d557239 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -1,29 +1,31 @@ import os from selfdrive.manager.process import PythonProcess, NativeProcess, DaemonProcess -from selfdrive.hardware import EON, TICI, PC +from selfdrive.hardware import EON, TICI, PC, JETSON +from common.params import Params +JETSON = JETSON or Params().get_bool('dp_jetson') WEBCAM = os.getenv("USE_WEBCAM") is not None procs = [ - DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"), + DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid", enabled=not JETSON), # due to qualcomm kernel bugs SIGKILLing camerad sometimes causes page table corruption NativeProcess("camerad", "selfdrive/camerad", ["./camerad"], unkillable=True, driverview=True), NativeProcess("clocksd", "selfdrive/clocksd", ["./clocksd"]), - NativeProcess("dmonitoringmodeld", "selfdrive/modeld", ["./dmonitoringmodeld"], enabled=(not PC or WEBCAM), driverview=True), - NativeProcess("logcatd", "selfdrive/logcatd", ["./logcatd"]), - NativeProcess("loggerd", "selfdrive/loggerd", ["./loggerd"]), + NativeProcess("dmonitoringmodeld", "selfdrive/modeld", ["./dmonitoringmodeld"], enabled=not JETSON and (not PC or WEBCAM), driverview=True), + NativeProcess("logcatd", "selfdrive/logcatd", ["./logcatd"], enabled=not JETSON), + NativeProcess("loggerd", "selfdrive/loggerd", ["./loggerd"], enabled=not JETSON), NativeProcess("modeld", "selfdrive/modeld", ["./modeld"]), - NativeProcess("proclogd", "selfdrive/proclogd", ["./proclogd"]), + NativeProcess("proclogd", "selfdrive/proclogd", ["./proclogd"], enabled=not JETSON), NativeProcess("sensord", "selfdrive/sensord", ["./sensord"], enabled=not PC, persistent=EON, sigkill=EON), - NativeProcess("ubloxd", "selfdrive/locationd", ["./ubloxd"], enabled=(not PC or WEBCAM)), + NativeProcess("ubloxd", "selfdrive/locationd", ["./ubloxd"], enabled=not PC or WEBCAM), NativeProcess("ui", "selfdrive/ui", ["./ui"], persistent=True, watchdog_max_dt=(10 if TICI else None)), NativeProcess("locationd", "selfdrive/locationd", ["./locationd"]), PythonProcess("calibrationd", "selfdrive.locationd.calibrationd"), PythonProcess("controlsd", "selfdrive.controls.controlsd"), PythonProcess("deleter", "selfdrive.loggerd.deleter", persistent=True), - PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", enabled=(not PC or WEBCAM), driverview=True), - PythonProcess("logmessaged", "selfdrive.logmessaged", persistent=True), + PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", enabled=not JETSON and (not PC or WEBCAM), driverview=True), + PythonProcess("logmessaged", "selfdrive.logmessaged", enabled=not JETSON, persistent=True), PythonProcess("pandad", "selfdrive.pandad", persistent=True), PythonProcess("paramsd", "selfdrive.locationd.paramsd"), PythonProcess("plannerd", "selfdrive.controls.plannerd"), @@ -31,9 +33,10 @@ procs = [ PythonProcess("rtshield", "selfdrive.rtshield", enabled=EON), PythonProcess("thermald", "selfdrive.thermald.thermald", persistent=True), PythonProcess("timezoned", "selfdrive.timezoned", enabled=TICI, persistent=True), - PythonProcess("tombstoned", "selfdrive.tombstoned", enabled=not PC, persistent=True), - PythonProcess("updated", "selfdrive.updated", enabled=not PC, persistent=True), - PythonProcess("uploader", "selfdrive.loggerd.uploader", persistent=True), + PythonProcess("tombstoned", "selfdrive.tombstoned", enabled=not PC and not JETSON, persistent=True), + PythonProcess("updated", "selfdrive.updated", enabled=not PC and not JETSON, persistent=True), + PythonProcess("uploader", "selfdrive.loggerd.uploader", enabled=not JETSON, persistent=True), + PythonProcess("systemd", "selfdrive.dragonpilot.systemd", persistent=True), ] managed_processes = {p.name: p for p in procs} diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index a0548ee36..8fed5892d 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -55,6 +55,12 @@ else: del libs[libs.index('symphony-cpu')] del common_src[common_src.index('runners/snpemodel.cc')] + elif arch == "jarch64": + # no SNPE on arm64 linux + del libs[libs.index('SNPE')] + del libs[libs.index('symphony-cpu')] + del common_src[common_src.index('runners/snpemodel.cc')] + common_model = lenv.Object(common_src) # build thneed model diff --git a/selfdrive/modeld/dmonitoringmodeld b/selfdrive/modeld/dmonitoringmodeld index e84bbbf37..87a3c321d 100755 --- a/selfdrive/modeld/dmonitoringmodeld +++ b/selfdrive/modeld/dmonitoringmodeld @@ -8,8 +8,12 @@ if [ -d /system ]; then fi export ADSP_LIBRARY_PATH="/data/pythonpath/phonelibs/snpe/dsp/" else - # PC - export LD_LIBRARY_PATH="$HOME/openpilot/phonelibs/snpe/x86_64-linux-clang:/openpilot/phonelibs/snpe/x86_64:$HOME/openpilot/phonelibs/snpe/x86_64:$LD_LIBRARY_PATH" + if [ -f /JETSON ]; then # Jetson + export LD_LIBRARY_PATH="/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH" + else + # PC + export LD_LIBRARY_PATH="$HOME/openpilot/phonelibs/snpe/x86_64-linux-clang:/openpilot/phonelibs/snpe/x86_64:$HOME/openpilot/phonelibs/snpe/x86_64:$LD_LIBRARY_PATH" + fi fi exec ./_dmonitoringmodeld diff --git a/selfdrive/modeld/modeld b/selfdrive/modeld/modeld index a87221dbd..049b98894 100755 --- a/selfdrive/modeld/modeld +++ b/selfdrive/modeld/modeld @@ -9,7 +9,11 @@ if [ -d /system ]; then export LD_LIBRARY_PATH="/data/pythonpath/phonelibs/snpe/aarch64/:$LD_LIBRARY_PATH" fi else - # PC - export LD_LIBRARY_PATH="$DIR/../../phonelibs/snpe/x86_64-linux-clang:$DIR/../..//openpilot/phonelibs/snpe/x86_64:$LD_LIBRARY_PATH" + if [ -f /JETSON ]; then # Jetson + export LD_LIBRARY_PATH="/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH" + else + # PC + export LD_LIBRARY_PATH="$DIR/../../phonelibs/snpe/x86_64-linux-clang:$DIR/../..//openpilot/phonelibs/snpe/x86_64:$LD_LIBRARY_PATH" + fi fi exec ./_modeld diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc index 0cfed4acd..18fa7d629 100644 --- a/selfdrive/modeld/modeld.cc +++ b/selfdrive/modeld/modeld.cc @@ -139,6 +139,8 @@ int main(int argc, char **argv) { set_core_affinity(2); } else if (Hardware::TICI()) { set_core_affinity(7); + } else if (Hardware::JETSON()) { + set_core_affinity(7); } bool wide_camera = Hardware::TICI() ? Params().getBool("EnableWideCamera") : false; diff --git a/selfdrive/modeld/runners/onnx_runner.py b/selfdrive/modeld/runners/onnx_runner.py new file mode 100755 index 000000000..1ae155bbb --- /dev/null +++ b/selfdrive/modeld/runners/onnx_runner.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import os +import sys +import numpy as np + +os.environ["OMP_NUM_THREADS"] = "4" + +import onnxruntime as ort + +def read(sz): + dd = [] + gt = 0 + while gt < sz * 4: + st = os.read(0, sz * 4 - gt) + assert(len(st) > 0) + dd.append(st) + gt += len(st) + return np.frombuffer(b''.join(dd), dtype=np.float32) + +def write(d): + os.write(1, d.tobytes()) + +def run_loop(m): + ishapes = [[1]+ii.shape[1:] for ii in m.get_inputs()] + keys = [x.name for x in m.get_inputs()] + print("ready to run onnx model", keys, ishapes, file=sys.stderr) + while 1: + inputs = [] + for shp in ishapes: + ts = np.product(shp) + #print("reshaping %s with offset %d" % (str(shp), offset), file=sys.stderr) + inputs.append(read(ts).reshape(shp)) + ret = m.run(None, dict(zip(keys, inputs))) + #print(ret, file=sys.stderr) + for r in ret: + write(r) + + +if __name__ == "__main__": + print(ort.get_available_providers(), file=sys.stderr) + if 'OpenVINOExecutionProvider' in ort.get_available_providers() and 'ONNXCPU' not in os.environ: + print("OnnxJit is using openvino", file=sys.stderr) + options = ort.SessionOptions() + options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_DISABLE_ALL + provider = 'OpenVINOExecutionProvider' + elif 'CUDAExecutionProvider' in ort.get_available_providers(): + print("OnnxJit is using CUDA", file=sys.stderr) + options = ort.SessionOptions() + options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_DISABLE_ALL + provider = 'CUDAExecutionProvider' + else: + print("OnnxJit is using CPU", file=sys.stderr) + options = ort.SessionOptions() + options.intra_op_num_threads = 4 + options.inter_op_num_threads = 8 + options.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL + options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL + + provider = 'CPUExecutionProvider' + + ort_session = ort.InferenceSession(sys.argv[1], options) + ort_session.set_providers([provider], None) + run_loop(ort_session) diff --git a/selfdrive/modeld/runners/onnxmodel.cc b/selfdrive/modeld/runners/onnxmodel.cc new file mode 100644 index 000000000..8631c6286 --- /dev/null +++ b/selfdrive/modeld/runners/onnxmodel.cc @@ -0,0 +1,120 @@ +#include "onnxmodel.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" + +ONNXModel::ONNXModel(const char *path, float *_output, size_t _output_size, int runtime) { + output = _output; + output_size = _output_size; + + char tmp[1024]; + strncpy(tmp, path, sizeof(tmp)); + strstr(tmp, ".dlc")[0] = '\0'; + strcat(tmp, ".onnx"); + LOGD("loading model %s", tmp); + + int err = pipe(pipein); + assert(err == 0); + err = pipe(pipeout); + assert(err == 0); + + std::string exe_dir = util::dir_name(util::readlink("/proc/self/exe")); + std::string onnx_runner = exe_dir + "/runners/onnx_runner.py"; + + proc_pid = fork(); + if (proc_pid == 0) { + LOGD("spawning onnx process %s", onnx_runner.c_str()); + char *argv[] = {(char*)onnx_runner.c_str(), tmp, NULL}; + dup2(pipein[0], 0); + dup2(pipeout[1], 1); + close(pipein[0]); + close(pipein[1]); + close(pipeout[0]); + close(pipeout[1]); + execvp(onnx_runner.c_str(), argv); + } + + // parent + close(pipein[0]); + close(pipeout[1]); +} + +ONNXModel::~ONNXModel() { + close(pipein[1]); + close(pipeout[0]); + kill(proc_pid, SIGTERM); +} + +void ONNXModel::pwrite(float *buf, int size) { + char *cbuf = (char *)buf; + int tw = size*sizeof(float); + while (tw > 0) { + int err = write(pipein[1], cbuf, tw); + //printf("host write %d\n", err); + assert(err >= 0); + cbuf += err; + tw -= err; + } + LOGD("host write of size %d done", size); +} + +void ONNXModel::pread(float *buf, int size) { + char *cbuf = (char *)buf; + int tr = size*sizeof(float); + struct pollfd fds[1]; + fds[0].fd = pipeout[0]; + fds[0].events = POLLIN; + while (tr > 0) { + int err; + err = poll(fds, 1, 10000); // 10 second timeout + assert(err == 1 || (err == -1 && errno == EINTR)); + LOGD("host read remaining %d/%d poll %d", tr, size*sizeof(float), err); + err = read(pipeout[0], cbuf, tr); + assert(err > 0 || (err == 0 && errno == EINTR)); + cbuf += err; + tr -= err; + } + LOGD("host read done"); +} + +void ONNXModel::addRecurrent(float *state, int state_size) { + rnn_input_buf = state; + rnn_state_size = state_size; +} + +void ONNXModel::addDesire(float *state, int state_size) { + desire_input_buf = state; + desire_state_size = state_size; +} + +void ONNXModel::addTrafficConvention(float *state, int state_size) { + traffic_convention_input_buf = state; + traffic_convention_size = state_size; +} + +void ONNXModel::execute(float *net_input_buf, int buf_size) { + // order must be this + pwrite(net_input_buf, buf_size); + if (desire_input_buf != NULL) { + pwrite(desire_input_buf, desire_state_size); + } + if (traffic_convention_input_buf != NULL) { + pwrite(traffic_convention_input_buf, traffic_convention_size); + } + if (rnn_input_buf != NULL) { + pwrite(rnn_input_buf, rnn_state_size); + } + pread(output, output_size); +} + diff --git a/selfdrive/modeld/runners/onnxmodel.h b/selfdrive/modeld/runners/onnxmodel.h new file mode 100644 index 000000000..5ecfdc040 --- /dev/null +++ b/selfdrive/modeld/runners/onnxmodel.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "selfdrive/modeld/runners/runmodel.h" + +class ONNXModel : public RunModel { +public: + ONNXModel(const char *path, float *output, size_t output_size, int runtime); + ~ONNXModel(); + void addRecurrent(float *state, int state_size); + void addDesire(float *state, int state_size); + void addTrafficConvention(float *state, int state_size); + void execute(float *net_input_buf, int buf_size); +private: + int proc_pid; + + float *output; + size_t output_size; + + float *rnn_input_buf = NULL; + int rnn_state_size; + float *desire_input_buf = NULL; + int desire_state_size; + float *traffic_convention_input_buf = NULL; + int traffic_convention_size; + + // pipe to communicate to keras subprocess + void pread(float *buf, int size); + void pwrite(float *buf, int size); + int pipein[2]; + int pipeout[2]; +}; + diff --git a/selfdrive/monitoring/dmonitoringd.py b/selfdrive/monitoring/dmonitoringd.py index 8321d3734..34452b534 100755 --- a/selfdrive/monitoring/dmonitoringd.py +++ b/selfdrive/monitoring/dmonitoringd.py @@ -37,7 +37,8 @@ def dmonitoringd_thread(sm=None, pm=None): driver_engaged = len(sm['carState'].buttonEvents) > 0 or \ v_cruise != v_cruise_last or \ sm['carState'].steeringPressed or \ - sm['carState'].gasPressed + sm['carState'].gasPressed or \ + sm['carState'].brakePressed if driver_engaged: driver_status.update(Events(), True, sm['controlsState'].enabled, sm['carState'].standstill) v_cruise_last = v_cruise diff --git a/selfdrive/swaglog.py b/selfdrive/swaglog.py index 08122b0ca..29c783f64 100644 --- a/selfdrive/swaglog.py +++ b/selfdrive/swaglog.py @@ -7,9 +7,9 @@ from logging.handlers import BaseRotatingHandler import zmq from common.logging_extra import SwagLogger, SwagFormatter, SwagLogFileFormatter -from selfdrive.hardware import PC +from selfdrive.hardware import PC, JETSON -if PC: +if PC or JETSON: SWAGLOG_DIR = os.path.join(str(Path.home()), ".comma", "log") else: SWAGLOG_DIR = "/data/log/" diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py index 70ee9fc0a..5b8012b19 100644 --- a/selfdrive/thermald/power_monitoring.py +++ b/selfdrive/thermald/power_monitoring.py @@ -174,13 +174,13 @@ class PowerMonitoring: return disable_charging # See if we need to shutdown - def should_shutdown(self, pandaState, offroad_timestamp, started_seen): + def should_shutdown(self, pandaState, offroad_timestamp, started_seen, LEON): if pandaState is None or offroad_timestamp is None: return False now = sec_since_boot() panda_charging = (pandaState.pandaState.usbPowerMode != log.PandaState.UsbPowerMode.client) - BATT_PERC_OFF = 10 + BATT_PERC_OFF = 10 if LEON else 3 should_shutdown = False # Wait until we have shut down charging before powering down diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 950b34e8b..a131a4ff6 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -14,13 +14,13 @@ from common.filter_simple import FirstOrderFilter from common.numpy_fast import clip, interp from common.params import Params, ParamKeyType from common.realtime import DT_TRML, sec_since_boot -from common.dict_helpers import strip_deprecated_keys +# from common.dict_helpers import strip_deprecated_keys from selfdrive.controls.lib.alertmanager import set_offroad_alert from selfdrive.hardware import EON, TICI, HARDWARE from selfdrive.loggerd.config import get_available_percent from selfdrive.pandad import get_expected_signature from selfdrive.swaglog import cloudlog -from selfdrive.thermald.power_monitoring import PowerMonitoring +from selfdrive.thermald.power_monitoring import PowerMonitoring, MAX_TIME_OFFROAD_S from selfdrive.version import get_git_branch, terms_version, training_version FW_SIGNATURE = get_expected_signature() @@ -36,8 +36,12 @@ DISCONNECT_TIMEOUT = 5. # wait 5 seconds before going offroad after disconnect prev_offroad_states: Dict[str, Tuple[bool, Optional[str]]] = {} +LEON = False last_eon_fan_val = None +params = Params() +from common.dp_time import LAST_MODIFIED_THERMALD +from common.dp_common import get_last_modified, param_get_if_updated def read_tz(x): if x is None: @@ -61,28 +65,49 @@ def read_thermal(thermal_config): def setup_eon_fan(): + global LEON + os.system("echo 2 > /sys/module/dwc3_msm/parameters/otg_switch") + bus = SMBus(7, force=True) + try: + bus.write_byte_data(0x21, 0x10, 0xf) # mask all interrupts + bus.write_byte_data(0x21, 0x03, 0x1) # set drive current and global interrupt disable + bus.write_byte_data(0x21, 0x02, 0x2) # needed? + bus.write_byte_data(0x21, 0x04, 0x4) # manual override source + except IOError: + print("LEON detected") + LEON = True + bus.close() + def set_eon_fan(val): - global last_eon_fan_val + global LEON, last_eon_fan_val if last_eon_fan_val is None or last_eon_fan_val != val: bus = SMBus(7, force=True) - try: - i = [0x1, 0x3 | 0, 0x3 | 0x08, 0x3 | 0x10][val] - bus.write_i2c_block_data(0x3d, 0, [i]) - except IOError: - # tusb320 - if val == 0: - bus.write_i2c_block_data(0x67, 0xa, [0]) - else: - bus.write_i2c_block_data(0x67, 0xa, [0x20]) - bus.write_i2c_block_data(0x67, 0x8, [(val - 1) << 6]) + if LEON: + try: + i = [0x1, 0x3 | 0, 0x3 | 0x08, 0x3 | 0x10][val] + bus.write_i2c_block_data(0x3d, 0, [i]) + except IOError: + # tusb320 + if val == 0: + bus.write_i2c_block_data(0x67, 0xa, [0]) + #bus.write_i2c_block_data(0x67, 0x45, [1<<2]) + else: + #bus.write_i2c_block_data(0x67, 0x45, [0]) + bus.write_i2c_block_data(0x67, 0xa, [0x20]) + bus.write_i2c_block_data(0x67, 0x8, [(val - 1) << 6]) + else: + bus.write_byte_data(0x21, 0x04, 0x2) + bus.write_byte_data(0x21, 0x03, (val*2)+1) + bus.write_byte_data(0x21, 0x04, 0x4) bus.close() last_eon_fan_val = val + # temp thresholds to control fan speed - high hysteresis _TEMP_THRS_H = [50., 65., 80., 10000] # temp thresholds to control fan speed - low hysteresis @@ -93,9 +118,17 @@ _FAN_SPEEDS = [0, 16384, 32768, 65535] _BAT_TEMP_THRESHOLD = 45. -def handle_fan_eon(max_cpu_temp, bat_temp, fan_speed, ignition): - new_speed_h = next(speed for speed, temp_h in zip(_FAN_SPEEDS, _TEMP_THRS_H) if temp_h > max_cpu_temp) - new_speed_l = next(speed for speed, temp_l in zip(_FAN_SPEEDS, _TEMP_THRS_L) if temp_l > max_cpu_temp) +def handle_fan_eon(dp_fan_mode, max_cpu_temp, bat_temp, fan_speed, ignition): + _fan_speed = _FAN_SPEEDS + _bat_temp_threshold = _BAT_TEMP_THRESHOLD + if dp_fan_mode == 2: + _fan_speed = [0, 65535, 65535, 65535] + _bat_temp_threshold = 15. + elif dp_fan_mode == 1: + _fan_speed = [0, 16384, 16384, 32768] + + new_speed_h = next(speed for speed, temp_h in zip(_fan_speed, _TEMP_THRS_H) if temp_h > max_cpu_temp) + new_speed_l = next(speed for speed, temp_l in zip(_fan_speed, _TEMP_THRS_L) if temp_l > max_cpu_temp) if new_speed_h > fan_speed: # update speed if using the high thresholds results in fan speed increment @@ -104,20 +137,25 @@ def handle_fan_eon(max_cpu_temp, bat_temp, fan_speed, ignition): # update speed if using the low thresholds results in fan speed decrement fan_speed = new_speed_l - if bat_temp < _BAT_TEMP_THRESHOLD: + if bat_temp < _bat_temp_threshold: # no max fan speed unless battery is hot - fan_speed = min(fan_speed, _FAN_SPEEDS[-2]) + fan_speed = min(fan_speed, _fan_speed[-2]) set_eon_fan(fan_speed // 16384) return fan_speed -def handle_fan_uno(max_cpu_temp, bat_temp, fan_speed, ignition): - new_speed = int(interp(max_cpu_temp, [40.0, 80.0], [0, 80])) +def handle_fan_uno(dp_fan_mode, max_cpu_temp, bat_temp, fan_speed, ignition): + if dp_fan_mode == 2: + new_speed = 80 + elif dp_fan_mode == 1: + new_speed = int(interp(max_cpu_temp, [65.0, 80.0, 90.0], [0, 20, 60])) + else: + new_speed = int(interp(max_cpu_temp, [40.0, 80.0], [0, 80])) if not ignition: - new_speed = min(30, new_speed) + new_speed = min(10 if dp_fan_mode == 2 else 30, new_speed) return new_speed @@ -165,7 +203,6 @@ def thermald_thread(): is_uno = False ui_running_prev = False - params = Params() power_monitor = PowerMonitoring() no_panda_cnt = 0 @@ -174,6 +211,29 @@ def thermald_thread(): if params.get_bool("IsOnroad"): cloudlog.event("onroad flag not cleared") + # dp + dp_no_batt = params.get_bool("dp_no_batt") + dp_temp_monitor = True + dp_last_modified_temp_monitor = None + + dp_debug = False + dp_last_modified_debug = None + + dp_auto_shutdown = False + dp_last_modified_auto_shutdown = None + dp_auto_shutdown_last = False + + dp_auto_shutdown_in = 90 + dp_last_modified_auto_shutdown_in = None + dp_auto_shutdown_in_last = 90 + + dp_fan_mode = 0 + dp_fan_mode_last = None + + modified = None + last_modified = None + last_modified_check = None + # CPR3 logging if EON: base_path = "/sys/kernel/debug/cpr3-regulator/" @@ -189,6 +249,17 @@ def thermald_thread(): cloudlog.event("CPR", data=cpr_data) while 1: + + # dp - load temp monitor conf + last_modified_check, modified = get_last_modified(LAST_MODIFIED_THERMALD, last_modified_check, modified) + if last_modified != modified: + dp_temp_monitor, dp_last_modified_temp_monitor = param_get_if_updated("dp_temp_monitor", "bool", dp_temp_monitor, dp_last_modified_temp_monitor) + dp_auto_shutdown, dp_last_modified_auto_shutdown = param_get_if_updated("dp_auto_shutdown", "bool", dp_auto_shutdown, dp_last_modified_auto_shutdown) + dp_auto_shutdown_in, dp_last_modified_auto_shutdown_in = param_get_if_updated("dp_auto_shutdown_in", "int", dp_auto_shutdown_in, dp_last_modified_auto_shutdown_in) + dp_fan_mode, dp_fan_mode_last = param_get_if_updated("dp_fan_mode", "int", dp_fan_mode, dp_fan_mode_last) + dp_debug, dp_last_modified_debug = param_get_if_updated("dp_debug", "int", dp_debug, dp_last_modified_debug) + last_modified = modified + pandaState = messaging.recv_sock(pandaState_sock, wait=True) msg = read_thermal(thermal_config) @@ -253,7 +324,7 @@ def thermald_thread(): msg.deviceState.usbOnline = HARDWARE.get_usb_present() # Fake battery levels on uno for frame - if (not EON) or is_uno: + if (not EON) or is_uno or dp_no_batt: msg.deviceState.batteryPercent = 100 msg.deviceState.batteryStatus = "Charging" msg.deviceState.batteryTempC = 0 @@ -266,7 +337,7 @@ def thermald_thread(): bat_temp = msg.deviceState.batteryTempC if handle_fan is not None: - fan_speed = handle_fan(max_cpu_temp, bat_temp, fan_speed, startup_conditions["ignition"]) + fan_speed = handle_fan(dp_fan_mode, max_cpu_temp, bat_temp, fan_speed, startup_conditions["ignition"]) msg.deviceState.fanSpeedPercentDesired = fan_speed # If device is offroad we want to cool down before going onroad @@ -291,48 +362,50 @@ def thermald_thread(): else: thermal_status = ThermalStatus.green # default to good condition + if not dp_temp_monitor and thermal_status in [ThermalStatus.red, ThermalStatus.danger]: + thermal_status = ThermalStatus.yellow # **** starting logic **** # Check for last update time and display alerts if needed - now = datetime.datetime.utcnow() - - # show invalid date/time alert - startup_conditions["time_valid"] = (now.year > 2020) or (now.year == 2020 and now.month >= 10) - set_offroad_alert_if_changed("Offroad_InvalidTime", (not startup_conditions["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) - last_update_exception = params.get("LastUpdateException", encoding='utf8') - - if update_failed_count > 15 and last_update_exception is not None: - if current_branch in ["release2", "dashcam"]: - extra_text = "Ensure the software is correctly installed" - else: - extra_text = last_update_exception - - set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False) - set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False) - set_offroad_alert_if_changed("Offroad_UpdateFailed", True, extra_text=extra_text) - elif dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1: - set_offroad_alert_if_changed("Offroad_UpdateFailed", False) - set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False) - set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", True) - elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT: - remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0)) - set_offroad_alert_if_changed("Offroad_UpdateFailed", False) - set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False) - set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", True, extra_text=f"{remaining_time} days.") - else: - set_offroad_alert_if_changed("Offroad_UpdateFailed", False) - set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False) - set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False) + # now = datetime.datetime.utcnow() + # + # # show invalid date/time alert + # startup_conditions["time_valid"] = (now.year > 2020) or (now.year == 2020 and now.month >= 10) + # set_offroad_alert_if_changed("Offroad_InvalidTime", (not startup_conditions["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) + # last_update_exception = params.get("LastUpdateException", encoding='utf8') + # + # if update_failed_count > 15 and last_update_exception is not None: + # if current_branch in ["release2", "dashcam"]: + # extra_text = "Ensure the software is correctly installed" + # else: + # extra_text = last_update_exception + # + # set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False) + # set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False) + # set_offroad_alert_if_changed("Offroad_UpdateFailed", True, extra_text=extra_text) + # elif dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1: + # set_offroad_alert_if_changed("Offroad_UpdateFailed", False) + # set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False) + # set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", True) + # elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT: + # remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0)) + # set_offroad_alert_if_changed("Offroad_UpdateFailed", False) + # set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False) + # set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", True, extra_text=f"{remaining_time} days.") + # else: + # set_offroad_alert_if_changed("Offroad_UpdateFailed", False) + # set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False) + # set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False) startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get_bool("DisableUpdates") startup_conditions["not_uninstalling"] = not params.get_bool("DoUninstall") @@ -358,6 +431,8 @@ def thermald_thread(): # Handle offroad/onroad transition should_start = all(startup_conditions.values()) + if dp_debug: + should_start = True if should_start != should_start_prev or (count == 0): params.put_bool("IsOnroad", should_start) params.put_bool("IsOffroad", not should_start) @@ -380,20 +455,38 @@ def thermald_thread(): off_ts = sec_since_boot() # Offroad power monitoring - power_monitor.calculate(pandaState) - msg.deviceState.offroadPowerUsageUwh = power_monitor.get_power_used() - msg.deviceState.carBatteryCapacityUwh = max(0, power_monitor.get_car_battery_capacity()) + if not dp_no_batt: + power_monitor.calculate(pandaState) + msg.deviceState.offroadPowerUsageUwh = power_monitor.get_power_used() + msg.deviceState.carBatteryCapacityUwh = max(0, power_monitor.get_car_battery_capacity()) # Check if we need to disable charging (handled by boardd) msg.deviceState.chargingDisabled = power_monitor.should_disable_charging(pandaState, off_ts) # Check if we need to shut down - if power_monitor.should_shutdown(pandaState, off_ts, started_seen): + if power_monitor.should_shutdown(pandaState, off_ts, started_seen, LEON): cloudlog.info(f"shutting device down, offroad since {off_ts}") # TODO: add function for blocking cloudlog instead of sleep time.sleep(10) HARDWARE.shutdown() + # dp - auto shutdown + # reset off_ts if we change auto shutdown related params + if off_ts is not None: + if dp_auto_shutdown: + shutdown_sec = dp_auto_shutdown_in * 60 + sec_now = sec_since_boot() - off_ts + if (shutdown_sec - 5) < sec_now: + msg.deviceState.chargingDisabled = True + if shutdown_sec < sec_now: + time.sleep(10) + HARDWARE.shutdown() + + if dp_auto_shutdown_in_last != dp_auto_shutdown_in or dp_auto_shutdown_last != dp_auto_shutdown: + off_ts = sec_since_boot() + dp_auto_shutdown_last = dp_auto_shutdown + dp_auto_shutdown_in_last = dp_auto_shutdown_in + # If UI has crashed, set the brightness to reasonable non-zero value manager_state = messaging.recv_one_or_none(managerState_sock) if manager_state is not None: @@ -420,16 +513,16 @@ def thermald_thread(): startup_conditions_prev = startup_conditions.copy() # report to server once every 10 minutes - if (count % int(600. / DT_TRML)) == 0: - if EON and started_ts is None and msg.deviceState.memoryUsagePercent > 40: - cloudlog.event("High offroad memory usage", mem=msg.deviceState.memoryUsagePercent) - - location = messaging.recv_sock(location_sock) - cloudlog.event("STATUS_PACKET", - count=count, - pandaState=(strip_deprecated_keys(pandaState.to_dict()) if pandaState else None), - location=(strip_deprecated_keys(location.gpsLocationExternal.to_dict()) if location else None), - deviceState=strip_deprecated_keys(msg.to_dict())) + # if (count % int(600. / DT_TRML)) == 0: + # if EON and started_ts is None and msg.deviceState.memoryUsagePercent > 40: + # cloudlog.event("High offroad memory usage", mem=msg.deviceState.memoryUsagePercent) + # + # location = messaging.recv_sock(location_sock) + # cloudlog.event("STATUS_PACKET", + # count=count, + # pandaState=(strip_deprecated_keys(pandaState.to_dict()) if pandaState else None), + # location=(strip_deprecated_keys(location.gpsLocationExternal.to_dict()) if location else None), + # deviceState=strip_deprecated_keys(msg.to_dict())) count += 1 diff --git a/selfdrive/ui/.gitignore b/selfdrive/ui/.gitignore deleted file mode 100644 index 2dbc32523..000000000 --- a/selfdrive/ui/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -moc_* -*.moc - -replay/replay -qt/text -qt/spinner -qt/setup/setup -qt/setup/reset -qt/setup/wifi -qt/setup/installer* diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript deleted file mode 100644 index d7625cf1c..000000000 --- a/selfdrive/ui/SConscript +++ /dev/null @@ -1,83 +0,0 @@ -import os -Import('qt_env', 'arch', 'common', 'messaging', 'gpucommon', 'visionipc', - 'cereal', 'transformations') - -base_libs = [gpucommon, common, messaging, cereal, visionipc, transformations, 'zmq', - 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] - -maps = arch in ['larch64', 'x86_64'] and \ - os.path.exists(File("qt/maps/map.cc").srcnode().abspath) - -if arch == 'aarch64': - base_libs += ['log', 'utils', 'gui', 'ui', 'CB', 'gsl', 'adreno_utils', 'cutils', 'uuid'] - -if maps and arch in ['x86_64']: - rpath = [Dir(f"#phonelibs/mapbox-gl-native-qt/{arch}").srcnode().abspath] - qt_env["RPATH"] += rpath - -if arch == "Darwin": - del base_libs[base_libs.index('OpenCL')] - qt_env['FRAMEWORKS'] += ['OpenCL'] - -widgets_src = ["qt/widgets/input.cc", "qt/widgets/drive_stats.cc", - "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", - "qt/widgets/offroad_alerts.cc", "qt/widgets/setup.cc", "qt/widgets/keyboard.cc", - "qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#phonelibs/qrcode/QrCode.cc", "qt/api.cc", - "qt/request_repeater.cc"] - -if arch != 'aarch64': - widgets_src += ["qt/offroad/networking.cc", "qt/offroad/wifiManager.cc"] - -if maps: - base_libs += ['qmapboxgl'] - widgets_src += ["qt/maps/map_helpers.cc", "qt/maps/map.cc"] - qt_env['CPPDEFINES'] = ["ENABLE_MAPS"] - -widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=base_libs) -qt_libs = [widgets] + base_libs - -# spinner and text window -qt_env.Program("qt/text", ["qt/text.cc"], LIBS=qt_libs) -qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=base_libs) - -# build main UI -qt_src = ["main.cc", "ui.cc", "paint.cc", "qt/sidebar.cc", "qt/onroad.cc", - "qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc", - "qt/offroad/onboarding.cc", "qt/offroad/driverview.cc", "#phonelibs/nanovg/nanovg.c"] - -qt_env.Program("_ui", qt_src, LIBS=qt_libs) - -# setup, factory resetter, and installer -if arch != 'aarch64' and "BUILD_SETUP" in os.environ: - qt_env.Program("qt/setup/reset", ["qt/setup/reset.cc"], LIBS=qt_libs) - qt_env.Program("qt/setup/setup", ["qt/setup/setup.cc"], LIBS=qt_libs + ['curl', 'common', 'json11']) - qt_env.Program("qt/setup/wifi", ["qt/setup/wifi.cc"], LIBS=qt_libs + ['common', 'json11']) - - installers = [ - ("openpilot", "master"), - ("openpilot_test", "release3-staging"), - ("openpilot_internal", "master"), - ("dashcam", "dashcam3-staging"), - ("dashcam_test", "dashcam3-staging"), - ] - for name, branch in installers: - d = {'BRANCH': f"'\"{branch}\"'"} - if "internal" in name: - d['INTERNAL'] = "1" - - import requests - r = requests.get("https://github.com/commaci2.keys") - r.raise_for_status() - d['SSH_KEYS'] = f'\\"{r.text.strip()}\\"' - obj = qt_env.Object(f"qt/setup/installer_{name}.o", ["qt/setup/installer.cc"], CPPDEFINES=d) - qt_env.Program(f"qt/setup/installer_{name}", obj, LIBS=qt_libs, CPPDEFINES=d) - -# build headless replay -if arch == 'x86_64' and os.path.exists(Dir("#tools/").get_abspath()): - qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"] - - replay_lib_src = ["replay/replay.cc", "replay/filereader.cc", "replay/framereader.cc"] - - replay_lib = qt_env.Library("qt_replay", replay_lib_src, LIBS=base_libs) - replay_libs = [replay_lib, 'avutil', 'avcodec', 'avformat', 'swscale', 'bz2'] + qt_libs - qt_env.Program("replay/replay", ["replay/main.cc"], LIBS=replay_libs) diff --git a/selfdrive/ui/_ui b/selfdrive/ui/_ui new file mode 100755 index 000000000..846d09b0e Binary files /dev/null and b/selfdrive/ui/_ui differ diff --git a/selfdrive/ui/main.cc b/selfdrive/ui/main.cc deleted file mode 100644 index dab8d6654..000000000 --- a/selfdrive/ui/main.cc +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -#include "selfdrive/hardware/hw.h" -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/window.h" - -int main(int argc, char *argv[]) { - QSurfaceFormat fmt; -#ifdef __APPLE__ - fmt.setVersion(3, 2); - fmt.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - fmt.setRenderableType(QSurfaceFormat::OpenGL); -#else - fmt.setRenderableType(QSurfaceFormat::OpenGLES); -#endif - QSurfaceFormat::setDefaultFormat(fmt); - - if (Hardware::EON()) { - QApplication::setAttribute(Qt::AA_ShareOpenGLContexts); - QSslConfiguration ssl = QSslConfiguration::defaultConfiguration(); - ssl.setCaCertificates(QSslCertificate::fromPath("/usr/etc/tls/cert.pem")); - QSslConfiguration::setDefaultConfiguration(ssl); - } - - QApplication a(argc, argv); - MainWindow w; - setMainWindow(&w); - a.installEventFilter(&w); - return a.exec(); -} diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc deleted file mode 100644 index eb834ef9f..000000000 --- a/selfdrive/ui/paint.cc +++ /dev/null @@ -1,475 +0,0 @@ -#include "paint.h" - -#include - -#include - -#ifdef __APPLE__ -#include -#define NANOVG_GL3_IMPLEMENTATION -#define nvgCreate nvgCreateGL3 -#else -#include -#define NANOVG_GLES3_IMPLEMENTATION -#define nvgCreate nvgCreateGLES3 -#endif - -#define NANOVG_GLES3_IMPLEMENTATION -#include -#include - -#include "selfdrive/common/timing.h" -#include "selfdrive/common/util.h" -#include "selfdrive/hardware/hw.h" - -#include "selfdrive/ui/ui.h" - -static void ui_draw_text(const UIState *s, float x, float y, const char *string, float size, NVGcolor color, const char *font_name) { - nvgFontFace(s->vg, font_name); - nvgFontSize(s->vg, size); - nvgFillColor(s->vg, color); - nvgText(s->vg, x, y, string, NULL); -} - -static void draw_chevron(UIState *s, float x, float y, float sz, NVGcolor fillColor, NVGcolor glowColor) { - // glow - float g_xo = sz/5; - float g_yo = sz/10; - nvgBeginPath(s->vg); - nvgMoveTo(s->vg, x+(sz*1.35)+g_xo, y+sz+g_yo); - nvgLineTo(s->vg, x, y-g_xo); - nvgLineTo(s->vg, x-(sz*1.35)-g_xo, y+sz+g_yo); - nvgClosePath(s->vg); - nvgFillColor(s->vg, glowColor); - nvgFill(s->vg); - - // chevron - nvgBeginPath(s->vg); - nvgMoveTo(s->vg, x+(sz*1.25), y+sz); - nvgLineTo(s->vg, x, y); - nvgLineTo(s->vg, x-(sz*1.25), y+sz); - nvgClosePath(s->vg); - nvgFillColor(s->vg, fillColor); - nvgFill(s->vg); -} - -static void ui_draw_circle_image(const UIState *s, int center_x, int center_y, int radius, const char *image, NVGcolor color, float img_alpha) { - nvgBeginPath(s->vg); - nvgCircle(s->vg, center_x, center_y, radius); - nvgFillColor(s->vg, color); - nvgFill(s->vg); - const int img_size = radius * 1.5; - ui_draw_image(s, {center_x - (img_size / 2), center_y - (img_size / 2), img_size, img_size}, image, img_alpha); -} - -static void ui_draw_circle_image(const UIState *s, int center_x, int center_y, int radius, const char *image, bool active) { - float bg_alpha = active ? 0.3f : 0.1f; - float img_alpha = active ? 1.0f : 0.15f; - ui_draw_circle_image(s, center_x, center_y, radius, image, nvgRGBA(0, 0, 0, (255 * bg_alpha)), img_alpha); -} - -static void draw_lead(UIState *s, const cereal::RadarState::LeadData::Reader &lead_data, const vertex_data &vd) { - // Draw lead car indicator - auto [x, y] = vd; - - float fillAlpha = 0; - float speedBuff = 10.; - float leadBuff = 40.; - float d_rel = lead_data.getDRel(); - float v_rel = lead_data.getVRel(); - if (d_rel < leadBuff) { - fillAlpha = 255*(1.0-(d_rel/leadBuff)); - if (v_rel < 0) { - fillAlpha += 255*(-1*(v_rel/speedBuff)); - } - fillAlpha = (int)(fmin(fillAlpha, 255)); - } - - float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * s->zoom; - x = std::clamp(x, 0.f, s->viz_rect.right() - sz / 2); - y = std::fmin(s->viz_rect.bottom() - sz * .6, y); - draw_chevron(s, x, y, sz, nvgRGBA(201, 34, 49, fillAlpha), COLOR_YELLOW); -} - -static void ui_draw_line(UIState *s, const line_vertices_data &vd, NVGcolor *color, NVGpaint *paint) { - if (vd.cnt == 0) return; - - const vertex_data *v = &vd.v[0]; - nvgBeginPath(s->vg); - nvgMoveTo(s->vg, v[0].x, v[0].y); - for (int i = 1; i < vd.cnt; i++) { - nvgLineTo(s->vg, v[i].x, v[i].y); - } - nvgClosePath(s->vg); - if (color) { - nvgFillColor(s->vg, *color); - } else if (paint) { - nvgFillPaint(s->vg, *paint); - } - nvgFill(s->vg); -} - -static void draw_frame(UIState *s) { - glBindVertexArray(s->frame_vao); - mat4 *out_mat = &s->rear_frame_mat; - glActiveTexture(GL_TEXTURE0); - - if (s->last_frame) { - glBindTexture(GL_TEXTURE_2D, s->texture[s->last_frame->idx]->frame_tex); - if (!Hardware::EON()) { - // this is handled in ion on QCOM - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, s->last_frame->width, s->last_frame->height, - 0, GL_RGB, GL_UNSIGNED_BYTE, s->last_frame->addr); - } - } - - glUseProgram(s->gl_shader->prog); - glUniform1i(s->gl_shader->getUniformLocation("uTexture"), 0); - glUniformMatrix4fv(s->gl_shader->getUniformLocation("uTransform"), 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 ui_draw_vision_lane_lines(UIState *s) { - const UIScene &scene = s->scene; - NVGpaint track_bg; - if (!scene.end_to_end) { - // paint lanelines - for (int i = 0; i < std::size(scene.lane_line_vertices); i++) { - NVGcolor color = nvgRGBAf(1.0, 1.0, 1.0, scene.lane_line_probs[i]); - ui_draw_line(s, scene.lane_line_vertices[i], &color, nullptr); - } - - // paint road edges - for (int i = 0; i < std::size(scene.road_edge_vertices); i++) { - NVGcolor color = nvgRGBAf(1.0, 0.0, 0.0, std::clamp(1.0 - scene.road_edge_stds[i], 0.0, 1.0)); - ui_draw_line(s, scene.road_edge_vertices[i], &color, nullptr); - } - track_bg = nvgLinearGradient(s->vg, s->fb_w, s->fb_h, s->fb_w, s->fb_h * .4, - COLOR_WHITE, COLOR_WHITE_ALPHA(0)); - } else { - track_bg = nvgLinearGradient(s->vg, s->fb_w, s->fb_h, s->fb_w, s->fb_h * .4, - COLOR_RED, COLOR_RED_ALPHA(0)); - } - // paint path - ui_draw_line(s, scene.track_vertices, nullptr, &track_bg); -} - -// Draw all world space objects. -static void ui_draw_world(UIState *s) { - // Don't draw on top of sidebar - nvgScissor(s->vg, s->viz_rect.x, s->viz_rect.y, s->viz_rect.w, s->viz_rect.h); - - // Draw lane edges and vision/mpc tracks - ui_draw_vision_lane_lines(s); - - // Draw lead indicators if openpilot is handling longitudinal - if (s->scene.longitudinal_control) { - auto radar_state = (*s->sm)["radarState"].getRadarState(); - auto lead_one = radar_state.getLeadOne(); - auto lead_two = radar_state.getLeadTwo(); - if (lead_one.getStatus()) { - draw_lead(s, lead_one, s->scene.lead_vertices[0]); - } - if (lead_two.getStatus() && (std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0)) { - draw_lead(s, lead_two, s->scene.lead_vertices[1]); - } - } - nvgResetScissor(s->vg); -} - -static void ui_draw_vision_maxspeed(UIState *s) { - const int SET_SPEED_NA = 255; - float maxspeed = (*s->sm)["controlsState"].getControlsState().getVCruise(); - const bool is_cruise_set = maxspeed != 0 && maxspeed != SET_SPEED_NA; - if (is_cruise_set && !s->scene.is_metric) { maxspeed *= 0.6225; } - - const Rect rect = {s->viz_rect.x + (bdr_s * 2), int(s->viz_rect.y + (bdr_s * 1.5)), 184, 202}; - ui_fill_rect(s->vg, rect, COLOR_BLACK_ALPHA(100), 30.); - ui_draw_rect(s->vg, rect, COLOR_WHITE_ALPHA(100), 10, 20.); - - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - ui_draw_text(s, rect.centerX(), 148, "MAX", 26 * 2.5, COLOR_WHITE_ALPHA(is_cruise_set ? 200 : 100), "sans-regular"); - if (is_cruise_set) { - const std::string maxspeed_str = std::to_string((int)std::nearbyint(maxspeed)); - ui_draw_text(s, rect.centerX(), 242, maxspeed_str.c_str(), 48 * 2.5, COLOR_WHITE, "sans-bold"); - } else { - ui_draw_text(s, rect.centerX(), 242, "N/A", 42 * 2.5, COLOR_WHITE_ALPHA(100), "sans-semibold"); - } -} - -static void ui_draw_vision_speed(UIState *s) { - const float speed = std::max(0.0, (*s->sm)["carState"].getCarState().getVEgo() * (s->scene.is_metric ? 3.6 : 2.2369363)); - const std::string speed_str = std::to_string((int)std::nearbyint(speed)); - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - ui_draw_text(s, s->viz_rect.centerX(), 240, speed_str.c_str(), 96 * 2.5, COLOR_WHITE, "sans-bold"); - ui_draw_text(s, s->viz_rect.centerX(), 320, s->scene.is_metric ? "km/h" : "mph", 36 * 2.5, COLOR_WHITE_ALPHA(200), "sans-regular"); -} - -static void ui_draw_vision_event(UIState *s) { - if (s->scene.engageable) { - // draw steering wheel - const int radius = 96; - const int center_x = s->viz_rect.right() - radius - bdr_s * 2; - const int center_y = s->viz_rect.y + radius + (bdr_s * 1.5); - const QColor &color = bg_colors[s->status]; - NVGcolor nvg_color = nvgRGBA(color.red(), color.green(), color.blue(), color.alpha()); - ui_draw_circle_image(s, center_x, center_y, radius, "wheel", nvg_color, 1.0f); - } -} - -static void ui_draw_vision_face(UIState *s) { - const int radius = 96; - const int center_x = s->viz_rect.x + radius + (bdr_s * 2); - const int center_y = s->viz_rect.bottom() - footer_h / 2; - ui_draw_circle_image(s, center_x, center_y, radius, "driver_face", s->scene.dm_active); -} - -static void ui_draw_vision_header(UIState *s) { - NVGpaint gradient = nvgLinearGradient(s->vg, s->viz_rect.x, - s->viz_rect.y+(header_h-(header_h/2.5)), - s->viz_rect.x, s->viz_rect.y+header_h, - nvgRGBAf(0,0,0,0.45), nvgRGBAf(0,0,0,0)); - - ui_fill_rect(s->vg, {s->viz_rect.x, s->viz_rect.y, s->viz_rect.w, header_h}, gradient); - - ui_draw_vision_maxspeed(s); - ui_draw_vision_speed(s); - ui_draw_vision_event(s); -} - -static void ui_draw_vision_frame(UIState *s) { - // Draw video frames - glEnable(GL_SCISSOR_TEST); - glViewport(s->video_rect.x, s->video_rect.y, s->video_rect.w, s->video_rect.h); - glScissor(s->viz_rect.x, s->viz_rect.y, s->viz_rect.w, s->viz_rect.h); - draw_frame(s); - glDisable(GL_SCISSOR_TEST); - - glViewport(0, 0, s->fb_w, s->fb_h); -} - -static void ui_draw_vision(UIState *s) { - const UIScene *scene = &s->scene; - // Draw augmented elements - if (scene->world_objects_visible) { - ui_draw_world(s); - } - // Set Speed, Current Speed, Status/Events - ui_draw_vision_header(s); - if ((*s->sm)["controlsState"].getControlsState().getAlertSize() == cereal::ControlsState::AlertSize::NONE) { - ui_draw_vision_face(s); - } -} - -static void ui_draw_background(UIState *s) { - const QColor &color = bg_colors[s->status]; - glClearColor(color.redF(), color.greenF(), color.blueF(), 1.0); - glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); -} - -void ui_draw(UIState *s, int w, int h) { - s->viz_rect = Rect{bdr_s, bdr_s, w - 2 * bdr_s, h - 2 * bdr_s}; - - const bool draw_vision = s->scene.started && s->vipc_client->connected; - - // GL drawing functions - ui_draw_background(s); - if (draw_vision) { - ui_draw_vision_frame(s); - } - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glViewport(0, 0, s->fb_w, s->fb_h); - - // NVG drawing functions - should be no GL inside NVG frame - nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f); - - if (draw_vision) { - ui_draw_vision(s); - } - - nvgEndFrame(s->vg); - glDisable(GL_BLEND); -} - -void ui_draw_image(const UIState *s, const Rect &r, const char *name, float alpha) { - nvgBeginPath(s->vg); - NVGpaint imgPaint = nvgImagePattern(s->vg, r.x, r.y, r.w, r.h, 0, s->images.at(name), alpha); - nvgRect(s->vg, r.x, r.y, r.w, r.h); - nvgFillPaint(s->vg, imgPaint); - nvgFill(s->vg); -} - -void ui_draw_rect(NVGcontext *vg, const Rect &r, NVGcolor color, int width, float radius) { - nvgBeginPath(vg); - radius > 0 ? nvgRoundedRect(vg, r.x, r.y, r.w, r.h, radius) : nvgRect(vg, r.x, r.y, r.w, r.h); - nvgStrokeColor(vg, color); - nvgStrokeWidth(vg, width); - nvgStroke(vg); -} - -static inline void fill_rect(NVGcontext *vg, const Rect &r, const NVGcolor *color, const NVGpaint *paint, float radius) { - nvgBeginPath(vg); - radius > 0 ? nvgRoundedRect(vg, r.x, r.y, r.w, r.h, radius) : nvgRect(vg, r.x, r.y, r.w, r.h); - if (color) nvgFillColor(vg, *color); - if (paint) nvgFillPaint(vg, *paint); - nvgFill(vg); -} -void ui_fill_rect(NVGcontext *vg, const Rect &r, const NVGcolor &color, float radius) { - fill_rect(vg, r, &color, nullptr, radius); -} -void ui_fill_rect(NVGcontext *vg, const Rect &r, const NVGpaint &paint, float radius) { - fill_rect(vg, r, nullptr, &paint, radius); -} - -static const char frame_vertex_shader[] = -#ifdef NANOVG_GL3_IMPLEMENTATION - "#version 150 core\n" -#else - "#version 300 es\n" -#endif - "in vec4 aPosition;\n" - "in vec4 aTexCoord;\n" - "uniform mat4 uTransform;\n" - "out vec4 vTexCoord;\n" - "void main() {\n" - " gl_Position = uTransform * aPosition;\n" - " vTexCoord = aTexCoord;\n" - "}\n"; - -static const char frame_fragment_shader[] = -#ifdef NANOVG_GL3_IMPLEMENTATION - "#version 150 core\n" -#else - "#version 300 es\n" -#endif - "precision mediump float;\n" - "uniform sampler2D uTexture;\n" - "in vec4 vTexCoord;\n" - "out vec4 colorOut;\n" - "void main() {\n" - " colorOut = texture(uTexture, vTexCoord.xy);\n" -#ifdef QCOM - " vec3 dz = vec3(0.0627f, 0.0627f, 0.0627f);\n" - " colorOut.rgb = ((vec3(1.0f, 1.0f, 1.0f) - dz) * colorOut.rgb / vec3(1.0f, 1.0f, 1.0f)) + dz;\n" -#endif - "}\n"; - -static const mat4 device_transform = {{ - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, -}}; - -void ui_nvg_init(UIState *s) { - // init drawing - - // on EON, we enable MSAA - s->vg = Hardware::EON() ? nvgCreate(0) : nvgCreate(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG); - assert(s->vg); - - // init fonts - std::pair fonts[] = { - {"sans-regular", "../assets/fonts/opensans_regular.ttf"}, - {"sans-semibold", "../assets/fonts/opensans_semibold.ttf"}, - {"sans-bold", "../assets/fonts/opensans_bold.ttf"}, - }; - for (auto [name, file] : fonts) { - int font_id = nvgCreateFont(s->vg, name, file); - assert(font_id >= 0); - } - - // init images - std::vector> images = { - {"wheel", "../assets/img_chffr_wheel.png"}, - {"driver_face", "../assets/img_driver_face.png"}, - }; - for (auto [name, file] : images) { - s->images[name] = nvgCreateImage(s->vg, file, 1); - assert(s->images[name] != 0); - } - - // init gl - s->gl_shader = std::make_unique(frame_vertex_shader, frame_fragment_shader); - GLint frame_pos_loc = glGetAttribLocation(s->gl_shader->prog, "aPosition"); - GLint frame_texcoord_loc = glGetAttribLocation(s->gl_shader->prog, "aTexCoord"); - - glViewport(0, 0, s->fb_w, s->fb_h); - - glDisable(GL_DEPTH_TEST); - - assert(glGetError() == GL_NO_ERROR); - - float x1 = 1.0, x2 = 0.0, y1 = 1.0, y2 = 0.0; - const uint8_t frame_indicies[] = {0, 1, 2, 0, 2, 3}; - const float frame_coords[4][4] = { - {-1.0, -1.0, x2, y1}, //bl - {-1.0, 1.0, x2, y2}, //tl - { 1.0, 1.0, x1, y2}, //tr - { 1.0, -1.0, x1, y1}, //br - }; - - glGenVertexArrays(1, &s->frame_vao); - glBindVertexArray(s->frame_vao); - glGenBuffers(1, &s->frame_vbo); - glBindBuffer(GL_ARRAY_BUFFER, s->frame_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(frame_coords), frame_coords, GL_STATIC_DRAW); - glEnableVertexAttribArray(frame_pos_loc); - glVertexAttribPointer(frame_pos_loc, 2, GL_FLOAT, GL_FALSE, - sizeof(frame_coords[0]), (const void *)0); - glEnableVertexAttribArray(frame_texcoord_loc); - glVertexAttribPointer(frame_texcoord_loc, 2, GL_FLOAT, GL_FALSE, - sizeof(frame_coords[0]), (const void *)(sizeof(float) * 2)); - glGenBuffers(1, &s->frame_ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->frame_ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(frame_indicies), frame_indicies, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - ui_resize(s, s->fb_w, s->fb_h); -} - -void ui_resize(UIState *s, int width, int height){ - s->fb_w = width; - s->fb_h = height; - - auto intrinsic_matrix = s->wide_camera ? ecam_intrinsic_matrix : fcam_intrinsic_matrix; - - s->zoom = zoom / intrinsic_matrix.v[0]; - - if (s->wide_camera) { - s->zoom *= 0.5; - } - - s->video_rect = Rect{bdr_s, bdr_s, s->fb_w - 2 * bdr_s, s->fb_h - 2 * bdr_s}; - float zx = s->zoom * 2 * intrinsic_matrix.v[2] / s->video_rect.w; - float zy = s->zoom * 2 * intrinsic_matrix.v[5] / s->video_rect.h; - - const mat4 frame_transform = {{ - zx, 0.0, 0.0, 0.0, - 0.0, zy, 0.0, -y_offset / s->video_rect.h * 2, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - }}; - - s->rear_frame_mat = matmul(device_transform, frame_transform); - - // Apply transformation such that video pixel coordinates match video - // 1) Put (0, 0) in the middle of the video - nvgTranslate(s->vg, s->video_rect.x + s->video_rect.w / 2, s->video_rect.y + s->video_rect.h / 2 + y_offset); - - // 2) Apply same scaling as video - nvgScale(s->vg, s->zoom, s->zoom); - - // 3) Put (0, 0) in top left corner of video - nvgTranslate(s->vg, -intrinsic_matrix.v[2], -intrinsic_matrix.v[5]); - - nvgCurrentTransform(s->vg, s->car_space_transform); - nvgResetTransform(s->vg); -} diff --git a/selfdrive/ui/paint.h b/selfdrive/ui/paint.h deleted file mode 100644 index 55fe9c1d0..000000000 --- a/selfdrive/ui/paint.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "selfdrive/ui/ui.h" - -void ui_draw(UIState *s, int w, int h); -void ui_draw_image(const UIState *s, const Rect &r, const char *name, float alpha); -void ui_draw_rect(NVGcontext *vg, const Rect &r, NVGcolor color, int width, float radius = 0); -void ui_fill_rect(NVGcontext *vg, const Rect &r, const NVGpaint &paint, float radius = 0); -void ui_fill_rect(NVGcontext *vg, const Rect &r, const NVGcolor &color, float radius = 0); -void ui_nvg_init(UIState *s); -void ui_resize(UIState *s, int width, int height); diff --git a/selfdrive/ui/qt/api.cc b/selfdrive/ui/qt/api.cc deleted file mode 100644 index 771af0fcf..000000000 --- a/selfdrive/ui/qt/api.cc +++ /dev/null @@ -1,141 +0,0 @@ -#include "selfdrive/ui/qt/api.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "selfdrive/common/params.h" -#include "selfdrive/common/util.h" -#include "selfdrive/hardware/hw.h" - -const std::string private_key_path = - Hardware::PC() ? util::getenv_default("HOME", "/.comma/persist/comma/id_rsa", "/persist/comma/id_rsa") - : "/persist/comma/id_rsa"; - -QByteArray CommaApi::rsa_sign(const QByteArray &data) { - auto file = QFile(private_key_path.c_str()); - if (!file.open(QIODevice::ReadOnly)) { - qDebug() << "No RSA private key found, please run manager.py or registration.py"; - return QByteArray(); - } - auto key = file.readAll(); - file.close(); - file.deleteLater(); - BIO* mem = BIO_new_mem_buf(key.data(), key.size()); - assert(mem); - RSA* rsa_private = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL); - assert(rsa_private); - auto sig = QByteArray(); - sig.resize(RSA_size(rsa_private)); - unsigned int sig_len; - int ret = RSA_sign(NID_sha256, (unsigned char*)data.data(), data.size(), (unsigned char*)sig.data(), &sig_len, rsa_private); - assert(ret == 1); - assert(sig_len == sig.size()); - BIO_free(mem); - RSA_free(rsa_private); - return sig; -} - -QString CommaApi::create_jwt(const QVector> &payloads, int expiry) { - QString dongle_id = QString::fromStdString(Params().get("DongleId")); - - QJsonObject header; - header.insert("alg", "RS256"); - - QJsonObject payload; - payload.insert("identity", dongle_id); - - auto t = QDateTime::currentSecsSinceEpoch(); - payload.insert("nbf", t); - payload.insert("iat", t); - payload.insert("exp", t + expiry); - for (auto &load : payloads) { - payload.insert(load.first, load.second); - } - - auto b64_opts = QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals; - QString jwt = QJsonDocument(header).toJson(QJsonDocument::Compact).toBase64(b64_opts) + '.' + - QJsonDocument(payload).toJson(QJsonDocument::Compact).toBase64(b64_opts); - - auto hash = QCryptographicHash::hash(jwt.toUtf8(), QCryptographicHash::Sha256); - auto sig = rsa_sign(hash); - jwt += '.' + sig.toBase64(b64_opts); - return jwt; -} - - -HttpRequest::HttpRequest(QObject *parent, const QString &requestURL, const QString &cache_key, bool create_jwt_) : cache_key(cache_key), create_jwt(create_jwt_), QObject(parent) { - networkAccessManager = new QNetworkAccessManager(this); - reply = NULL; - - networkTimer = new QTimer(this); - networkTimer->setSingleShot(true); - networkTimer->setInterval(20000); - connect(networkTimer, &QTimer::timeout, this, &HttpRequest::requestTimeout); - - sendRequest(requestURL); - - if (!cache_key.isEmpty()) { - if (std::string cached_resp = Params().get(cache_key.toStdString()); !cached_resp.empty()) { - QTimer::singleShot(0, [=]() { emit receivedResponse(QString::fromStdString(cached_resp)); }); - } - } -} - -void HttpRequest::sendRequest(const QString &requestURL){ - QString token; - if(create_jwt) { - token = CommaApi::create_jwt(); - } else { - QString token_json = QString::fromStdString(util::read_file(util::getenv_default("HOME", "/.comma/auth.json", "/.comma/auth.json"))); - QJsonDocument json_d = QJsonDocument::fromJson(token_json.toUtf8()); - token = json_d["access_token"].toString(); - } - - QNetworkRequest request; - request.setUrl(QUrl(requestURL)); - request.setRawHeader(QByteArray("Authorization"), ("JWT " + token).toUtf8()); - - reply = networkAccessManager->get(request); - - networkTimer->start(); - connect(reply, &QNetworkReply::finished, this, &HttpRequest::requestFinished); -} - -void HttpRequest::requestTimeout(){ - reply->abort(); -} - -// This function should always emit something -void HttpRequest::requestFinished(){ - if (reply->error() != QNetworkReply::OperationCanceledError) { - networkTimer->stop(); - QString response = reply->readAll(); - - if (reply->error() == QNetworkReply::NoError) { - // save to cache - if (!cache_key.isEmpty()) { - Params().put(cache_key.toStdString(), response.toStdString()); - } - emit receivedResponse(response); - } else { - if (!cache_key.isEmpty()) { - Params().remove(cache_key.toStdString()); - } - qDebug() << reply->errorString(); - emit failedResponse(reply->errorString()); - } - } else { - emit timeoutResponse("timeout"); - } - reply->deleteLater(); - reply = NULL; -} diff --git a/selfdrive/ui/qt/api.h b/selfdrive/ui/qt/api.h deleted file mode 100644 index 71fd9b868..000000000 --- a/selfdrive/ui/qt/api.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class CommaApi : public QObject { - Q_OBJECT - -public: - static QByteArray rsa_sign(const QByteArray &data); - static QString create_jwt(const QVector> &payloads = {}, int expiry = 3600); -}; - -/** - * Makes a request to the request endpoint. - */ - -class HttpRequest : public QObject { - Q_OBJECT - -public: - explicit HttpRequest(QObject* parent, const QString &requestURL, const QString &cache_key = "", bool create_jwt_ = true); - QNetworkReply *reply; - void sendRequest(const QString &requestURL); - -private: - QNetworkAccessManager *networkAccessManager; - QTimer *networkTimer; - QString cache_key; - bool create_jwt; - -private slots: - void requestTimeout(); - void requestFinished(); - -signals: - void receivedResponse(const QString &response); - void failedResponse(const QString &errorString); - void timeoutResponse(const QString &errorString); -}; diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc deleted file mode 100644 index bdda7f91b..000000000 --- a/selfdrive/ui/qt/home.cc +++ /dev/null @@ -1,210 +0,0 @@ -#include "selfdrive/ui/qt/home.h" - -#include -#include -#include -#include - -#include "selfdrive/common/params.h" -#include "selfdrive/common/swaglog.h" -#include "selfdrive/common/timing.h" -#include "selfdrive/common/util.h" -#include "selfdrive/ui/qt/widgets/drive_stats.h" -#include "selfdrive/ui/qt/widgets/setup.h" - -// HomeWindow: the container for the offroad and onroad UIs - -HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) { - QHBoxLayout *layout = new QHBoxLayout(this); - layout->setMargin(0); - layout->setSpacing(0); - - sidebar = new Sidebar(this); - layout->addWidget(sidebar); - QObject::connect(this, &HomeWindow::update, sidebar, &Sidebar::updateState); - QObject::connect(sidebar, &Sidebar::openSettings, this, &HomeWindow::openSettings); - - slayout = new QStackedLayout(); - layout->addLayout(slayout); - - onroad = new OnroadWindow(this); - slayout->addWidget(onroad); - - QObject::connect(this, &HomeWindow::update, onroad, &OnroadWindow::update); - QObject::connect(this, &HomeWindow::offroadTransitionSignal, onroad, &OnroadWindow::offroadTransitionSignal); - - home = new OffroadHome(); - slayout->addWidget(home); - QObject::connect(this, &HomeWindow::openSettings, home, &OffroadHome::refresh); - - driver_view = new DriverViewWindow(this); - connect(driver_view, &DriverViewWindow::done, [=] { - showDriverView(false); - }); - slayout->addWidget(driver_view); - - setLayout(layout); -} - -void HomeWindow::offroadTransition(bool offroad) { - if (offroad) { - slayout->setCurrentWidget(home); - } else { - slayout->setCurrentWidget(onroad); - } - sidebar->setVisible(offroad); - emit offroadTransitionSignal(offroad); -} - -void HomeWindow::showDriverView(bool show) { - if (show) { - emit closeSettings(); - slayout->setCurrentWidget(driver_view); - } else { - slayout->setCurrentWidget(home); - } - sidebar->setVisible(show == false); -} - -void HomeWindow::mousePressEvent(QMouseEvent* e) { - // Handle sidebar collapsing - if (onroad->isVisible() && (!sidebar->isVisible() || e->x() > sidebar->width())) { - - // TODO: Handle this without exposing pointer to map widget - // Hide map first if visible, then hide sidebar - if (onroad->map != nullptr && onroad->map->isVisible()){ - onroad->map->setVisible(false); - } else if (!sidebar->isVisible()) { - sidebar->setVisible(true); - } else { - sidebar->setVisible(false); - - if (onroad->map != nullptr) onroad->map->setVisible(true); - } - } -} - -// OffroadHome: the offroad home page - -OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { - QVBoxLayout* main_layout = new QVBoxLayout(); - main_layout->setMargin(50); - - // top header - QHBoxLayout* header_layout = new QHBoxLayout(); - - date = new QLabel(); - date->setStyleSheet(R"(font-size: 55px;)"); - header_layout->addWidget(date, 0, Qt::AlignHCenter | Qt::AlignLeft); - - alert_notification = new QPushButton(); - alert_notification->setVisible(false); - QObject::connect(alert_notification, &QPushButton::released, this, &OffroadHome::openAlerts); - header_layout->addWidget(alert_notification, 0, Qt::AlignHCenter | Qt::AlignRight); - - std::string brand = Params().getBool("Passive") ? "dashcam" : "openpilot"; - QLabel* version = new QLabel(QString::fromStdString(brand + " v" + Params().get("Version"))); - version->setStyleSheet(R"(font-size: 55px;)"); - header_layout->addWidget(version, 0, Qt::AlignHCenter | Qt::AlignRight); - - main_layout->addLayout(header_layout); - - // main content - main_layout->addSpacing(25); - center_layout = new QStackedLayout(); - - QHBoxLayout* statsAndSetup = new QHBoxLayout(); - statsAndSetup->setMargin(0); - - DriveStats* drive = new DriveStats; - drive->setFixedSize(800, 800); - statsAndSetup->addWidget(drive); - - SetupWidget* setup = new SetupWidget; - statsAndSetup->addWidget(setup); - - QWidget* statsAndSetupWidget = new QWidget(); - statsAndSetupWidget->setLayout(statsAndSetup); - - center_layout->addWidget(statsAndSetupWidget); - - alerts_widget = new OffroadAlert(); - QObject::connect(alerts_widget, &OffroadAlert::closeAlerts, this, &OffroadHome::closeAlerts); - center_layout->addWidget(alerts_widget); - center_layout->setAlignment(alerts_widget, Qt::AlignCenter); - - main_layout->addLayout(center_layout, 1); - - // set up refresh timer - timer = new QTimer(this); - QObject::connect(timer, &QTimer::timeout, this, &OffroadHome::refresh); - timer->start(10 * 1000); - - setLayout(main_layout); - setStyleSheet(R"( - OffroadHome { - background-color: black; - } - * { - color: white; - } - )"); -} - -void OffroadHome::showEvent(QShowEvent *event) { - refresh(); -} - -void OffroadHome::openAlerts() { - center_layout->setCurrentIndex(1); -} - -void OffroadHome::closeAlerts() { - center_layout->setCurrentIndex(0); -} - -void OffroadHome::refresh() { - bool first_refresh = !date->text().size(); - if (!isVisible() && !first_refresh) { - return; - } - - date->setText(QDateTime::currentDateTime().toString("dddd, MMMM d")); - - // update alerts - - alerts_widget->refresh(); - if (!alerts_widget->alertCount && !alerts_widget->updateAvailable) { - emit closeAlerts(); - alert_notification->setVisible(false); - return; - } - - if (alerts_widget->updateAvailable) { - alert_notification->setText("UPDATE"); - } else { - int alerts = alerts_widget->alertCount; - alert_notification->setText(QString::number(alerts) + " ALERT" + (alerts == 1 ? "" : "S")); - } - - if (!alert_notification->isVisible() && !first_refresh) { - emit openAlerts(); - } - alert_notification->setVisible(true); - - // Red background for alerts, blue for update available - QString style = QString(R"( - padding: 15px; - padding-left: 30px; - padding-right: 30px; - border: 1px solid; - border-radius: 5px; - font-size: 40px; - font-weight: 500; - background-color: #E22C2C; - )"); - if (alerts_widget->updateAvailable) { - style.replace("#E22C2C", "#364DEF"); - } - alert_notification->setStyleSheet(style); -} diff --git a/selfdrive/ui/qt/home.h b/selfdrive/ui/qt/home.h deleted file mode 100644 index db3e2f8f6..000000000 --- a/selfdrive/ui/qt/home.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "selfdrive/ui/qt/offroad/driverview.h" -#include "selfdrive/ui/qt/onroad.h" -#include "selfdrive/ui/qt/sidebar.h" -#include "selfdrive/ui/qt/widgets/offroad_alerts.h" -#include "selfdrive/ui/ui.h" - -class OffroadHome : public QFrame { - Q_OBJECT - -public: - explicit OffroadHome(QWidget* parent = 0); - -protected: - void showEvent(QShowEvent *event) override; - -private: - QTimer* timer; - - QLabel* date; - QStackedLayout* center_layout; - OffroadAlert* alerts_widget; - QPushButton* alert_notification; - -public slots: - void closeAlerts(); - void openAlerts(); - void refresh(); -}; - -class HomeWindow : public QWidget { - Q_OBJECT - -public: - explicit HomeWindow(QWidget* parent = 0); - -signals: - void openSettings(); - void closeSettings(); - - // forwarded signals - void displayPowerChanged(bool on); - void update(const UIState &s); - void offroadTransitionSignal(bool offroad); - -public slots: - void offroadTransition(bool offroad); - void showDriverView(bool show); - -protected: - void mousePressEvent(QMouseEvent* e) override; - -private: - Sidebar *sidebar; - OffroadHome *home; - OnroadWindow *onroad; - DriverViewWindow *driver_view; - QStackedLayout *slayout; -}; diff --git a/selfdrive/ui/qt/images/icon_minus.png b/selfdrive/ui/qt/images/icon_minus.png new file mode 100755 index 000000000..e5327c0d3 Binary files /dev/null and b/selfdrive/ui/qt/images/icon_minus.png differ diff --git a/selfdrive/ui/qt/images/icon_plus.png b/selfdrive/ui/qt/images/icon_plus.png new file mode 100755 index 000000000..92b448b0b Binary files /dev/null and b/selfdrive/ui/qt/images/icon_plus.png differ diff --git a/selfdrive/ui/qt/offroad/driverview.cc b/selfdrive/ui/qt/offroad/driverview.cc deleted file mode 100644 index f6a3ebaf7..000000000 --- a/selfdrive/ui/qt/offroad/driverview.cc +++ /dev/null @@ -1,109 +0,0 @@ -#include "selfdrive/ui/qt/offroad/driverview.h" - -#include - -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/util.h" - -const int FACE_IMG_SIZE = 130; - -DriverViewWindow::DriverViewWindow(QWidget* parent) : QWidget(parent) { - setAttribute(Qt::WA_OpaquePaintEvent); - layout = new QStackedLayout(this); - layout->setStackingMode(QStackedLayout::StackAll); - - cameraView = new CameraViewWidget(VISION_STREAM_RGB_FRONT, this); - layout->addWidget(cameraView); - - scene = new DriverViewScene(this); - connect(cameraView, &CameraViewWidget::frameUpdated, scene, &DriverViewScene::frameUpdated); - layout->addWidget(scene); - layout->setCurrentWidget(scene); -} - -void DriverViewWindow::mousePressEvent(QMouseEvent* e) { - emit done(); -} - -DriverViewScene::DriverViewScene(QWidget* parent) : sm({"driverState"}), QWidget(parent) { - face = QImage("../assets/img_driver_face.png").scaled(FACE_IMG_SIZE, FACE_IMG_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation); -} - -void DriverViewScene::showEvent(QShowEvent* event) { - frame_updated = false; - is_rhd = params.getBool("IsRHD"); - params.putBool("IsDriverViewEnabled", true); -} - -void DriverViewScene::hideEvent(QHideEvent* event) { - params.putBool("IsDriverViewEnabled", false); -} - -void DriverViewScene::frameUpdated() { - frame_updated = true; - sm.update(0); - update(); -} - -void DriverViewScene::paintEvent(QPaintEvent* event) { - QPainter p(this); - - // startup msg - if (!frame_updated) { - p.setPen(QColor(0xff, 0xff, 0xff)); - p.setRenderHint(QPainter::TextAntialiasing); - configFont(p, "Inter", 100, "Bold"); - p.drawText(geometry(), Qt::AlignCenter, "camera starting"); - return; - } - - const int width = 4 * height() / 3; - const QRect rect2 = {rect().center().x() - width / 2, rect().top(), width, rect().height()}; - const QRect valid_rect = {is_rhd ? rect2.right() - rect2.height() / 2 : rect2.left(), rect2.top(), rect2.height() / 2, rect2.height()}; - - // blackout - const int blackout_x_r = valid_rect.right(); - const QRect& blackout_rect = Hardware::TICI() ? rect() : rect2; - const int blackout_w_r = blackout_rect.right() - valid_rect.right(); - const int blackout_x_l = blackout_rect.left(); - const int blackout_w_l = valid_rect.left() - blackout_x_l; - - QColor bg(0, 0, 0, 140); - p.setPen(QPen(bg)); - p.setBrush(QBrush(bg)); - p.drawRect(blackout_x_l, rect2.top(), blackout_w_l, rect2.height()); - p.drawRect(blackout_x_r, rect2.top(), blackout_w_r, rect2.height()); - - // face bounding box - cereal::DriverState::Reader driver_state = sm["driverState"].getDriverState(); - bool face_detected = driver_state.getFaceProb() > 0.4; - if (face_detected) { - auto fxy_list = driver_state.getFacePosition(); - float face_x = fxy_list[0]; - float face_y = fxy_list[1]; - int fbox_x = valid_rect.center().x() + (is_rhd ? face_x : -face_x) * valid_rect.width(); - int fbox_y = valid_rect.center().y() + face_y * valid_rect.height(); - - float alpha = 0.2; - face_x = std::abs(face_x); - face_y = std::abs(face_y); - if (face_x <= 0.35 && face_y <= 0.4) { - alpha = 0.8 - (face_x > face_y ? face_x : face_y) * 0.6 / 0.375; - } - - const int box_size = 0.6 * rect2.height() / 2; - QPen pen(QColor(255, 255, 255, alpha * 255)); - pen.setWidth(10); - p.setPen(pen); - p.setBrush(Qt::NoBrush); - p.drawRoundedRect(fbox_x - box_size / 2, fbox_y - box_size / 2, box_size, box_size, 35.0, 35.0); - } - - // icon - const int img_offset = 30; - const int img_x = is_rhd ? rect2.right() - FACE_IMG_SIZE - img_offset : rect2.left() + img_offset; - const int img_y = rect2.bottom() - FACE_IMG_SIZE - img_offset; - p.setPen(Qt::NoPen); - p.setOpacity(face_detected ? 1.0 : 0.3); - p.drawImage(img_x, img_y, face); -} diff --git a/selfdrive/ui/qt/offroad/driverview.h b/selfdrive/ui/qt/offroad/driverview.h deleted file mode 100644 index 002c8f19f..000000000 --- a/selfdrive/ui/qt/offroad/driverview.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include - -#include - -#include "selfdrive/common/util.h" -#include "selfdrive/ui/qt/widgets/cameraview.h" - -class DriverViewScene : public QWidget { - Q_OBJECT - -public: - explicit DriverViewScene(QWidget *parent); - -public slots: - void frameUpdated(); - -protected: - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - void paintEvent(QPaintEvent *event) override; - -private: - Params params; - SubMaster sm; - QImage face; - bool is_rhd = false; - bool frame_updated = false; -}; - -class DriverViewWindow : public QWidget { - Q_OBJECT - -public: - explicit DriverViewWindow(QWidget *parent); - -signals: - void done(); - -protected: - void mousePressEvent(QMouseEvent* e) override; - -private: - CameraViewWidget *cameraView; - DriverViewScene *scene; - QStackedLayout *layout; -}; diff --git a/selfdrive/ui/qt/offroad/networking.cc b/selfdrive/ui/qt/offroad/networking.cc deleted file mode 100644 index 901315ac5..000000000 --- a/selfdrive/ui/qt/offroad/networking.cc +++ /dev/null @@ -1,236 +0,0 @@ -#include "networking.h" - -#include -#include -#include -#include - -#include "selfdrive/ui/qt/widgets/scrollview.h" -#include "selfdrive/ui/qt/util.h" - -// Networking functions - -Networking::Networking(QWidget* parent, bool show_advanced) : QWidget(parent), show_advanced(show_advanced){ - s = new QStackedLayout; - - QLabel* warning = new QLabel("Network manager is inactive!"); - warning->setAlignment(Qt::AlignCenter); - warning->setStyleSheet(R"(font-size: 65px;)"); - - s->addWidget(warning); - setLayout(s); - - QTimer* timer = new QTimer(this); - QObject::connect(timer, &QTimer::timeout, this, &Networking::refresh); - timer->start(5000); - attemptInitialization(); -} - -void Networking::attemptInitialization(){ - // Checks if network manager is active - try { - wifi = new WifiManager(this); - } catch (std::exception &e) { - return; - } - - connect(wifi, &WifiManager::wrongPassword, this, &Networking::wrongPassword); - - QVBoxLayout* vlayout = new QVBoxLayout; - - if (show_advanced) { - QPushButton* advancedSettings = new QPushButton("Advanced"); - advancedSettings->setStyleSheet("margin-right: 30px;"); - advancedSettings->setFixedSize(350, 100); - connect(advancedSettings, &QPushButton::released, [=](){ s->setCurrentWidget(an); }); - vlayout->addSpacing(10); - vlayout->addWidget(advancedSettings, 0, Qt::AlignRight); - vlayout->addSpacing(10); - } - - wifiWidget = new WifiUI(this, wifi); - connect(wifiWidget, &WifiUI::connectToNetwork, this, &Networking::connectToNetwork); - vlayout->addWidget(new ScrollView(wifiWidget, this), 1); - - QWidget* wifiScreen = new QWidget(this); - wifiScreen->setLayout(vlayout); - s->addWidget(wifiScreen); - - an = new AdvancedNetworking(this, wifi); - connect(an, &AdvancedNetworking::backPress, [=](){s->setCurrentWidget(wifiScreen);}); - s->addWidget(an); - - setStyleSheet(R"( - QPushButton { - font-size: 50px; - margin: 0px; - padding: 15px; - border-width: 0; - border-radius: 30px; - color: #dddddd; - background-color: #444444; - } - QPushButton:disabled { - color: #777777; - background-color: #222222; - } - )"); - s->setCurrentWidget(wifiScreen); - ui_setup_complete = true; -} - -void Networking::refresh(){ - if (!this->isVisible()) { - return; - } - if (!ui_setup_complete) { - attemptInitialization(); - if (!ui_setup_complete) { - return; - } - } - wifiWidget->refresh(); - an->refresh(); -} - -void Networking::connectToNetwork(Network n) { - if (n.security_type == SecurityType::OPEN) { - wifi->connect(n); - } else if (n.security_type == SecurityType::WPA) { - QString pass = InputDialog::getText("Enter password for \"" + n.ssid + "\"", 8); - wifi->connect(n, pass); - } -} - -void Networking::wrongPassword(QString ssid) { - for (Network n : wifi->seen_networks) { - if (n.ssid == ssid) { - QString pass = InputDialog::getText("Wrong password for \"" + n.ssid +"\"", 8); - wifi->connect(n, pass); - return; - } - } -} - -// AdvancedNetworking functions - -AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWidget(parent), wifi(wifi){ - - QVBoxLayout* vlayout = new QVBoxLayout; - vlayout->setMargin(40); - vlayout->setSpacing(20); - - // Back button - QPushButton* back = new QPushButton("Back"); - back->setFixedSize(500, 100); - connect(back, &QPushButton::released, [=](){emit backPress();}); - vlayout->addWidget(back, 0, Qt::AlignLeft); - - // Enable tethering layout - ToggleControl *tetheringToggle = new ToggleControl("Enable Tethering", "", "", wifi->tetheringEnabled()); - vlayout->addWidget(tetheringToggle); - QObject::connect(tetheringToggle, &ToggleControl::toggleFlipped, this, &AdvancedNetworking::toggleTethering); - vlayout->addWidget(horizontal_line(), 0); - - // Change tethering password - editPasswordButton = new ButtonControl("Tethering Password", "EDIT", "", [=](){ - QString pass = InputDialog::getText("Enter new tethering password", 8); - if (pass.size()) { - wifi->changeTetheringPassword(pass); - } - }); - vlayout->addWidget(editPasswordButton, 0); - vlayout->addWidget(horizontal_line(), 0); - - // IP address - ipLabel = new LabelControl("IP Address", wifi->ipv4_address); - vlayout->addWidget(ipLabel, 0); - vlayout->addWidget(horizontal_line(), 0); - - // SSH keys - vlayout->addWidget(new SshToggle()); - vlayout->addWidget(horizontal_line(), 0); - vlayout->addWidget(new SshControl()); - - vlayout->addStretch(1); - setLayout(vlayout); -} - -void AdvancedNetworking::refresh(){ - ipLabel->setText(wifi->ipv4_address); - update(); -} - -void AdvancedNetworking::toggleTethering(bool enable) { - if (enable) { - wifi->enableTethering(); - } else { - wifi->disableTethering(); - } - editPasswordButton->setEnabled(!enable); -} - - -// WifiUI functions - -WifiUI::WifiUI(QWidget *parent, WifiManager* wifi) : QWidget(parent), wifi(wifi) { - vlayout = new QVBoxLayout; - - // Scan on startup - QLabel *scanning = new QLabel("Scanning for networks"); - scanning->setStyleSheet(R"(font-size: 65px;)"); - vlayout->addWidget(scanning, 0, Qt::AlignCenter); - vlayout->setSpacing(25); - - setLayout(vlayout); -} - -void WifiUI::refresh() { - wifi->request_scan(); - wifi->refreshNetworks(); - clearLayout(vlayout); - - connectButtons = new QButtonGroup(this); // TODO check if this is a leak - QObject::connect(connectButtons, qOverload(&QButtonGroup::buttonClicked), this, &WifiUI::handleButton); - - int i = 0; - for (Network &network : wifi->seen_networks) { - QHBoxLayout *hlayout = new QHBoxLayout; - hlayout->addSpacing(50); - - QLabel *ssid_label = new QLabel(QString::fromUtf8(network.ssid)); - ssid_label->setStyleSheet("font-size: 55px;"); - hlayout->addWidget(ssid_label, 1, Qt::AlignLeft); - - // TODO: don't use images for this - // strength indicator - unsigned int strength_scale = network.strength / 17; - QPixmap pix("../assets/images/network_" + QString::number(strength_scale) + ".png"); - QLabel *icon = new QLabel(); - icon->setPixmap(pix.scaledToWidth(100, Qt::SmoothTransformation)); - icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); - hlayout->addWidget(icon, 0, Qt::AlignRight); - - // connect button - QPushButton* btn = new QPushButton(network.security_type == SecurityType::UNSUPPORTED ? "Unsupported" : (network.connected == ConnectedType::CONNECTED ? "Connected" : (network.connected == ConnectedType::CONNECTING ? "Connecting" : "Connect"))); - btn->setDisabled(network.connected == ConnectedType::CONNECTED || network.connected == ConnectedType::CONNECTING || network.security_type == SecurityType::UNSUPPORTED); - btn->setFixedWidth(350); - hlayout->addWidget(btn, 0, Qt::AlignRight); - - connectButtons->addButton(btn, i); - - vlayout->addLayout(hlayout, 1); - // Don't add the last horizontal line - if (i+1 < wifi->seen_networks.size()) { - vlayout->addWidget(horizontal_line(), 0); - } - i++; - } - vlayout->addStretch(3); -} - -void WifiUI::handleButton(QAbstractButton* button) { - QPushButton* btn = static_cast(button); - Network n = wifi->seen_networks[connectButtons->id(btn)]; - emit connectToNetwork(n); -} diff --git a/selfdrive/ui/qt/offroad/networking.h b/selfdrive/ui/qt/offroad/networking.h deleted file mode 100644 index 9fa1cfe88..000000000 --- a/selfdrive/ui/qt/offroad/networking.h +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "selfdrive/ui/qt/offroad/wifiManager.h" -#include "selfdrive/ui/qt/widgets/input.h" -#include "selfdrive/ui/qt/widgets/ssh_keys.h" -#include "selfdrive/ui/qt/widgets/toggle.h" - -class WifiUI : public QWidget { - Q_OBJECT - -public: - explicit WifiUI(QWidget *parent = 0, WifiManager* wifi = 0); - -private: - WifiManager *wifi = nullptr; - QVBoxLayout *vlayout; - - QButtonGroup *connectButtons; - bool tetheringEnabled; - -signals: - void connectToNetwork(Network n); - -public slots: - void refresh(); - void handleButton(QAbstractButton* m_button); -}; - -class AdvancedNetworking : public QWidget { - Q_OBJECT -public: - explicit AdvancedNetworking(QWidget* parent = 0, WifiManager* wifi = 0); - -private: - LabelControl* ipLabel; - ButtonControl* editPasswordButton; - WifiManager* wifi = nullptr; - -signals: - void backPress(); - -public slots: - void toggleTethering(bool enable); - void refresh(); -}; - -class Networking : public QWidget { - Q_OBJECT - -public: - explicit Networking(QWidget* parent = 0, bool show_advanced = true); - -private: - QStackedLayout* s = nullptr; // nm_warning, wifiScreen, advanced - QWidget* wifiScreen = nullptr; - AdvancedNetworking* an = nullptr; - bool ui_setup_complete = false; - bool show_advanced; - - Network selectedNetwork; - - WifiUI* wifiWidget; - WifiManager* wifi = nullptr; - void attemptInitialization(); - -private slots: - void connectToNetwork(Network n); - void refresh(); - void wrongPassword(QString ssid); -}; - diff --git a/selfdrive/ui/qt/offroad/onboarding.cc b/selfdrive/ui/qt/offroad/onboarding.cc deleted file mode 100644 index c0ede84a6..000000000 --- a/selfdrive/ui/qt/offroad/onboarding.cc +++ /dev/null @@ -1,227 +0,0 @@ -#include "onboarding.h" - -#include -#include -#include -#include -#include -#include - -#include "selfdrive/common/params.h" -#include "selfdrive/common/util.h" -#include "selfdrive/ui/qt/home.h" -#include "selfdrive/ui/qt/widgets/input.h" - - -void TrainingGuide::mouseReleaseEvent(QMouseEvent *e) { - QPoint touch = QPoint(e->x(), e->y()) - imageCorner; - //qDebug() << touch.x() << ", " << touch.y(); - - // Check for restart - if (currentIndex == (boundingBox.size() - 1) && 200 <= touch.x() && touch.x() <= 920 && - 760 <= touch.y() && touch.y() <= 960) { - currentIndex = 0; - } else if (boundingBox[currentIndex][0] <= touch.x() && touch.x() <= boundingBox[currentIndex][1] && - boundingBox[currentIndex][2] <= touch.y() && touch.y() <= boundingBox[currentIndex][3]) { - currentIndex += 1; - } - - if (currentIndex >= boundingBox.size()) { - emit completedTraining(); - } else { - image.load("../assets/training/step" + QString::number(currentIndex) + ".png"); - update(); - } -} - -void TrainingGuide::showEvent(QShowEvent *event) { - currentIndex = 0; - image.load("../assets/training/step0.png"); -} - -void TrainingGuide::paintEvent(QPaintEvent *event) { - QPainter painter(this); - - QRect bg(0, 0, painter.device()->width(), painter.device()->height()); - QBrush bgBrush("#000000"); - painter.fillRect(bg, bgBrush); - - QRect rect(image.rect()); - rect.moveCenter(bg.center()); - painter.drawImage(rect.topLeft(), image); - imageCorner = rect.topLeft(); -} - -void TermsPage::showEvent(QShowEvent *event) { - // late init, building QML widget takes 200ms - if (layout()) { - return; - } - - QVBoxLayout *main_layout = new QVBoxLayout; - main_layout->setMargin(40); - main_layout->setSpacing(40); - - QQuickWidget *text = new QQuickWidget(this); - text->setResizeMode(QQuickWidget::SizeRootObjectToView); - text->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - text->setAttribute(Qt::WA_AlwaysStackOnTop); - text->setClearColor(Qt::transparent); - - QString text_view = util::read_file("../assets/offroad/tc.html").c_str(); - text->rootContext()->setContextProperty("text_view", text_view); - text->rootContext()->setContextProperty("font_size", 55); - - text->setSource(QUrl::fromLocalFile("qt/offroad/text_view.qml")); - - main_layout->addWidget(text); - - QObject *obj = (QObject*)text->rootObject(); - QObject::connect(obj, SIGNAL(qmlSignal()), SLOT(enableAccept())); - - QHBoxLayout* buttons = new QHBoxLayout; - main_layout->addLayout(buttons); - - decline_btn = new QPushButton("Decline"); - buttons->addWidget(decline_btn); - QObject::connect(decline_btn, &QPushButton::released, this, &TermsPage::declinedTerms); - - buttons->addSpacing(50); - - accept_btn = new QPushButton("Scroll to accept"); - accept_btn->setEnabled(false); - buttons->addWidget(accept_btn); - QObject::connect(accept_btn, &QPushButton::released, this, &TermsPage::acceptedTerms); - - setLayout(main_layout); - setStyleSheet(R"( - QPushButton { - padding: 50px; - font-size: 50px; - border-radius: 10px; - background-color: #292929; - } - )"); -} - -void TermsPage::enableAccept(){ - accept_btn->setText("Accept"); - accept_btn->setEnabled(true); - return; -} - -void DeclinePage::showEvent(QShowEvent *event) { - if (layout()) { - return; - } - - QVBoxLayout *main_layout = new QVBoxLayout; - main_layout->setMargin(40); - main_layout->setSpacing(40); - - QLabel *text = new QLabel(this); - text->setText("You must accept the Terms and Conditions in order to use openpilot!"); - text->setStyleSheet(R"(font-size: 50px;)"); - main_layout->addWidget(text, 0, Qt::AlignCenter); - - QHBoxLayout* buttons = new QHBoxLayout; - main_layout->addLayout(buttons); - - back_btn = new QPushButton("Back"); - buttons->addWidget(back_btn); - buttons->addSpacing(50); - - QObject::connect(back_btn, &QPushButton::released, this, &DeclinePage::getBack); - - uninstall_btn = new QPushButton("Decline, uninstall openpilot"); - uninstall_btn->setStyleSheet("background-color: #E22C2C;"); - buttons->addWidget(uninstall_btn); - - QObject::connect(uninstall_btn, &QPushButton::released, [=](){ - if (ConfirmationDialog::confirm("Are you sure you want to uninstall?", this)) { - Params().putBool("DoUninstall", true); - } - }); - - setLayout(main_layout); - setStyleSheet(R"( - QPushButton { - padding: 50px; - font-size: 50px; - border-radius: 10px; - background-color: #292929; - } - )"); -} - -void OnboardingWindow::updateActiveScreen() { - updateOnboardingStatus(); - - if (!accepted_terms) { - setCurrentIndex(0); - } else if (!training_done) { - setCurrentIndex(1); - } else { - emit onboardingDone(); - } -} - -OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) { - params = Params(); - current_terms_version = params.get("TermsVersion", false); - current_training_version = params.get("TrainingVersion", false); - - TermsPage* terms = new TermsPage(this); - addWidget(terms); - - connect(terms, &TermsPage::acceptedTerms, [=](){ - Params().put("HasAcceptedTerms", current_terms_version); - updateActiveScreen(); - }); - - TrainingGuide* tr = new TrainingGuide(this); - connect(tr, &TrainingGuide::completedTraining, [=](){ - Params().put("CompletedTrainingVersion", current_training_version); - updateActiveScreen(); - }); - addWidget(tr); - - DeclinePage* declinePage = new DeclinePage(this); - addWidget(declinePage); - - connect(terms, &TermsPage::declinedTerms, [=](){ - setCurrentIndex(2); - }); - - connect(declinePage, &DeclinePage::getBack, [=](){ - updateActiveScreen(); - }); - - setStyleSheet(R"( - * { - color: white; - background-color: black; - } - QPushButton { - padding: 50px; - border-radius: 30px; - background-color: #292929; - } - QPushButton:disabled { - color: #777777; - background-color: #222222; - } - )"); - - updateActiveScreen(); -} - -void OnboardingWindow::updateOnboardingStatus() { - accepted_terms = params.get("HasAcceptedTerms", false).compare(current_terms_version) == 0; - training_done = params.get("CompletedTrainingVersion", false).compare(current_training_version) == 0; -} - -bool OnboardingWindow::isOnboardingDone() { - updateOnboardingStatus(); - return accepted_terms && training_done; -} diff --git a/selfdrive/ui/qt/offroad/onboarding.h b/selfdrive/ui/qt/offroad/onboarding.h deleted file mode 100644 index 51a055d87..000000000 --- a/selfdrive/ui/qt/offroad/onboarding.h +++ /dev/null @@ -1,115 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "selfdrive/common/params.h" - -class TrainingGuide : public QFrame { - Q_OBJECT - -public: - explicit TrainingGuide(QWidget *parent = 0) : QFrame(parent) {}; - -protected: - void showEvent(QShowEvent *event) override; - void paintEvent(QPaintEvent *event) override; - void mouseReleaseEvent(QMouseEvent* e) override; - -private: - QImage image; - QPoint imageCorner; - int currentIndex = 0; - - // Bounding boxes for the a given training guide step - // (minx, maxx, miny, maxy) - QVector> boundingBox { - {650, 1375, 700, 900}, - {1600, 1920, 0, 1080}, - {1600, 1920, 0, 1080}, - {1240, 1750, 480, 1080}, - {1570, 1780, 620, 750}, - {1600, 1920, 0, 1080}, - {1630, 1740, 620, 780}, - {1200, 1920, 0, 1080}, - {1455, 1850, 400, 660}, - {1460, 1800, 195, 520}, - {1600, 1920, 0, 1080}, - {1350, 1920, 65, 1080}, - {1600, 1920, 0, 1080}, - {1570, 1900, 130, 1000}, - {1350, 1770, 500, 700}, - {1600, 1920, 0, 1080}, - {1600, 1920, 0, 1080}, - {1000, 1800, 760, 954}, - }; - -signals: - void completedTraining(); -}; - - -class TermsPage : public QFrame { - Q_OBJECT - -public: - explicit TermsPage(QWidget *parent = 0) : QFrame(parent) {}; - -protected: - void showEvent(QShowEvent *event) override; - -private: - QPushButton *accept_btn; - QPushButton *decline_btn; - -public slots: - void enableAccept(); - -signals: - void acceptedTerms(); - void declinedTerms(); -}; - -class DeclinePage : public QFrame { - Q_OBJECT - -public: - explicit DeclinePage(QWidget *parent = 0) : QFrame(parent) {}; - -protected: - void showEvent(QShowEvent *event) override; - -private: - QPushButton *back_btn; - QPushButton *uninstall_btn; - -signals: - void getBack(); -}; - -class OnboardingWindow : public QStackedWidget { - Q_OBJECT - -public: - explicit OnboardingWindow(QWidget *parent = 0); - bool isOnboardingDone(); - -private: - Params params; - std::string current_terms_version; - std::string current_training_version; - bool accepted_terms = false; - bool training_done = false; - void updateOnboardingStatus(); - -signals: - void onboardingDone(); - void resetTrainingGuide(); - -public slots: - void updateActiveScreen(); -}; diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc deleted file mode 100644 index 39108667a..000000000 --- a/selfdrive/ui/qt/offroad/settings.cc +++ /dev/null @@ -1,425 +0,0 @@ -#include "settings.h" - -#include -#include - -#ifndef QCOM -#include "selfdrive/ui/qt/offroad/networking.h" -#endif -#include "selfdrive/common/params.h" -#include "selfdrive/common/util.h" -#include "selfdrive/hardware/hw.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/input.h" -#include "selfdrive/ui/qt/widgets/offroad_alerts.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" -#include "selfdrive/ui/qt/widgets/ssh_keys.h" -#include "selfdrive/ui/qt/widgets/toggle.h" -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/util.h" - -TogglesPanel::TogglesPanel(QWidget *parent) : QWidget(parent) { - QVBoxLayout *toggles_list = new QVBoxLayout(); - - QList toggles; - - toggles.append(new ParamControl("OpenpilotEnabledToggle", - "Enable openpilot", - "Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.", - "../assets/offroad/icon_openpilot.png", - this)); - toggles.append(new ParamControl("IsLdwEnabled", - "Enable Lane Departure Warnings", - "Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31mph (50kph).", - "../assets/offroad/icon_warning.png", - this)); - toggles.append(new ParamControl("IsRHD", - "Enable Right-Hand Drive", - "Allow openpilot to obey left-hand traffic conventions and perform driver monitoring on right driver seat.", - "../assets/offroad/icon_openpilot_mirrored.png", - this)); - toggles.append(new ParamControl("IsMetric", - "Use Metric System", - "Display speed in km/h instead of mp/h.", - "../assets/offroad/icon_metric.png", - this)); - toggles.append(new ParamControl("CommunityFeaturesToggle", - "Enable Community Features", - "Use features from the open source community that are not maintained or supported by comma.ai and have not been confirmed to meet the standard safety model. These features include community supported cars and community supported hardware. Be extra cautious when using these features", - "../assets/offroad/icon_shell.png", - this)); - - toggles.append(new ParamControl("UploadRaw", - "Upload Raw Logs", - "Upload full logs and full resolution video by default while on WiFi. If not enabled, individual logs can be marked for upload at my.comma.ai/useradmin.", - "../assets/offroad/icon_network.png", - this)); - - ParamControl *record_toggle = new ParamControl("RecordFront", - "Record and Upload Driver Camera", - "Upload data from the driver facing camera and help improve the driver monitoring algorithm.", - "../assets/offroad/icon_monitoring.png", - this); - toggles.append(record_toggle); - toggles.append(new ParamControl("EndToEndToggle", - "\U0001f96c Disable use of lanelines (Alpha) \U0001f96c", - "In this mode openpilot will ignore lanelines and just drive how it thinks a human would.", - "../assets/offroad/icon_road.png", - this)); - - if (Hardware::TICI()) { - toggles.append(new ParamControl("EnableWideCamera", - "Enable use of Wide Angle Camera", - "Use wide angle camera for driving and ui.", - "../assets/offroad/icon_openpilot.png", - this)); - QObject::connect(toggles.back(), &ToggleControl::toggleFlipped, [=](bool state) { - Params().remove("CalibrationParams"); - }); - - toggles.append(new ParamControl("EnableLteOnroad", - "Enable LTE while onroad", - "", - "../assets/offroad/icon_network.png", - this)); - } - - bool record_lock = Params().getBool("RecordFrontLock"); - record_toggle->setEnabled(!record_lock); - - for(ParamControl *toggle : toggles){ - if(toggles_list->count() != 0){ - toggles_list->addWidget(horizontal_line()); - } - toggles_list->addWidget(toggle); - } - - setLayout(toggles_list); -} - -DevicePanel::DevicePanel(QWidget* parent) : QWidget(parent) { - QVBoxLayout *device_layout = new QVBoxLayout; - Params params = Params(); - - QString dongle = QString::fromStdString(params.get("DongleId", false)); - device_layout->addWidget(new LabelControl("Dongle ID", dongle)); - device_layout->addWidget(horizontal_line()); - - QString serial = QString::fromStdString(params.get("HardwareSerial", false)); - device_layout->addWidget(new LabelControl("Serial", serial)); - - // offroad-only buttons - QList offroad_btns; - - offroad_btns.append(new ButtonControl("Driver Camera", "PREVIEW", - "Preview the driver facing camera to help optimize device mounting position for best driver monitoring experience. (vehicle must be off)", - [=]() { emit showDriverView(); }, "", this)); - - QString resetCalibDesc = "openpilot requires the device to be mounted within 4° left or right and within 5° up or down. openpilot is continuously calibrating, resetting is rarely required."; - ButtonControl *resetCalibBtn = new ButtonControl("Reset Calibration", "RESET", resetCalibDesc, [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to reset calibration?", this)) { - Params().remove("CalibrationParams"); - } - }, "", this); - connect(resetCalibBtn, &ButtonControl::showDescription, [=]() { - QString desc = resetCalibDesc; - std::string calib_bytes = Params().get("CalibrationParams"); - if (!calib_bytes.empty()) { - try { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(calib_bytes.data(), calib_bytes.size())); - auto calib = cmsg.getRoot().getLiveCalibration(); - if (calib.getCalStatus() != 0) { - double pitch = calib.getRpyCalib()[1] * (180 / M_PI); - double yaw = calib.getRpyCalib()[2] * (180 / M_PI); - desc += QString(" Your device is pointed %1° %2 and %3° %4.") - .arg(QString::number(std::abs(pitch), 'g', 1), pitch > 0 ? "up" : "down", - QString::number(std::abs(yaw), 'g', 1), yaw > 0 ? "right" : "left"); - } - } catch (kj::Exception) { - qInfo() << "invalid CalibrationParams"; - } - } - resetCalibBtn->setDescription(desc); - }); - offroad_btns.append(resetCalibBtn); - - offroad_btns.append(new ButtonControl("Review Training Guide", "REVIEW", - "Review the rules, features, and limitations of openpilot", [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to review the training guide?", this)) { - Params().remove("CompletedTrainingVersion"); - emit reviewTrainingGuide(); - } - }, "", this)); - - QString brand = params.getBool("Passive") ? "dashcam" : "openpilot"; - offroad_btns.append(new ButtonControl("Uninstall " + brand, "UNINSTALL", "", [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to uninstall?", this)) { - Params().putBool("DoUninstall", true); - } - }, "", this)); - - for(auto &btn : offroad_btns){ - device_layout->addWidget(horizontal_line()); - QObject::connect(parent, SIGNAL(offroadTransition(bool)), btn, SLOT(setEnabled(bool))); - device_layout->addWidget(btn); - } - - // power buttons - QHBoxLayout *power_layout = new QHBoxLayout(); - power_layout->setSpacing(30); - - QPushButton *reboot_btn = new QPushButton("Reboot"); - power_layout->addWidget(reboot_btn); - QObject::connect(reboot_btn, &QPushButton::released, [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to reboot?", this)) { - Hardware::reboot(); - } - }); - - QPushButton *poweroff_btn = new QPushButton("Power Off"); - poweroff_btn->setStyleSheet("background-color: #E22C2C;"); - power_layout->addWidget(poweroff_btn); - QObject::connect(poweroff_btn, &QPushButton::released, [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to power off?", this)) { - Hardware::poweroff(); - } - }); - - device_layout->addLayout(power_layout); - - setLayout(device_layout); - setStyleSheet(R"( - QPushButton { - padding: 0; - height: 120px; - border-radius: 15px; - background-color: #393939; - } - )"); -} - -SoftwarePanel::SoftwarePanel(QWidget* parent) : QFrame(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - setLayout(main_layout); - setStyleSheet(R"(QLabel {font-size: 50px;})"); - - fs_watch = new QFileSystemWatcher(this); - QObject::connect(fs_watch, &QFileSystemWatcher::fileChanged, [=](const QString path) { - int update_failed_count = Params().get("UpdateFailedCount").value_or(0); - if (path.contains("UpdateFailedCount") && update_failed_count > 0) { - lastUpdateTimeLbl->setText("failed to fetch update"); - updateButton->setText("CHECK"); - updateButton->setEnabled(true); - } else if (path.contains("LastUpdateTime")) { - updateLabels(); - } - }); -} - -void SoftwarePanel::showEvent(QShowEvent *event) { - updateLabels(); -} - -void SoftwarePanel::updateLabels() { - Params params = Params(); - std::string brand = params.getBool("Passive") ? "dashcam" : "openpilot"; - QList> dev_params = { - {"Git Branch", params.get("GitBranch")}, - {"Git Commit", params.get("GitCommit").substr(0, 10)}, - {"Panda Firmware", params.get("PandaFirmwareHex")}, - {"OS Version", Hardware::get_os_version()}, - }; - - QString version = QString::fromStdString(brand + " v" + params.get("Version").substr(0, 14)).trimmed(); - QString lastUpdateTime = ""; - - std::string last_update_param = params.get("LastUpdateTime"); - if (!last_update_param.empty()){ - QDateTime lastUpdateDate = QDateTime::fromString(QString::fromStdString(last_update_param + "Z"), Qt::ISODate); - lastUpdateTime = timeAgo(lastUpdateDate); - } - - if (labels.size() < dev_params.size()) { - versionLbl = new LabelControl("Version", version, QString::fromStdString(params.get("ReleaseNotes")).trimmed()); - layout()->addWidget(versionLbl); - layout()->addWidget(horizontal_line()); - - lastUpdateTimeLbl = new LabelControl("Last Update Check", lastUpdateTime, "The last time openpilot successfully checked for an update. The updater only runs while the car is off."); - layout()->addWidget(lastUpdateTimeLbl); - layout()->addWidget(horizontal_line()); - - updateButton = new ButtonControl("Check for Update", "CHECK", "", [=]() { - Params params = Params(); - if (params.getBool("IsOffroad")) { - fs_watch->addPath(QString::fromStdString(params.getParamsPath()) + "/d/LastUpdateTime"); - fs_watch->addPath(QString::fromStdString(params.getParamsPath()) + "/d/UpdateFailedCount"); - updateButton->setText("CHECKING"); - updateButton->setEnabled(false); - } - std::system("pkill -1 -f selfdrive.updated"); - }, "", this); - layout()->addWidget(updateButton); - layout()->addWidget(horizontal_line()); - } else { - versionLbl->setText(version); - lastUpdateTimeLbl->setText(lastUpdateTime); - updateButton->setText("CHECK"); - updateButton->setEnabled(true); - } - - for (int i = 0; i < dev_params.size(); i++) { - const auto &[name, value] = dev_params[i]; - QString val = QString::fromStdString(value).trimmed(); - if (labels.size() > i) { - labels[i]->setText(val); - } else { - labels.push_back(new LabelControl(name, val)); - layout()->addWidget(labels[i]); - if (i < (dev_params.size() - 1)) { - layout()->addWidget(horizontal_line()); - } - } - } -} - -QWidget * network_panel(QWidget * parent) { -#ifdef QCOM - QVBoxLayout *layout = new QVBoxLayout; - layout->setSpacing(30); - - // wifi + tethering buttons - layout->addWidget(new ButtonControl("WiFi Settings", "OPEN", "", - [=]() { HardwareEon::launch_wifi(); })); - layout->addWidget(horizontal_line()); - - layout->addWidget(new ButtonControl("Tethering Settings", "OPEN", "", - [=]() { HardwareEon::launch_tethering(); })); - layout->addWidget(horizontal_line()); - - // SSH key management - layout->addWidget(new SshToggle()); - layout->addWidget(horizontal_line()); - layout->addWidget(new SshControl()); - - layout->addStretch(1); - - QWidget *w = new QWidget; - w->setLayout(layout); -#else - Networking *w = new Networking(parent); -#endif - return w; -} - -void SettingsWindow::showEvent(QShowEvent *event) { - if (layout()) { - panel_widget->setCurrentIndex(0); - nav_btns->buttons()[0]->setChecked(true); - return; - } - - // setup two main layouts - QVBoxLayout *sidebar_layout = new QVBoxLayout(); - sidebar_layout->setMargin(0); - panel_widget = new QStackedWidget(); - panel_widget->setStyleSheet(R"( - border-radius: 30px; - background-color: #292929; - )"); - - // close button - QPushButton *close_btn = new QPushButton("X"); - close_btn->setStyleSheet(R"( - font-size: 90px; - font-weight: bold; - border 1px grey solid; - border-radius: 100px; - background-color: #292929; - )"); - close_btn->setFixedSize(200, 200); - sidebar_layout->addSpacing(45); - sidebar_layout->addWidget(close_btn, 0, Qt::AlignCenter); - QObject::connect(close_btn, &QPushButton::released, this, &SettingsWindow::closeSettings); - - // setup panels - DevicePanel *device = new DevicePanel(this); - QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide); - QObject::connect(device, &DevicePanel::showDriverView, this, &SettingsWindow::showDriverView); - - QPair panels[] = { - {"Device", device}, - {"Network", network_panel(this)}, - {"Toggles", new TogglesPanel(this)}, - {"Software", new SoftwarePanel()}, - }; - - sidebar_layout->addSpacing(45); - nav_btns = new QButtonGroup(); - for (auto &[name, panel] : panels) { - QPushButton *btn = new QPushButton(name); - btn->setCheckable(true); - btn->setChecked(nav_btns->buttons().size() == 0); - btn->setStyleSheet(R"( - QPushButton { - color: grey; - border: none; - background: none; - font-size: 65px; - font-weight: 500; - padding-top: 35px; - padding-bottom: 35px; - } - QPushButton:checked { - color: white; - } - )"); - - nav_btns->addButton(btn); - sidebar_layout->addWidget(btn, 0, Qt::AlignRight); - - panel->setContentsMargins(50, 25, 50, 25); - - ScrollView *panel_frame = new ScrollView(panel, this); - panel_widget->addWidget(panel_frame); - - QObject::connect(btn, &QPushButton::released, [=, w = panel_frame]() { - panel_widget->setCurrentWidget(w); - }); - } - sidebar_layout->setContentsMargins(50, 50, 100, 50); - - // main settings layout, sidebar + main panel - QHBoxLayout *settings_layout = new QHBoxLayout(); - - sidebar_widget = new QWidget; - sidebar_widget->setLayout(sidebar_layout); - sidebar_widget->setFixedWidth(500); - settings_layout->addWidget(sidebar_widget); - settings_layout->addWidget(panel_widget); - - setLayout(settings_layout); - setStyleSheet(R"( - * { - color: white; - font-size: 50px; - } - SettingsWindow { - background-color: black; - } - )"); -} - -void SettingsWindow::hideEvent(QHideEvent *event){ -#ifdef QCOM - HardwareEon::close_activities(); -#endif - - // TODO: this should be handled by the Dialog classes - QList children = findChildren(); - for(auto &w : children){ - if(w->metaObject()->superClass()->className() == QString("QDialog")){ - w->close(); - } - } -} diff --git a/selfdrive/ui/qt/offroad/settings.h b/selfdrive/ui/qt/offroad/settings.h deleted file mode 100644 index b0ae4875b..000000000 --- a/selfdrive/ui/qt/offroad/settings.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "selfdrive/ui/qt/widgets/controls.h" - -// ********** settings window + top-level panels ********** - -class DevicePanel : public QWidget { - Q_OBJECT -public: - explicit DevicePanel(QWidget* parent = nullptr); -signals: - void reviewTrainingGuide(); - void showDriverView(); -}; - -class TogglesPanel : public QWidget { - Q_OBJECT -public: - explicit TogglesPanel(QWidget *parent = nullptr); -}; - -class SoftwarePanel : public QFrame { - Q_OBJECT -public: - explicit SoftwarePanel(QWidget* parent = nullptr); - -protected: - void showEvent(QShowEvent *event) override; - -private: - QList labels; - LabelControl *versionLbl; - LabelControl *lastUpdateTimeLbl; - ButtonControl *updateButton; - void updateLabels(); - - QFileSystemWatcher *fs_watch; -}; - -class SettingsWindow : public QFrame { - Q_OBJECT - -public: - explicit SettingsWindow(QWidget *parent = 0) : QFrame(parent) {}; - -protected: - void hideEvent(QHideEvent *event) override; - void showEvent(QShowEvent *event) override; - -signals: - void closeSettings(); - void offroadTransition(bool offroad); - void reviewTrainingGuide(); - void showDriverView(); - -private: - QPushButton *sidebar_alert_widget; - QWidget *sidebar_widget; - QButtonGroup *nav_btns; - QStackedWidget *panel_widget; -}; diff --git a/selfdrive/ui/qt/offroad/wifiManager.cc b/selfdrive/ui/qt/offroad/wifiManager.cc deleted file mode 100644 index 7ffaccb1c..000000000 --- a/selfdrive/ui/qt/offroad/wifiManager.cc +++ /dev/null @@ -1,522 +0,0 @@ -#include "wifiManager.h" - -#include - -#include -#include - -#include "selfdrive/common/params.h" -#include "selfdrive/common/swaglog.h" - -/** - * We are using a NetworkManager DBUS API : https://developer.gnome.org/NetworkManager/1.26/spec.html - * */ - -// https://developer.gnome.org/NetworkManager/1.26/nm-dbus-types.html#NM80211ApFlags -const int NM_802_11_AP_FLAGS_PRIVACY = 0x00000001; - -// https://developer.gnome.org/NetworkManager/1.26/nm-dbus-types.html#NM80211ApSecurityFlags -const int NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001; -const int NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002; -const int NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010; -const int NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020; -const int NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100; -const int NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200; - -const QString nm_path = "/org/freedesktop/NetworkManager"; -const QString nm_settings_path = "/org/freedesktop/NetworkManager/Settings"; - -const QString nm_iface = "org.freedesktop.NetworkManager"; -const QString props_iface = "org.freedesktop.DBus.Properties"; -const QString nm_settings_iface = "org.freedesktop.NetworkManager.Settings"; -const QString nm_settings_conn_iface = "org.freedesktop.NetworkManager.Settings.Connection"; -const QString device_iface = "org.freedesktop.NetworkManager.Device"; -const QString wireless_device_iface = "org.freedesktop.NetworkManager.Device.Wireless"; -const QString ap_iface = "org.freedesktop.NetworkManager.AccessPoint"; -const QString connection_iface = "org.freedesktop.NetworkManager.Connection.Active"; -const QString ipv4config_iface = "org.freedesktop.NetworkManager.IP4Config"; - -const QString nm_service = "org.freedesktop.NetworkManager"; - -const int state_connected = 100; -const int state_need_auth = 60; -const int reason_wrong_password = 8; -const int dbus_timeout = 100; - -template -T get_response(QDBusMessage response) { - QVariant first = response.arguments().at(0); - QDBusVariant dbvFirst = first.value(); - QVariant vFirst = dbvFirst.variant(); - if (vFirst.canConvert()) { - return vFirst.value(); - } else { - LOGE("Variant unpacking failure"); - return T(); - } -} - -bool compare_by_strength(const Network &a, const Network &b) { - if (a.connected == ConnectedType::CONNECTED) return true; - if (b.connected == ConnectedType::CONNECTED) return false; - if (a.connected == ConnectedType::CONNECTING) return true; - if (b.connected == ConnectedType::CONNECTING) return false; - return a.strength > b.strength; -} - -WifiManager::WifiManager(QWidget* parent) { - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - connecting_to_network = ""; - adapter = get_adapter(); - - bool has_adapter = adapter != ""; - if (!has_adapter){ - throw std::runtime_error("Error connecting to NetworkManager"); - } - - QDBusInterface nm(nm_service, adapter, device_iface, bus); - bus.connect(nm_service, adapter, device_iface, "StateChanged", this, SLOT(change(unsigned int, unsigned int, unsigned int))); - - QDBusInterface device_props(nm_service, adapter, props_iface, bus); - device_props.setTimeout(dbus_timeout); - QDBusMessage response = device_props.call("Get", device_iface, "State"); - raw_adapter_state = get_response(response); - change(raw_adapter_state, 0, 0); - - // Set tethering ssid as "weedle" + first 4 characters of a dongle id - tethering_ssid = "weedle"; - std::string bytes = Params().get("DongleId"); - if (bytes.length() >= 4) { - tethering_ssid+="-"+QString::fromStdString(bytes.substr(0,4)); - } - - // Create dbus interface for tethering button. This populates the introspection cache, - // making sure all future creations are non-blocking - // https://bugreports.qt.io/browse/QTBUG-14485 - QDBusInterface(nm_service, nm_settings_path, nm_settings_iface, bus); -} - -void WifiManager::refreshNetworks() { - seen_networks.clear(); - seen_ssids.clear(); - ipv4_address = get_ipv4_address(); - for (Network &network : get_networks()) { - if (seen_ssids.count(network.ssid)) { - continue; - } - seen_ssids.push_back(network.ssid); - seen_networks.push_back(network); - } - -} - -QString WifiManager::get_ipv4_address(){ - if (raw_adapter_state != state_connected){ - return ""; - } - QVector conns = get_active_connections(); - for (auto &p : conns){ - QString active_connection = p.path(); - QDBusInterface nm(nm_service, active_connection, props_iface, bus); - nm.setTimeout(dbus_timeout); - - QDBusObjectPath pth = get_response(nm.call("Get", connection_iface, "Ip4Config")); - QString ip4config = pth.path(); - - QString type = get_response(nm.call("Get", connection_iface, "Type")); - - if (type == "802-11-wireless") { - QDBusInterface nm2(nm_service, ip4config, props_iface, bus); - nm2.setTimeout(dbus_timeout); - - const QDBusArgument &arr = get_response(nm2.call("Get", ipv4config_iface, "AddressData")); - QMap pth2; - arr.beginArray(); - while (!arr.atEnd()){ - arr >> pth2; - QString ipv4 = pth2.value("address").value(); - arr.endArray(); - return ipv4; - } - arr.endArray(); - } - } - return ""; -} - -QList WifiManager::get_networks() { - QList r; - QDBusInterface nm(nm_service, adapter, wireless_device_iface, bus); - nm.setTimeout(dbus_timeout); - - QDBusMessage response = nm.call("GetAllAccessPoints"); - QVariant first = response.arguments().at(0); - - QString active_ap = get_active_ap(); - const QDBusArgument &args = first.value(); - args.beginArray(); - while (!args.atEnd()) { - QDBusObjectPath path; - args >> path; - - QByteArray ssid = get_property(path.path(), "Ssid"); - unsigned int strength = get_ap_strength(path.path()); - SecurityType security = getSecurityType(path.path()); - ConnectedType ctype; - if (path.path() != active_ap) { - ctype = ConnectedType::DISCONNECTED; - } else { - if (ssid == connecting_to_network) { - ctype = ConnectedType::CONNECTING; - } else { - ctype = ConnectedType::CONNECTED; - } - } - Network network = {path.path(), ssid, strength, ctype, security}; - - if (ssid.length()) { - r.push_back(network); - } - } - args.endArray(); - - std::sort(r.begin(), r.end(), compare_by_strength); - return r; -} - -SecurityType WifiManager::getSecurityType(QString path) { - int sflag = get_property(path, "Flags").toInt(); - int wpaflag = get_property(path, "WpaFlags").toInt(); - int rsnflag = get_property(path, "RsnFlags").toInt(); - int wpa_props = wpaflag | rsnflag; - - // obtained by looking at flags of networks in the office as reported by an Android phone - const int supports_wpa = NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104 | NM_802_11_AP_SEC_GROUP_WEP40 | NM_802_11_AP_SEC_GROUP_WEP104 | NM_802_11_AP_SEC_KEY_MGMT_PSK; - - if (sflag == 0) { - return SecurityType::OPEN; - } else if ((sflag & NM_802_11_AP_FLAGS_PRIVACY) && (wpa_props & supports_wpa) && !(wpa_props & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { - return SecurityType::WPA; - } else { - return SecurityType::UNSUPPORTED; - } -} - -void WifiManager::connect(Network n) { - return connect(n, "", ""); -} - -void WifiManager::connect(Network n, QString password) { - return connect(n, "", password); -} - -void WifiManager::connect(Network n, QString username, QString password) { - connecting_to_network = n.ssid; - // disconnect(); - clear_connections(n.ssid); //Clear all connections that may already exist to the network we are connecting - connect(n.ssid, username, password, n.security_type); -} - -void WifiManager::connect(QByteArray ssid, QString username, QString password, SecurityType security_type) { - Connection connection; - connection["connection"]["type"] = "802-11-wireless"; - connection["connection"]["uuid"] = QUuid::createUuid().toString().remove('{').remove('}'); - connection["connection"]["id"] = "openpilot connection "+QString::fromStdString(ssid.toStdString()); - connection["connection"]["autoconnect-retries"] = 0; - - connection["802-11-wireless"]["ssid"] = ssid; - connection["802-11-wireless"]["mode"] = "infrastructure"; - - if (security_type == SecurityType::WPA) { - connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk"; - connection["802-11-wireless-security"]["auth-alg"] = "open"; - connection["802-11-wireless-security"]["psk"] = password; - } - - connection["ipv4"]["method"] = "auto"; - connection["ipv6"]["method"] = "ignore"; - - QDBusInterface nm_settings(nm_service, nm_settings_path, nm_settings_iface, bus); - nm_settings.setTimeout(dbus_timeout); - - nm_settings.call("AddConnection", QVariant::fromValue(connection)); - activate_wifi_connection(QString(ssid)); -} - -void WifiManager::deactivate_connections(QString ssid) { - for (QDBusObjectPath active_connection_raw : get_active_connections()) { - QString active_connection = active_connection_raw.path(); - QDBusInterface nm(nm_service, active_connection, props_iface, bus); - nm.setTimeout(dbus_timeout); - - QDBusObjectPath pth = get_response(nm.call("Get", connection_iface, "SpecificObject")); - if (pth.path() != "" && pth.path() != "/") { - QString Ssid = get_property(pth.path(), "Ssid"); - if (Ssid == ssid) { - QDBusInterface nm2(nm_service, nm_path, nm_iface, bus); - nm2.setTimeout(dbus_timeout); - nm2.call("DeactivateConnection", QVariant::fromValue(active_connection_raw));// TODO change to disconnect - } - } - } -} - -QVector WifiManager::get_active_connections() { - QDBusInterface nm(nm_service, nm_path, props_iface, bus); - nm.setTimeout(dbus_timeout); - - QDBusMessage response = nm.call("Get", nm_iface, "ActiveConnections"); - const QDBusArgument &arr = get_response(response); - QVector conns; - - QDBusObjectPath path; - arr.beginArray(); - while (!arr.atEnd()) { - arr >> path; - conns.push_back(path); - } - arr.endArray(); - return conns; -} - -void WifiManager::clear_connections(QString ssid) { - for(QDBusObjectPath path : list_connections()){ - QDBusInterface nm2(nm_service, path.path(), nm_settings_conn_iface, bus); - nm2.setTimeout(dbus_timeout); - - QDBusMessage response = nm2.call("GetSettings"); - - const QDBusArgument &dbusArg = response.arguments().at(0).value(); - - QMap> map; - dbusArg >> map; - for (auto &inner : map) { - for (auto &val : inner) { - QString key = inner.key(val); - if (key == "ssid") { - if (val == ssid) { - nm2.call("Delete"); - } - } - } - } - } -} - -void WifiManager::request_scan() { - QDBusInterface nm(nm_service, adapter, wireless_device_iface, bus); - nm.setTimeout(dbus_timeout); - nm.call("RequestScan", QVariantMap()); -} - -uint WifiManager::get_wifi_device_state() { - QDBusInterface device_props(nm_service, adapter, props_iface, bus); - device_props.setTimeout(dbus_timeout); - - QDBusMessage response = device_props.call("Get", device_iface, "State"); - uint resp = get_response(response); - return resp; -} - -QString WifiManager::get_active_ap() { - QDBusInterface device_props(nm_service, adapter, props_iface, bus); - device_props.setTimeout(dbus_timeout); - - QDBusMessage response = device_props.call("Get", wireless_device_iface, "ActiveAccessPoint"); - QDBusObjectPath r = get_response(response); - return r.path(); -} - -QByteArray WifiManager::get_property(QString network_path ,QString property) { - QDBusInterface device_props(nm_service, network_path, props_iface, bus); - device_props.setTimeout(dbus_timeout); - - QDBusMessage response = device_props.call("Get", ap_iface, property); - return get_response(response); -} - -unsigned int WifiManager::get_ap_strength(QString network_path) { - QDBusInterface device_props(nm_service, network_path, props_iface, bus); - device_props.setTimeout(dbus_timeout); - - QDBusMessage response = device_props.call("Get", ap_iface, "Strength"); - return get_response(response); -} - -QString WifiManager::get_adapter() { - QDBusInterface nm(nm_service, nm_path, nm_iface, bus); - nm.setTimeout(dbus_timeout); - - QDBusMessage response = nm.call("GetDevices"); - QVariant first = response.arguments().at(0); - - QString adapter_path = ""; - - const QDBusArgument &args = first.value(); - args.beginArray(); - while (!args.atEnd()) { - QDBusObjectPath path; - args >> path; - - // Get device type - QDBusInterface device_props(nm_service, path.path(), props_iface, bus); - device_props.setTimeout(dbus_timeout); - - QDBusMessage response = device_props.call("Get", device_iface, "DeviceType"); - uint device_type = get_response(response); - - if (device_type == 2) { // Wireless - adapter_path = path.path(); - break; - } - } - args.endArray(); - - return adapter_path; -} - -void WifiManager::change(unsigned int new_state, unsigned int previous_state, unsigned int change_reason) { - raw_adapter_state = new_state; - if (new_state == state_need_auth && change_reason == reason_wrong_password) { - emit wrongPassword(connecting_to_network); - } else if (new_state == state_connected) { - emit successfulConnection(connecting_to_network); - connecting_to_network = ""; - } -} - -void WifiManager::disconnect() { - QString active_ap = get_active_ap(); - if (active_ap != "" && active_ap != "/") { - deactivate_connections(get_property(active_ap, "Ssid")); - } -} - -QVector WifiManager::list_connections(){ - QVector connections; - QDBusInterface nm(nm_service, nm_settings_path, nm_settings_iface, bus); - nm.setTimeout(dbus_timeout); - - QDBusMessage response = nm.call("ListConnections"); - QVariant first = response.arguments().at(0); - const QDBusArgument &args = first.value(); - args.beginArray(); - while (!args.atEnd()) { - QDBusObjectPath path; - args >> path; - connections.push_back(path); - } - return connections; -} - -bool WifiManager::activate_wifi_connection(QString ssid){ - QString devicePath = get_adapter(); - - for(QDBusObjectPath path : list_connections()){ - QDBusInterface nm2(nm_service, path.path(), nm_settings_conn_iface, bus); - nm2.setTimeout(dbus_timeout); - - QDBusMessage response = nm2.call("GetSettings"); - const QDBusArgument &dbusArg = response.arguments().at(0).value(); - - QMap> map; - dbusArg >> map; - for (auto &inner : map) { - for (auto &val : inner) { - QString key = inner.key(val); - if (key == "ssid") { - if (val == ssid) { - QDBusInterface nm3(nm_service, nm_path, nm_iface, bus); - nm3.setTimeout(dbus_timeout); - nm3.call("ActivateConnection", QVariant::fromValue(path), QVariant::fromValue(QDBusObjectPath(devicePath)), QVariant::fromValue(QDBusObjectPath("/"))); - return true; - } - } - } - } - } - return false; -} -//Functions for tethering -bool WifiManager::activate_tethering_connection(){ - QString devicePath = get_adapter(); - - for(QDBusObjectPath path : list_connections()){ - QDBusInterface nm2(nm_service, path.path(), nm_settings_conn_iface, bus); - nm2.setTimeout(dbus_timeout); - - QDBusMessage response = nm2.call("GetSettings"); - const QDBusArgument &dbusArg = response.arguments().at(0).value(); - - QMap> map; - dbusArg >> map; - for (auto &inner : map) { - for (auto &val : inner) { - QString key = inner.key(val); - if (key == "ssid") { - if (val == tethering_ssid.toUtf8()) { - QDBusInterface nm3(nm_service, nm_path, nm_iface, bus); - nm3.setTimeout(dbus_timeout); - nm3.call("ActivateConnection", QVariant::fromValue(path), QVariant::fromValue(QDBusObjectPath(devicePath)), QVariant::fromValue(QDBusObjectPath("/"))); - return true; - } - } - } - } - } - return false; -} -void WifiManager::addTetheringConnection(){ - Connection connection; - connection["connection"]["id"] = "Hotspot"; - connection["connection"]["uuid"] = QUuid::createUuid().toString().remove('{').remove('}'); - connection["connection"]["type"] = "802-11-wireless"; - connection["connection"]["interface-name"] = "wlan0"; - connection["connection"]["autoconnect"] = false; - - connection["802-11-wireless"]["band"] = "bg"; - connection["802-11-wireless"]["mode"] = "ap"; - connection["802-11-wireless"]["ssid"] = tethering_ssid.toUtf8(); - - connection["802-11-wireless-security"]["group"] = QStringList("ccmp"); - connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk"; - connection["802-11-wireless-security"]["pairwise"] = QStringList("ccmp"); - connection["802-11-wireless-security"]["proto"] = QStringList("rsn"); - connection["802-11-wireless-security"]["psk"] = tetheringPassword; - - connection["ipv4"]["method"] = "shared"; - QMap address; - address["address"] = "192.168.43.1"; - address["prefix"] = 24u; - connection["ipv4"]["address-data"] = QVariant::fromValue(IpConfig() << address); - connection["ipv4"]["gateway"] = "192.168.43.1"; - connection["ipv6"]["method"] = "ignore"; - - QDBusInterface nm_settings(nm_service, nm_settings_path, nm_settings_iface, bus); - nm_settings.setTimeout(dbus_timeout); - nm_settings.call("AddConnection", QVariant::fromValue(connection)); -} - -void WifiManager::enableTethering() { - if(activate_tethering_connection()){ - return; - } - addTetheringConnection(); - activate_tethering_connection(); -} - -void WifiManager::disableTethering() { - deactivate_connections(tethering_ssid.toUtf8()); -} - -bool WifiManager::tetheringEnabled() { - QString active_ap = get_active_ap(); - return get_property(active_ap, "Ssid") == tethering_ssid; -} - -void WifiManager::changeTetheringPassword(QString newPassword){ - tetheringPassword = newPassword; - clear_connections(tethering_ssid.toUtf8()); - addTetheringConnection(); -} diff --git a/selfdrive/ui/qt/offroad/wifiManager.h b/selfdrive/ui/qt/offroad/wifiManager.h deleted file mode 100644 index bbbe2e3ed..000000000 --- a/selfdrive/ui/qt/offroad/wifiManager.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include -#include - -enum class SecurityType { - OPEN, - WPA, - UNSUPPORTED -}; -enum class ConnectedType{ - DISCONNECTED, - CONNECTING, - CONNECTED -}; - -typedef QMap> Connection; -typedef QVector> IpConfig; - -struct Network { - QString path; - QByteArray ssid; - unsigned int strength; - ConnectedType connected; - SecurityType security_type; -}; - -class WifiManager : public QWidget { - Q_OBJECT -public: - explicit WifiManager(QWidget* parent); - - void request_scan(); - QVector seen_networks; - QString ipv4_address; - - void refreshNetworks(); - void connect(Network ssid); - void connect(Network ssid, QString password); - void connect(Network ssid, QString username, QString password); - void disconnect(); - - // Tethering functions - void enableTethering(); - void disableTethering(); - bool tetheringEnabled(); - - bool activate_tethering_connection(); - void addTetheringConnection(); - bool activate_wifi_connection(QString ssid); - void changeTetheringPassword(QString newPassword); - -private: - QVector seen_ssids; - QString adapter;//Path to network manager wifi-device - QDBusConnection bus = QDBusConnection::systemBus(); - unsigned int raw_adapter_state;//Connection status https://developer.gnome.org/NetworkManager/1.26/nm-dbus-types.html#NMDeviceState - QString connecting_to_network; - QString tethering_ssid; - QString tetheringPassword = "swagswagcommma"; - - QString get_adapter(); - QString get_ipv4_address(); - QList get_networks(); - void connect(QByteArray ssid, QString username, QString password, SecurityType security_type); - QString get_active_ap(); - void deactivate_connections(QString ssid); - void clear_connections(QString ssid); - QVector get_active_connections(); - uint get_wifi_device_state(); - QByteArray get_property(QString network_path, QString property); - unsigned int get_ap_strength(QString network_path); - SecurityType getSecurityType(QString ssid); - QVector list_connections(); - -private slots: - void change(unsigned int new_state, unsigned int previous_state, unsigned int change_reason); -signals: - void wrongPassword(QString ssid); - void successfulConnection(QString ssid); - void refresh(); -}; diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc deleted file mode 100644 index e26aff7bc..000000000 --- a/selfdrive/ui/qt/onroad.cc +++ /dev/null @@ -1,246 +0,0 @@ -#include "selfdrive/ui/qt/onroad.h" - -#include - -#include "selfdrive/common/swaglog.h" -#include "selfdrive/common/timing.h" -#include "selfdrive/ui/paint.h" -#include "selfdrive/ui/qt/util.h" - -#ifdef ENABLE_MAPS -#include "selfdrive/ui/qt/maps/map.h" -#endif - -OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { - layout = new QStackedLayout(this); - layout->setStackingMode(QStackedLayout::StackAll); - - // old UI on bottom - nvg = new NvgWindow(this); - QObject::connect(this, &OnroadWindow::update, nvg, &NvgWindow::update); - - split = new QHBoxLayout(); - split->setContentsMargins(0, 0, 0, 0); - split->setSpacing(0); - split->addWidget(nvg); - - - QWidget * split_wrapper = new QWidget; - split_wrapper->setLayout(split); - layout->addWidget(split_wrapper); - - alerts = new OnroadAlerts(this); - alerts->setAttribute(Qt::WA_TransparentForMouseEvents, true); - QObject::connect(this, &OnroadWindow::update, alerts, &OnroadAlerts::updateState); - QObject::connect(this, &OnroadWindow::offroadTransitionSignal, alerts, &OnroadAlerts::offroadTransition); - QObject::connect(this, &OnroadWindow::offroadTransitionSignal, this, &OnroadWindow::offroadTransition); - layout->addWidget(alerts); - - // setup stacking order - alerts->raise(); - - setLayout(layout); - setAttribute(Qt::WA_OpaquePaintEvent); -} - - -void OnroadWindow::offroadTransition(bool offroad) { -#ifdef ENABLE_MAPS - if (!offroad) { - QString token = QString::fromStdString(Params().get("MapboxToken")); - if (map == nullptr && !token.isEmpty()){ - QMapboxGLSettings settings; - settings.setCacheDatabasePath("/data/mbgl-cache.db"); - settings.setCacheDatabaseMaximumSize(20 * 1024 * 1024); - settings.setAccessToken(token.trimmed()); - - MapWindow * m = new MapWindow(settings); - QObject::connect(this, &OnroadWindow::offroadTransitionSignal, m, &MapWindow::offroadTransition); - split->addWidget(m); - - map = m; - } - - } -#endif -} - -// ***** onroad widgets ***** - -OnroadAlerts::OnroadAlerts(QWidget *parent) : QWidget(parent) { - for (auto &kv : sound_map) { - auto path = QUrl::fromLocalFile(kv.second.first); - sounds[kv.first].setSource(path); - } -} - -void OnroadAlerts::updateState(const UIState &s) { - SubMaster &sm = *(s.sm); - if (sm.updated("carState")) { - // scale volume with speed - volume = util::map_val(sm["carState"].getCarState().getVEgo(), 0.f, 20.f, - Hardware::MIN_VOLUME, Hardware::MAX_VOLUME); - } - if (sm["deviceState"].getDeviceState().getStarted()) { - if (sm.updated("controlsState")) { - const cereal::ControlsState::Reader &cs = sm["controlsState"].getControlsState(); - updateAlert(QString::fromStdString(cs.getAlertText1()), QString::fromStdString(cs.getAlertText2()), - cs.getAlertBlinkingRate(), cs.getAlertType(), cs.getAlertSize(), cs.getAlertSound()); - } else if ((sm.frame - s.scene.started_frame) > 10 * UI_FREQ) { - // Handle controls timeout - if (sm.rcv_frame("controlsState") < s.scene.started_frame) { - // car is started, but controlsState hasn't been seen at all - updateAlert("openpilot Unavailable", "Waiting for controls to start", 0, - "controlsWaiting", cereal::ControlsState::AlertSize::MID, AudibleAlert::NONE); - } else if ((sm.frame - sm.rcv_frame("controlsState")) > 5 * UI_FREQ) { - // car is started, but controls is lagging or died - updateAlert("TAKE CONTROL IMMEDIATELY", "Controls Unresponsive", 0, - "controlsUnresponsive", cereal::ControlsState::AlertSize::FULL, AudibleAlert::CHIME_WARNING_REPEAT); - - // TODO: clean this up once Qt handles the border - QUIState::ui_state.status = STATUS_ALERT; - } - } - } - - // TODO: add blinking back if performant - //float alpha = 0.375 * cos((millis_since_boot() / 1000) * 2 * M_PI * blinking_rate) + 0.625; - bg = bg_colors[s.status]; -} - -void OnroadAlerts::offroadTransition(bool offroad) { - updateAlert("", "", 0, "", cereal::ControlsState::AlertSize::NONE, AudibleAlert::NONE); -} - -void OnroadAlerts::updateAlert(const QString &t1, const QString &t2, float blink_rate, - const std::string &type, cereal::ControlsState::AlertSize size, AudibleAlert sound) { - if (alert_type.compare(type) == 0 && text1.compare(t1) == 0) { - return; - } - - stopSounds(); - if (sound != AudibleAlert::NONE) { - playSound(sound); - } - - text1 = t1; - text2 = t2; - alert_type = type; - alert_size = size; - blinking_rate = blink_rate; - - update(); -} - -void OnroadAlerts::playSound(AudibleAlert alert) { - int loops = sound_map[alert].second ? QSoundEffect::Infinite : 0; - sounds[alert].setLoopCount(loops); - sounds[alert].setVolume(volume); - sounds[alert].play(); -} - -void OnroadAlerts::stopSounds() { - for (auto &kv : sounds) { - // Only stop repeating sounds - if (kv.second.loopsRemaining() == QSoundEffect::Infinite) { - kv.second.stop(); - } - } -} - -void OnroadAlerts::paintEvent(QPaintEvent *event) { - QPainter p(this); - - if (alert_size == cereal::ControlsState::AlertSize::NONE) { - return; - } - static std::map alert_sizes = { - {cereal::ControlsState::AlertSize::SMALL, 271}, - {cereal::ControlsState::AlertSize::MID, 420}, - {cereal::ControlsState::AlertSize::FULL, height()}, - }; - int h = alert_sizes[alert_size]; - QRect r = QRect(0, height() - h, width(), h); - - // draw background + gradient - p.setPen(Qt::NoPen); - p.setCompositionMode(QPainter::CompositionMode_DestinationOver); - - p.setBrush(QBrush(bg)); - p.drawRect(r); - - QLinearGradient g(0, r.y(), 0, r.bottom()); - g.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.05)); - g.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0.35)); - p.setBrush(QBrush(g)); - p.fillRect(r, g); - p.setCompositionMode(QPainter::CompositionMode_SourceOver); - - // remove bottom border - r = QRect(0, height() - h, width(), h - 30); - - // text - const QPoint c = r.center(); - p.setPen(QColor(0xff, 0xff, 0xff)); - p.setRenderHint(QPainter::TextAntialiasing); - if (alert_size == cereal::ControlsState::AlertSize::SMALL) { - configFont(p, "Open Sans", 74, "SemiBold"); - p.drawText(r, Qt::AlignCenter, text1); - } else if (alert_size == cereal::ControlsState::AlertSize::MID) { - configFont(p, "Open Sans", 88, "Bold"); - p.drawText(QRect(0, c.y() - 125, width(), 150), Qt::AlignHCenter | Qt::AlignTop, text1); - configFont(p, "Open Sans", 66, "Regular"); - p.drawText(QRect(0, c.y() + 21, width(), 90), Qt::AlignHCenter, text2); - } else if (alert_size == cereal::ControlsState::AlertSize::FULL) { - bool l = text1.length() > 15; - configFont(p, "Open Sans", l ? 132 : 177, "Bold"); - p.drawText(QRect(0, r.y() + (l ? 240 : 270), width(), 600), Qt::AlignHCenter | Qt::TextWordWrap, text1); - configFont(p, "Open Sans", 88, "Regular"); - p.drawText(QRect(0, r.height() - (l ? 361 : 420), width(), 300), Qt::AlignHCenter | Qt::TextWordWrap, text2); - } -} - - -NvgWindow::NvgWindow(QWidget *parent) : QOpenGLWidget(parent) { - setAttribute(Qt::WA_OpaquePaintEvent); -} - -NvgWindow::~NvgWindow() { - makeCurrent(); - doneCurrent(); -} - -void NvgWindow::initializeGL() { - initializeOpenGLFunctions(); - std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl; - std::cout << "OpenGL vendor: " << glGetString(GL_VENDOR) << std::endl; - std::cout << "OpenGL renderer: " << glGetString(GL_RENDERER) << std::endl; - std::cout << "OpenGL language version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; - - ui_nvg_init(&QUIState::ui_state); - prev_draw_t = millis_since_boot(); -} - -void NvgWindow::update(const UIState &s) { - // Connecting to visionIPC requires opengl to be current - if (s.vipc_client->connected){ - makeCurrent(); - } - repaint(); -} - -void NvgWindow::resizeGL(int w, int h) { - ui_resize(&QUIState::ui_state, w, h); -} - -void NvgWindow::paintGL() { - ui_draw(&QUIState::ui_state, width(), height()); - - double cur_draw_t = millis_since_boot(); - double dt = cur_draw_t - prev_draw_t; - if (dt > 66) { - // warn on sub 15fps - LOGW("slow frame time: %.2f", dt); - } - prev_draw_t = cur_draw_t; -} diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h deleted file mode 100644 index c3baf0103..000000000 --- a/selfdrive/ui/qt/onroad.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include "cereal/gen/cpp/log.capnp.h" -#include "selfdrive/hardware/hw.h" -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/qt_window.h" - -typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert; - -// ***** onroad widgets ***** - -class OnroadAlerts : public QWidget { - Q_OBJECT - -public: - OnroadAlerts(QWidget *parent = 0); - -protected: - void paintEvent(QPaintEvent*) override; - -private: - void stopSounds(); - void playSound(AudibleAlert alert); - void updateAlert(const QString &t1, const QString &t2, float blink_rate, - const std::string &type, cereal::ControlsState::AlertSize size, AudibleAlert sound); - - std::map> sound_map { - // AudibleAlert, (file path, inf loop) - {AudibleAlert::CHIME_DISENGAGE, {"../assets/sounds/disengaged.wav", false}}, - {AudibleAlert::CHIME_ENGAGE, {"../assets/sounds/engaged.wav", false}}, - {AudibleAlert::CHIME_WARNING1, {"../assets/sounds/warning_1.wav", false}}, - {AudibleAlert::CHIME_WARNING2, {"../assets/sounds/warning_2.wav", false}}, - {AudibleAlert::CHIME_WARNING2_REPEAT, {"../assets/sounds/warning_2.wav", true}}, - {AudibleAlert::CHIME_WARNING_REPEAT, {"../assets/sounds/warning_repeat.wav", true}}, - {AudibleAlert::CHIME_ERROR, {"../assets/sounds/error.wav", false}}, - {AudibleAlert::CHIME_PROMPT, {"../assets/sounds/error.wav", false}} - }; - - QColor bg; - float volume = Hardware::MIN_VOLUME; - std::map sounds; - float blinking_rate = 0; - QString text1, text2; - std::string alert_type; - cereal::ControlsState::AlertSize alert_size; - -public slots: - void updateState(const UIState &s); - void offroadTransition(bool offroad); -}; - -// container window for the NVG UI -class NvgWindow : public QOpenGLWidget, protected QOpenGLFunctions { - Q_OBJECT - -public: - using QOpenGLWidget::QOpenGLWidget; - explicit NvgWindow(QWidget* parent = 0); - ~NvgWindow(); - -protected: - void paintGL() override; - void initializeGL() override; - void resizeGL(int w, int h) override; - -private: - double prev_draw_t = 0; - -public slots: - void update(const UIState &s); -}; - -// container for all onroad widgets -class OnroadWindow : public QWidget { - Q_OBJECT - -public: - OnroadWindow(QWidget* parent = 0); - QWidget *map = nullptr; - -private: - OnroadAlerts *alerts; - NvgWindow *nvg; - QStackedLayout *layout; - QHBoxLayout* split; - -signals: - void update(const UIState &s); - void offroadTransitionSignal(bool offroad); - -private slots: - void offroadTransition(bool offroad); -}; diff --git a/selfdrive/ui/qt/qt_window.h b/selfdrive/ui/qt/qt_window.h deleted file mode 100644 index 295ab083f..000000000 --- a/selfdrive/ui/qt/qt_window.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -#include -#include - -#ifdef QCOM2 -#include -#include -#include -#endif - -#include "selfdrive/hardware/hw.h" - -const int vwp_w = Hardware::TICI() ? 2160 : 1920; -const int vwp_h = 1080; - -inline void setMainWindow(QWidget *w) { - const float scale = getenv("SCALE") != NULL ? std::stof(getenv("SCALE")) : 1.0; - w->setFixedSize(vwp_w*scale, vwp_h*scale); - w->show(); - -#ifdef QCOM2 - QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface(); - wl_surface *s = reinterpret_cast(native->nativeResourceForWindow("surface", w->windowHandle())); - wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270); - wl_surface_commit(s); - w->showFullScreen(); -#endif -} diff --git a/selfdrive/ui/qt/request_repeater.cc b/selfdrive/ui/qt/request_repeater.cc deleted file mode 100644 index ee6680cc7..000000000 --- a/selfdrive/ui/qt/request_repeater.cc +++ /dev/null @@ -1,13 +0,0 @@ -#include "request_repeater.h" - -RequestRepeater::RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey, - int period) : HttpRequest(parent, requestURL, cacheKey) { - timer = new QTimer(this); - timer->setTimerType(Qt::VeryCoarseTimer); - QObject::connect(timer, &QTimer::timeout, [=](){ - if (!QUIState::ui_state.scene.started && QUIState::ui_state.awake && reply == NULL) { - sendRequest(requestURL); - } - }); - timer->start(period * 1000); -} diff --git a/selfdrive/ui/qt/request_repeater.h b/selfdrive/ui/qt/request_repeater.h deleted file mode 100644 index c23bbbcf1..000000000 --- a/selfdrive/ui/qt/request_repeater.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "selfdrive/ui/qt/api.h" -#include "selfdrive/ui/ui.h" - -class RequestRepeater : public HttpRequest { -public: - RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey = "", int period = 0); - -private: - QTimer *timer; -}; diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc deleted file mode 100644 index 198d99be1..000000000 --- a/selfdrive/ui/qt/sidebar.cc +++ /dev/null @@ -1,115 +0,0 @@ -#include "selfdrive/ui/qt/sidebar.h" - -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/common/util.h" -#include "selfdrive/hardware/hw.h" -#include "selfdrive/ui/qt/util.h" - -void Sidebar::drawMetric(QPainter &p, const QString &label, const QString &val, QColor c, int y) { - const QRect rect = {30, y, 240, val.isEmpty() ? (label.contains("\n") ? 124 : 100) : 148}; - - p.setPen(Qt::NoPen); - p.setBrush(QBrush(c)); - p.setClipRect(rect.x() + 6, rect.y(), 18, rect.height(), Qt::ClipOperation::ReplaceClip); - p.drawRoundedRect(QRect(rect.x() + 6, rect.y() + 6, 100, rect.height() - 12), 10, 10); - p.setClipping(false); - - QPen pen = QPen(QColor(0xff, 0xff, 0xff, 0x55)); - pen.setWidth(2); - p.setPen(pen); - p.setBrush(Qt::NoBrush); - p.drawRoundedRect(rect, 20, 20); - - p.setPen(QColor(0xff, 0xff, 0xff)); - if (val.isEmpty()) { - configFont(p, "Open Sans", 35, "Bold"); - const QRect r = QRect(rect.x() + 35, rect.y(), rect.width() - 50, rect.height()); - p.drawText(r, Qt::AlignCenter, label); - } else { - configFont(p, "Open Sans", 58, "Bold"); - p.drawText(rect.x() + 50, rect.y() + 71, val); - configFont(p, "Open Sans", 35, "Regular"); - p.drawText(rect.x() + 50, rect.y() + 50 + 77, label); - } -} - -Sidebar::Sidebar(QWidget *parent) : QFrame(parent) { - home_img = QImage("../assets/images/button_home.png").scaled(180, 180, Qt::KeepAspectRatio, Qt::SmoothTransformation); - settings_img = QImage("../assets/images/button_settings.png").scaled(settings_btn.width(), settings_btn.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);; - - connect(this, &Sidebar::valueChanged, [=] { update(); }); - - setFixedWidth(300); - setMinimumHeight(vwp_h); - setStyleSheet("background-color: rgb(57, 57, 57);"); -} - -void Sidebar::mousePressEvent(QMouseEvent *event) { - if (settings_btn.contains(event->pos())) { - emit openSettings(); - } -} - -void Sidebar::updateState(const UIState &s) { - auto &sm = *(s.sm); - - auto deviceState = sm["deviceState"].getDeviceState(); - setProperty("netType", network_type[deviceState.getNetworkType()]); - setProperty("netStrength", signal_imgs[deviceState.getNetworkStrength()]); - - auto last_ping = deviceState.getLastAthenaPingTime(); - if (last_ping == 0) { - setProperty("connectStr", "OFFLINE"); - setProperty("connectStatus", warning_color); - } else { - bool online = nanos_since_boot() - last_ping < 80e9; - setProperty("connectStr", online ? "ONLINE" : "ERROR"); - setProperty("connectStatus", online ? good_color : danger_color); - } - - QColor tempStatus = danger_color; - auto ts = deviceState.getThermalStatus(); - if (ts == cereal::DeviceState::ThermalStatus::GREEN) { - tempStatus = good_color; - } else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) { - tempStatus = warning_color; - } - setProperty("tempStatus", tempStatus); - setProperty("tempVal", (int)deviceState.getAmbientTempC()); - - QString pandaStr = "VEHICLE\nONLINE"; - QColor pandaStatus = good_color; - if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) { - pandaStatus = danger_color; - pandaStr = "NO\nPANDA"; - } else if (Hardware::TICI() && s.scene.started) { - pandaStr = QString("SATS %1\nACC %2").arg(s.scene.satelliteCount).arg(fmin(10, s.scene.gpsAccuracy), 0, 'f', 2); - pandaStatus = sm["liveLocationKalman"].getLiveLocationKalman().getGpsOK() ? good_color : warning_color; - } - setProperty("pandaStr", pandaStr); - setProperty("pandaStatus", pandaStatus); -} - -void Sidebar::paintEvent(QPaintEvent *event) { - QPainter p(this); - p.setPen(Qt::NoPen); - p.setRenderHint(QPainter::Antialiasing); - - // static imgs - p.setOpacity(0.65); - p.drawImage(settings_btn.x(), settings_btn.y(), settings_img); - p.setOpacity(1.0); - p.drawImage(60, 1080 - 180 - 40, home_img); - - // network - p.drawImage(58, 196, net_strength); - configFont(p, "Open Sans", 35, "Regular"); - p.setPen(QColor(0xff, 0xff, 0xff)); - const QRect r = QRect(50, 247, 100, 50); - p.drawText(r, Qt::AlignCenter, net_type); - - // metrics - drawMetric(p, "TEMP", QString("%1°C").arg(temp_val), temp_status, 338); - drawMetric(p, panda_str, "", panda_status, 518); - drawMetric(p, "CONNECT\n" + connect_str, "", connect_status, 676); -} diff --git a/selfdrive/ui/qt/sidebar.h b/selfdrive/ui/qt/sidebar.h deleted file mode 100644 index f03871045..000000000 --- a/selfdrive/ui/qt/sidebar.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include - -#include "selfdrive/ui/ui.h" - -class Sidebar : public QFrame { - Q_OBJECT - Q_PROPERTY(QString connectStr MEMBER connect_str NOTIFY valueChanged); - Q_PROPERTY(QColor connectStatus MEMBER connect_status NOTIFY valueChanged); - Q_PROPERTY(QString pandaStr MEMBER panda_str NOTIFY valueChanged); - Q_PROPERTY(QColor pandaStatus MEMBER panda_status NOTIFY valueChanged); - Q_PROPERTY(int tempVal MEMBER temp_val NOTIFY valueChanged); - Q_PROPERTY(QColor tempStatus MEMBER temp_status NOTIFY valueChanged); - Q_PROPERTY(QString netType MEMBER net_type NOTIFY valueChanged); - Q_PROPERTY(QImage netStrength MEMBER net_strength NOTIFY valueChanged); - -public: - explicit Sidebar(QWidget* parent = 0); - -signals: - void openSettings(); - void valueChanged(); - -public slots: - void updateState(const UIState &s); - -protected: - void paintEvent(QPaintEvent *event) override; - void mousePressEvent(QMouseEvent *event) override; - -private: - void drawMetric(QPainter &p, const QString &label, const QString &val, QColor c, int y); - - QImage home_img, settings_img; - const QMap network_type = { - {cereal::DeviceState::NetworkType::NONE, "--"}, - {cereal::DeviceState::NetworkType::WIFI, "WiFi"}, - {cereal::DeviceState::NetworkType::CELL2_G, "2G"}, - {cereal::DeviceState::NetworkType::CELL3_G, "3G"}, - {cereal::DeviceState::NetworkType::CELL4_G, "LTE"}, - {cereal::DeviceState::NetworkType::CELL5_G, "5G"} - }; - const QMap signal_imgs = { - {cereal::DeviceState::NetworkStrength::UNKNOWN, QImage("../assets/images/network_0.png")}, - {cereal::DeviceState::NetworkStrength::POOR, QImage("../assets/images/network_1.png")}, - {cereal::DeviceState::NetworkStrength::MODERATE, QImage("../assets/images/network_2.png")}, - {cereal::DeviceState::NetworkStrength::GOOD, QImage("../assets/images/network_3.png")}, - {cereal::DeviceState::NetworkStrength::GREAT, QImage("../assets/images/network_4.png")}, - }; - - const QRect settings_btn = QRect(50, 35, 200, 117); - const QColor good_color = QColor(255, 255, 255); - const QColor warning_color = QColor(218, 202, 37); - const QColor danger_color = QColor(201, 34, 49); - - QString connect_str = "OFFLINE"; - QColor connect_status = warning_color; - QString panda_str = "NO\nPANDA"; - QColor panda_status = warning_color; - int temp_val = 0; - QColor temp_status = warning_color; - QString net_type; - QImage net_strength; -}; diff --git a/selfdrive/ui/qt/spinner b/selfdrive/ui/qt/spinner new file mode 100755 index 000000000..42b98ffdc Binary files /dev/null and b/selfdrive/ui/qt/spinner differ diff --git a/selfdrive/ui/qt/spinner.cc b/selfdrive/ui/qt/spinner.cc deleted file mode 100644 index b91bd7bc4..000000000 --- a/selfdrive/ui/qt/spinner.cc +++ /dev/null @@ -1,134 +0,0 @@ -#include "spinner.h" - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "selfdrive/hardware/hw.h" -#include "selfdrive/ui/qt/qt_window.h" - -TrackWidget::TrackWidget(QWidget *parent) : QWidget(parent) { - setFixedSize(spinner_size); - setAutoFillBackground(false); - - comma_img = QPixmap("../assets/img_spinner_comma.png").scaled(spinner_size, Qt::KeepAspectRatio, Qt::SmoothTransformation); - - // pre-compute all the track imgs. make this a gif instead? - QTransform transform; - QPixmap track_img = QPixmap("../assets/img_spinner_track.png").scaled(spinner_size, Qt::KeepAspectRatio, Qt::SmoothTransformation); - for (auto &img : track_imgs) { - img = track_img.transformed(transform.rotate(360/spinner_fps), Qt::SmoothTransformation); - } - - m_anim.setDuration(1000); - m_anim.setStartValue(0); - m_anim.setEndValue(int(track_imgs.size() -1)); - m_anim.setLoopCount(-1); - m_anim.start(); - connect(&m_anim, SIGNAL(valueChanged(QVariant)), SLOT(update())); -} - -void TrackWidget::paintEvent(QPaintEvent *event) { - QPainter painter(this); - QRect bg(0, 0, painter.device()->width(), painter.device()->height()); - QBrush bgBrush("#000000"); - painter.fillRect(bg, bgBrush); - - int track_idx = m_anim.currentValue().toInt(); - QRect rect(track_imgs[track_idx].rect()); - rect.moveCenter(bg.center()); - painter.drawPixmap(rect.topLeft(), track_imgs[track_idx]); - - rect = comma_img.rect(); - rect.moveCenter(bg.center()); - painter.drawPixmap(rect.topLeft(), comma_img); -} - -// Spinner - -Spinner::Spinner(QWidget *parent) { - QGridLayout *main_layout = new QGridLayout(); - main_layout->setSpacing(0); - main_layout->setMargin(200); - - main_layout->addWidget(new TrackWidget(this), 0, 0, Qt::AlignHCenter | Qt::AlignVCenter); - - text = new QLabel(); - text->setVisible(false); - main_layout->addWidget(text, 1, 0, Qt::AlignHCenter); - - progress_bar = new QProgressBar(); - progress_bar->setRange(5, 100); - progress_bar->setTextVisible(false); - progress_bar->setVisible(false); - progress_bar->setFixedHeight(20); - main_layout->addWidget(progress_bar, 1, 0, Qt::AlignHCenter); - - setLayout(main_layout); - setStyleSheet(R"( - Spinner { - background-color: black; - } - * { - background-color: transparent; - } - QLabel { - color: white; - font-size: 80px; - } - QProgressBar { - background-color: #373737; - width: 1000px; - border solid white; - border-radius: 10px; - } - QProgressBar::chunk { - border-radius: 10px; - background-color: white; - } - )"); - - notifier = new QSocketNotifier(fileno(stdin), QSocketNotifier::Read); - QObject::connect(notifier, &QSocketNotifier::activated, this, &Spinner::update); -}; - -void Spinner::update(int n) { - std::string line; - std::getline(std::cin, line); - - if (line.length()) { - bool number = std::all_of(line.begin(), line.end(), ::isdigit); - text->setVisible(!number); - progress_bar->setVisible(number); - text->setText(QString::fromStdString(line)); - if (number) { - progress_bar->setValue(std::stoi(line)); - } - } -} - -int main(int argc, char *argv[]) { - QSurfaceFormat fmt; -#ifdef __APPLE__ - fmt.setVersion(3, 2); - fmt.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - fmt.setRenderableType(QSurfaceFormat::OpenGL); -#else - fmt.setRenderableType(QSurfaceFormat::OpenGLES); -#endif - QSurfaceFormat::setDefaultFormat(fmt); - - Hardware::set_display_power(true); - Hardware::set_brightness(65); - - QApplication a(argc, argv); - Spinner spinner; - setMainWindow(&spinner); - return a.exec(); -} diff --git a/selfdrive/ui/qt/spinner.h b/selfdrive/ui/qt/spinner.h deleted file mode 100644 index c54aea103..000000000 --- a/selfdrive/ui/qt/spinner.h +++ /dev/null @@ -1,39 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include - -constexpr int spinner_fps = 30; -constexpr QSize spinner_size = QSize(360, 360); - -class TrackWidget : public QWidget { - Q_OBJECT -public: - TrackWidget(QWidget *parent = nullptr); - -private: - void paintEvent(QPaintEvent *event) override; - std::array track_imgs; - QPixmap comma_img; - QVariantAnimation m_anim; -}; - -class Spinner : public QWidget { - Q_OBJECT - -public: - explicit Spinner(QWidget *parent = 0); - -private: - QLabel *text; - QProgressBar *progress_bar; - QSocketNotifier *notifier; - -public slots: - void update(int n); -}; diff --git a/selfdrive/ui/qt/text b/selfdrive/ui/qt/text new file mode 100755 index 000000000..60241436d Binary files /dev/null and b/selfdrive/ui/qt/text differ diff --git a/selfdrive/ui/qt/text.cc b/selfdrive/ui/qt/text.cc deleted file mode 100644 index 0708b30db..000000000 --- a/selfdrive/ui/qt/text.cc +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "selfdrive/hardware/hw.h" -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - -int main(int argc, char *argv[]) { - QApplication a(argc, argv); - QWidget window; - setMainWindow(&window); - - Hardware::set_display_power(true); - Hardware::set_brightness(65); - - QGridLayout *layout = new QGridLayout; - layout->setMargin(50); - - QLabel *label = new QLabel(argv[1]); - label->setWordWrap(true); - label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); - ScrollView *scroll = new ScrollView(label); - scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - layout->addWidget(scroll, 0, 0, Qt::AlignTop); - - // Scroll to the bottom - QObject::connect(scroll->verticalScrollBar(), &QAbstractSlider::rangeChanged, [=](){ - scroll->verticalScrollBar()->setValue(scroll->verticalScrollBar()->maximum()); - }); - - QPushButton *btn = new QPushButton(); -#ifdef __aarch64__ - btn->setText("Reboot"); - QObject::connect(btn, &QPushButton::released, [=]() { - Hardware::reboot(); - }); -#else - btn->setText("Exit"); - QObject::connect(btn, &QPushButton::released, &a, &QApplication::quit); -#endif - layout->addWidget(btn, 0, 0, Qt::AlignRight | Qt::AlignBottom); - - window.setLayout(layout); - window.setStyleSheet(R"( - * { - outline: none; - color: white; - background-color: black; - font-size: 60px; - } - QPushButton { - padding: 50px; - padding-right: 100px; - padding-left: 100px; - border: 2px solid white; - border-radius: 20px; - margin-right: 40px; - } - )"); - - return a.exec(); -} diff --git a/selfdrive/ui/qt/util.h b/selfdrive/ui/qt/util.h deleted file mode 100644 index c8c33504d..000000000 --- a/selfdrive/ui/qt/util.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -inline void configFont(QPainter &p, QString family, int size, const QString &style) { - QFont f(family); - f.setPixelSize(size); - f.setStyleName(style); - p.setFont(f); -} - -inline void clearLayout(QLayout* layout) { - while (QLayoutItem* item = layout->takeAt(0)) { - if (QWidget* widget = item->widget()) { - widget->deleteLater(); - } - if (QLayout* childLayout = item->layout()) { - clearLayout(childLayout); - } - delete item; - } -} - -inline QString timeAgo(const QDateTime &date) { - int diff = date.secsTo(QDateTime::currentDateTimeUtc()); - - QString s; - if (diff < 60) { - s = "now"; - } else if (diff < 60 * 60) { - int minutes = diff / 60; - s = QString("%1 minute%2 ago").arg(minutes).arg(minutes > 1 ? "s" : ""); - } else if (diff < 60 * 60 * 24) { - int hours = diff / (60 * 60); - s = QString("%1 hour%2 ago").arg(hours).arg(hours > 1 ? "s" : ""); - } else if (diff < 3600 * 24 * 7) { - int days = diff / (60 * 60 * 24); - s = QString("%1 day%2 ago").arg(days).arg(days > 1 ? "s" : ""); - } else { - s = date.date().toString(); - } - - return s; -} diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc deleted file mode 100644 index e8909c95b..000000000 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ /dev/null @@ -1,217 +0,0 @@ -#include "selfdrive/ui/qt/widgets/cameraview.h" - -#include "selfdrive/ui/qt/qt_window.h" - -namespace { -const char frame_vertex_shader[] = -#ifdef NANOVG_GL3_IMPLEMENTATION - "#version 150 core\n" -#else - "#version 300 es\n" -#endif - "in vec4 aPosition;\n" - "in vec4 aTexCoord;\n" - "uniform mat4 uTransform;\n" - "out vec4 vTexCoord;\n" - "void main() {\n" - " gl_Position = uTransform * aPosition;\n" - " vTexCoord = aTexCoord;\n" - "}\n"; - -const char frame_fragment_shader[] = -#ifdef NANOVG_GL3_IMPLEMENTATION - "#version 150 core\n" -#else - "#version 300 es\n" -#endif - "precision mediump float;\n" - "uniform sampler2D uTexture;\n" - "in vec4 vTexCoord;\n" - "out vec4 colorOut;\n" - "void main() {\n" - " colorOut = texture(uTexture, vTexCoord.xy);\n" -#ifdef QCOM - " vec3 dz = vec3(0.0627f, 0.0627f, 0.0627f);\n" - " colorOut.rgb = ((vec3(1.0f, 1.0f, 1.0f) - dz) * colorOut.rgb / vec3(1.0f, 1.0f, 1.0f)) + dz;\n" -#endif - "}\n"; - -const mat4 device_transform = {{ - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, -}}; - -mat4 get_driver_view_transform() { - const float driver_view_ratio = 1.333; - mat4 transform; - if (Hardware::TICI()) { - // from dmonitoring.cc - const int full_width_tici = 1928; - const int full_height_tici = 1208; - const int adapt_width_tici = 668; - const int crop_x_offset = 32; - const int crop_y_offset = -196; - const float yscale = full_height_tici * driver_view_ratio / adapt_width_tici; - const float xscale = yscale*(1080)/(2160)*full_width_tici/full_height_tici; - transform = (mat4){{ - xscale, 0.0, 0.0, xscale*crop_x_offset/full_width_tici*2, - 0.0, yscale, 0.0, yscale*crop_y_offset/full_height_tici*2, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - }}; - } else { - // frame from 4/3 to 16/9 display - transform = (mat4){{ - driver_view_ratio*(1080)/(1920), 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - }}; - } - return transform; -} - -} // namespace - -CameraViewWidget::CameraViewWidget(VisionStreamType stream_type, QWidget* parent) : stream_type(stream_type), QOpenGLWidget(parent) { - setAttribute(Qt::WA_OpaquePaintEvent); - - timer = new QTimer(this); - connect(timer, &QTimer::timeout, this, &CameraViewWidget::updateFrame); -} - -CameraViewWidget::~CameraViewWidget() { - makeCurrent(); - doneCurrent(); - glDeleteVertexArrays(1, &frame_vao); - glDeleteBuffers(1, &frame_vbo); - glDeleteBuffers(1, &frame_ibo); -} - -void CameraViewWidget::initializeGL() { - initializeOpenGLFunctions(); - - gl_shader = std::make_unique(frame_vertex_shader, frame_fragment_shader); - GLint frame_pos_loc = glGetAttribLocation(gl_shader->prog, "aPosition"); - GLint frame_texcoord_loc = glGetAttribLocation(gl_shader->prog, "aTexCoord"); - - auto [x1, x2, y1, y2] = stream_type == VISION_STREAM_RGB_FRONT ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f); - const uint8_t frame_indicies[] = {0, 1, 2, 0, 2, 3}; - const float frame_coords[4][4] = { - {-1.0, -1.0, x2, y1}, //bl - {-1.0, 1.0, x2, y2}, //tl - { 1.0, 1.0, x1, y2}, //tr - { 1.0, -1.0, x1, y1}, //br - }; - - glGenVertexArrays(1, &frame_vao); - glBindVertexArray(frame_vao); - glGenBuffers(1, &frame_vbo); - glBindBuffer(GL_ARRAY_BUFFER, frame_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(frame_coords), frame_coords, GL_STATIC_DRAW); - glEnableVertexAttribArray(frame_pos_loc); - glVertexAttribPointer(frame_pos_loc, 2, GL_FLOAT, GL_FALSE, - sizeof(frame_coords[0]), (const void *)0); - glEnableVertexAttribArray(frame_texcoord_loc); - glVertexAttribPointer(frame_texcoord_loc, 2, GL_FLOAT, GL_FALSE, - sizeof(frame_coords[0]), (const void *)(sizeof(float) * 2)); - glGenBuffers(1, &frame_ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, frame_ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(frame_indicies), frame_indicies, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - if (stream_type == VISION_STREAM_RGB_FRONT) { - frame_mat = matmul(device_transform, get_driver_view_transform()); - } else { - auto intrinsic_matrix = stream_type == VISION_STREAM_RGB_WIDE ? ecam_intrinsic_matrix : fcam_intrinsic_matrix; - float zoom_ = zoom / intrinsic_matrix.v[0]; - if (stream_type == VISION_STREAM_RGB_WIDE) { - zoom_ *= 0.5; - } - float zx = zoom_ * 2 * intrinsic_matrix.v[2] / width(); - float zy = zoom_ * 2 * intrinsic_matrix.v[5] / height(); - - const mat4 frame_transform = {{ - zx, 0.0, 0.0, 0.0, - 0.0, zy, 0.0, -y_offset / height() * 2, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - }}; - frame_mat = matmul(device_transform, frame_transform); - } - vipc_client = std::make_unique("camerad", stream_type, true); -} - -void CameraViewWidget::showEvent(QShowEvent *event) { - timer->start(0); -} - -void CameraViewWidget::hideEvent(QHideEvent *event) { - timer->stop(); - vipc_client->connected = false; - latest_frame = nullptr; -} - -void CameraViewWidget::paintGL() { - if (!latest_frame) { - glClearColor(0, 0, 0, 1.0); - glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - return; - } - - glViewport(0, 0, width(), height()); - - glBindVertexArray(frame_vao); - glActiveTexture(GL_TEXTURE0); - - glBindTexture(GL_TEXTURE_2D, texture[latest_frame->idx]->frame_tex); - if (!Hardware::EON()) { - // this is handled in ion on QCOM - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, latest_frame->width, latest_frame->height, - 0, GL_RGB, GL_UNSIGNED_BYTE, latest_frame->addr); - } - - glUseProgram(gl_shader->prog); - glUniform1i(gl_shader->getUniformLocation("uTexture"), 0); - glUniformMatrix4fv(gl_shader->getUniformLocation("uTransform"), 1, GL_TRUE, frame_mat.v); - - assert(glGetError() == GL_NO_ERROR); - glEnableVertexAttribArray(0); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (const void *)0); - glDisableVertexAttribArray(0); - glBindVertexArray(0); -} - -void CameraViewWidget::updateFrame() { - if (!vipc_client->connected && vipc_client->connect(false)) { - // init vision - for (int i = 0; i < vipc_client->num_buffers; i++) { - texture[i].reset(new EGLImageTexture(&vipc_client->buffers[i])); - - glBindTexture(GL_TEXTURE_2D, texture[i]->frame_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - // BGR - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); - assert(glGetError() == GL_NO_ERROR); - } - latest_frame = nullptr; - } - - if (vipc_client->connected) { - VisionBuf *buf = vipc_client->recv(); - if (buf != nullptr) { - latest_frame = buf; - update(); - emit frameUpdated(); - } else { - LOGE("visionIPC receive timeout"); - } - } -} diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h deleted file mode 100644 index 91ff9befb..000000000 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include "cereal/visionipc/visionipc_client.h" -#include "selfdrive/common/glutil.h" -#include "selfdrive/common/mat.h" -#include "selfdrive/common/visionimg.h" -#include "selfdrive/ui/ui.h" - -class CameraViewWidget : public QOpenGLWidget, protected QOpenGLFunctions { -Q_OBJECT - -public: - using QOpenGLWidget::QOpenGLWidget; - explicit CameraViewWidget(VisionStreamType stream_type, QWidget* parent = nullptr); - ~CameraViewWidget(); - -signals: - void frameUpdated(); - -protected: - void paintGL() override; - void initializeGL() override; - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - -protected slots: - void updateFrame(); - -private: - VisionBuf *latest_frame = nullptr; - GLuint frame_vao, frame_vbo, frame_ibo; - mat4 frame_mat; - std::unique_ptr vipc_client; - std::unique_ptr texture[UI_BUF_COUNT]; - std::unique_ptr gl_shader; - - VisionStreamType stream_type; - QTimer* timer; -}; diff --git a/selfdrive/ui/qt/widgets/controls.cc b/selfdrive/ui/qt/widgets/controls.cc deleted file mode 100644 index 24c586113..000000000 --- a/selfdrive/ui/qt/widgets/controls.cc +++ /dev/null @@ -1,66 +0,0 @@ -#include "controls.h" - -QFrame *horizontal_line(QWidget *parent) { - QFrame *line = new QFrame(parent); - line->setFrameShape(QFrame::StyledPanel); - line->setStyleSheet(R"( - margin-left: 40px; - margin-right: 40px; - border-width: 1px; - border-bottom-style: solid; - border-color: gray; - )"); - line->setFixedHeight(2); - return line; -} - -AbstractControl::AbstractControl(const QString &title, const QString &desc, const QString &icon, QWidget *parent) : QFrame(parent) { - QVBoxLayout *vlayout = new QVBoxLayout(); - vlayout->setMargin(0); - - hlayout = new QHBoxLayout; - hlayout->setMargin(0); - hlayout->setSpacing(20); - - // left icon - if (!icon.isEmpty()) { - QPixmap pix(icon); - QLabel *icon = new QLabel(); - icon->setPixmap(pix.scaledToWidth(80, Qt::SmoothTransformation)); - icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); - hlayout->addWidget(icon); - } - - // title - title_label = new QPushButton(title); - title_label->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left;"); - hlayout->addWidget(title_label); - - vlayout->addLayout(hlayout); - - // description - if (!desc.isEmpty()) { - description = new QLabel(desc); - description->setContentsMargins(40, 20, 40, 20); - description->setStyleSheet("font-size: 40px; color:grey"); - description->setWordWrap(true); - description->setVisible(false); - vlayout->addWidget(description); - - connect(title_label, &QPushButton::clicked, [=]() { - if (!description->isVisible()) { - emit showDescription(); - } - description->setVisible(!description->isVisible()); - }); - } - - setLayout(vlayout); - setStyleSheet("background-color: transparent;"); -} - -void AbstractControl::hideEvent(QHideEvent *e){ - if(description != nullptr){ - description->hide(); - } -} diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h deleted file mode 100644 index 238817ca3..000000000 --- a/selfdrive/ui/qt/widgets/controls.h +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "selfdrive/common/params.h" -#include "selfdrive/ui/qt/widgets/toggle.h" - -QFrame *horizontal_line(QWidget *parent = nullptr); - -class AbstractControl : public QFrame { - Q_OBJECT - -public: - void setDescription(const QString &desc) { - if(description) description->setText(desc); - } - -signals: - void showDescription(); - -protected: - AbstractControl(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr); - void hideEvent(QHideEvent *e) override; - - QSize minimumSizeHint() const override { - QSize size = QFrame::minimumSizeHint(); - size.setHeight(120); - return size; - }; - - QHBoxLayout *hlayout; - QPushButton *title_label; - QLabel *description = nullptr; -}; - -// widget to display a value -class LabelControl : public AbstractControl { - Q_OBJECT - -public: - LabelControl(const QString &title, const QString &text, const QString &desc = "", QWidget *parent = nullptr) : AbstractControl(title, desc, "", parent) { - label.setText(text); - label.setAlignment(Qt::AlignRight | Qt::AlignVCenter); - hlayout->addWidget(&label); - } - void setText(const QString &text) { label.setText(text); } - -private: - QLabel label; -}; - -// widget for a button with a label -class ButtonControl : public AbstractControl { - Q_OBJECT - -public: - template - ButtonControl(const QString &title, const QString &text, const QString &desc, Functor functor, const QString &icon = "", QWidget *parent = nullptr) : AbstractControl(title, desc, icon, parent) { - btn.setText(text); - btn.setStyleSheet(R"( - QPushButton { - padding: 0; - border-radius: 50px; - font-size: 35px; - font-weight: 500; - color: #E4E4E4; - background-color: #393939; - } - QPushButton:disabled { - color: #33E4E4E4; - } - )"); - btn.setFixedSize(250, 100); - QObject::connect(&btn, &QPushButton::released, functor); - hlayout->addWidget(&btn); - } - void setText(const QString &text) { btn.setText(text); } - -public slots: - void setEnabled(bool enabled) { - btn.setEnabled(enabled); - }; - -private: - QPushButton btn; -}; - -class ToggleControl : public AbstractControl { - Q_OBJECT - -public: - ToggleControl(const QString &title, const QString &desc = "", const QString &icon = "", const bool state = false, QWidget *parent = nullptr) : AbstractControl(title, desc, icon, parent) { - toggle.setFixedSize(150, 100); - if (state) { - toggle.togglePosition(); - } - hlayout->addWidget(&toggle); - QObject::connect(&toggle, &Toggle::stateChanged, this, &ToggleControl::toggleFlipped); - } - - void setEnabled(bool enabled) { toggle.setEnabled(enabled); } - -signals: - void toggleFlipped(bool state); - -protected: - Toggle toggle; -}; - -// widget to toggle params -class ParamControl : public ToggleControl { - Q_OBJECT - -public: - ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr) : ToggleControl(title, desc, icon, false, parent) { - if (params.getBool(param.toStdString().c_str())) { - toggle.togglePosition(); - } - QObject::connect(this, &ToggleControl::toggleFlipped, [=](bool state) { - params.putBool(param.toStdString().c_str(), state); - }); - } - -private: - Params params; -}; diff --git a/selfdrive/ui/qt/widgets/drive_stats.cc b/selfdrive/ui/qt/widgets/drive_stats.cc deleted file mode 100644 index 1395c150c..000000000 --- a/selfdrive/ui/qt/widgets/drive_stats.cc +++ /dev/null @@ -1,70 +0,0 @@ -#include "drive_stats.h" - -#include -#include -#include -#include - -#include "selfdrive/common/params.h" -#include "selfdrive/ui/qt/request_repeater.h" - -const double MILE_TO_KM = 1.60934; - -static QLayout* build_stat_layout(QLabel** metric, const QString& name) { - QVBoxLayout* layout = new QVBoxLayout; - layout->setMargin(0); - *metric = new QLabel("0"); - (*metric)->setStyleSheet("font-size: 80px; font-weight: 600;"); - layout->addWidget(*metric, 0, Qt::AlignLeft); - - QLabel* label = new QLabel(name); - label->setStyleSheet("font-size: 45px; font-weight: 500;"); - layout->addWidget(label, 0, Qt::AlignLeft); - return layout; -} - -void DriveStats::parseResponse(const QString& response) { - QJsonDocument doc = QJsonDocument::fromJson(response.trimmed().toUtf8()); - if (doc.isNull()) { - qDebug() << "JSON Parse failed on getting past drives statistics"; - return; - } - - auto update = [](const QJsonObject &obj, StatsLabels& labels, bool metric) { - labels.routes->setText(QString::number((int)obj["routes"].toDouble())); - labels.distance->setText(QString::number(int(obj["distance"].toDouble() * (metric ? MILE_TO_KM : 1)))); - labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60))); - }; - - QJsonObject json = doc.object(); - update(json["all"].toObject(), all_, metric); - update(json["week"].toObject(), week_, metric); -} - -DriveStats::DriveStats(QWidget* parent) : QWidget(parent) { - metric = Params().getBool("IsMetric"); - QString distance_unit = metric ? "KM" : "MILES"; - - auto add_stats_layouts = [&](QGridLayout* gl, StatsLabels& labels, int row, const QString &distance_unit) { - gl->addLayout(build_stat_layout(&labels.routes, "DRIVES"), row, 0, 3, 1); - gl->addLayout(build_stat_layout(&labels.distance, distance_unit), row, 1, 3, 1); - gl->addLayout(build_stat_layout(&labels.hours, "HOURS"), row, 2, 3, 1); - }; - - QGridLayout* gl = new QGridLayout(this); - gl->setMargin(0); - - gl->addWidget(new QLabel("ALL TIME"), 0, 0, 1, 3); - add_stats_layouts(gl, all_, 1, distance_unit); - - gl->addWidget(new QLabel("PAST WEEK"), 6, 0, 1, 3); - add_stats_layouts(gl, week_, 7, distance_unit); - - QString dongleId = QString::fromStdString(Params().get("DongleId")); - QString url = "https://api.commadotai.com/v1.1/devices/" + dongleId + "/stats"; - RequestRepeater *repeater = new RequestRepeater(this, url, "ApiCache_DriveStats", 30); - QObject::connect(repeater, &RequestRepeater::receivedResponse, this, &DriveStats::parseResponse); - - setLayout(gl); - setStyleSheet(R"(QLabel {font-size: 48px; font-weight: 500;})"); -} diff --git a/selfdrive/ui/qt/widgets/drive_stats.h b/selfdrive/ui/qt/widgets/drive_stats.h deleted file mode 100644 index deeb80f65..000000000 --- a/selfdrive/ui/qt/widgets/drive_stats.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -class DriveStats : public QWidget { - Q_OBJECT - -public: - explicit DriveStats(QWidget* parent = 0); - -private: - bool metric; - struct StatsLabels { - QLabel *routes, *distance, *hours; - } all_, week_; - -private slots: - void parseResponse(const QString &response); -}; diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc deleted file mode 100644 index 4e9d2e668..000000000 --- a/selfdrive/ui/qt/widgets/input.cc +++ /dev/null @@ -1,181 +0,0 @@ -#include "input.h" - -#include - -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/hardware/hw.h" - -InputDialog::InputDialog(const QString &prompt_text, QWidget *parent) : QDialog(parent) { - layout = new QVBoxLayout(); - layout->setContentsMargins(50, 50, 50, 50); - layout->setSpacing(20); - - // build header - QHBoxLayout *header_layout = new QHBoxLayout(); - - label = new QLabel(prompt_text, this); - label->setStyleSheet(R"(font-size: 75px; font-weight: 500;)"); - header_layout->addWidget(label, 1, Qt::AlignLeft); - - QPushButton* cancel_btn = new QPushButton("Cancel"); - cancel_btn->setStyleSheet(R"( - padding: 30px; - padding-right: 45px; - padding-left: 45px; - border-radius: 7px; - font-size: 45px; - background-color: #444444; - )"); - header_layout->addWidget(cancel_btn, 0, Qt::AlignRight); - QObject::connect(cancel_btn, &QPushButton::released, this, &InputDialog::reject); - QObject::connect(cancel_btn, &QPushButton::released, this, &InputDialog::cancel); - - layout->addLayout(header_layout); - - // text box - layout->addSpacing(20); - line = new QLineEdit(); - line->setStyleSheet(R"( - border: none; - background-color: #444444; - font-size: 80px; - font-weight: 500; - padding: 10px; - )"); - layout->addWidget(line, 1, Qt::AlignTop); - - k = new Keyboard(this); - QObject::connect(k, &Keyboard::emitButton, this, &InputDialog::handleInput); - layout->addWidget(k, 2, Qt::AlignBottom); - - setStyleSheet(R"( - * { - color: white; - background-color: black; - } - )"); - - setLayout(layout); -} - -QString InputDialog::getText(const QString &prompt, int minLength) { - InputDialog d = InputDialog(prompt); - d.setMinLength(minLength); - const int ret = d.exec(); - return ret ? d.text() : QString(); -} - -QString InputDialog::text() { - return line->text(); -} - -int InputDialog::exec() { - setMainWindow(this); - return QDialog::exec(); -} - -void InputDialog::show(){ - setMainWindow(this); -} - -void InputDialog::handleInput(const QString &s) { - if (!QString::compare(s,"⌫")) { - line->backspace(); - } - - if (!QString::compare(s,"⏎")) { - if (line->text().length() >= minLength){ - done(QDialog::Accepted); - emitText(line->text()); - } else { - setMessage("Need at least "+QString::number(minLength)+" characters!", false); - } - } - - QVector control_buttons {"⇧", "↑", "ABC", "⏎", "#+=", "⌫", "123"}; - for(QString c : control_buttons) { - if (!QString::compare(s, c)) { - return; - } - } - - line->insert(s.left(1)); -} - -void InputDialog::setMessage(const QString &message, bool clearInputField){ - label->setText(message); - if (clearInputField){ - line->setText(""); - } -} - -void InputDialog::setMinLength(int length){ - minLength = length; -} - -ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString &confirm_text, const QString &cancel_text, - QWidget *parent):QDialog(parent) { - setWindowFlags(Qt::Popup); - layout = new QVBoxLayout(); - layout->setMargin(25); - - prompt = new QLabel(prompt_text, this); - prompt->setWordWrap(true); - prompt->setAlignment(Qt::AlignHCenter); - prompt->setStyleSheet(R"(font-size: 55px; font-weight: 400;)"); - layout->addWidget(prompt, 1, Qt::AlignTop | Qt::AlignHCenter); - - // cancel + confirm buttons - QHBoxLayout *btn_layout = new QHBoxLayout(); - btn_layout->setSpacing(20); - btn_layout->addStretch(1); - layout->addLayout(btn_layout); - - if (cancel_text.length()) { - QPushButton* cancel_btn = new QPushButton(cancel_text); - btn_layout->addWidget(cancel_btn, 0, Qt::AlignRight); - QObject::connect(cancel_btn, &QPushButton::released, this, &ConfirmationDialog::reject); - } - - if (confirm_text.length()) { - QPushButton* confirm_btn = new QPushButton(confirm_text); - btn_layout->addWidget(confirm_btn, 0, Qt::AlignRight); - QObject::connect(confirm_btn, &QPushButton::released, this, &ConfirmationDialog::accept); - } - - setFixedSize(900, 350); - setStyleSheet(R"( - * { - color: black; - background-color: white; - } - QPushButton { - font-size: 40px; - padding: 30px; - padding-right: 45px; - padding-left: 45px; - border-radius: 7px; - background-color: #44444400; - } - )"); - - setLayout(layout); -} - -bool ConfirmationDialog::alert(const QString &prompt_text, QWidget *parent) { - ConfirmationDialog d = ConfirmationDialog(prompt_text, "Ok", "", parent); - return d.exec(); -} - -bool ConfirmationDialog::confirm(const QString &prompt_text, QWidget *parent) { - ConfirmationDialog d = ConfirmationDialog(prompt_text, "Ok", "Cancel", parent); - return d.exec(); -} - -int ConfirmationDialog::exec() { - // TODO: make this work without fullscreen - if (Hardware::TICI()) { - setMainWindow(this); - } - return QDialog::exec(); -} diff --git a/selfdrive/ui/qt/widgets/input.h b/selfdrive/ui/qt/widgets/input.h deleted file mode 100644 index 4ffd0a9bb..000000000 --- a/selfdrive/ui/qt/widgets/input.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "selfdrive/ui/qt/widgets/keyboard.h" - -class InputDialog : public QDialog { - Q_OBJECT - -public: - explicit InputDialog(const QString &prompt_text, QWidget* parent = 0); - static QString getText(const QString &prompt, int minLength = -1); - QString text(); - void setMessage(const QString &message, bool clearInputField = true); - void setMinLength(int length); - void show(); - -private: - int minLength; - QLineEdit *line; - Keyboard *k; - QLabel *label; - QVBoxLayout *layout; - -public slots: - int exec() override; - -private slots: - void handleInput(const QString &s); - -signals: - void cancel(); - void emitText(const QString &text); -}; - -class ConfirmationDialog : public QDialog { - Q_OBJECT - -public: - explicit ConfirmationDialog(const QString &prompt_text, const QString &confirm_text = "Ok", - const QString &cancel_text = "Cancel", QWidget* parent = 0); - static bool alert(const QString &prompt_text, QWidget *parent = 0); - static bool confirm(const QString &prompt_text, QWidget *parent = 0); - -private: - QLabel *prompt; - QVBoxLayout *layout; - -public slots: - int exec() override; -}; diff --git a/selfdrive/ui/qt/widgets/keyboard.cc b/selfdrive/ui/qt/widgets/keyboard.cc deleted file mode 100644 index 6613897b1..000000000 --- a/selfdrive/ui/qt/widgets/keyboard.cc +++ /dev/null @@ -1,127 +0,0 @@ -#include "keyboard.h" - -#include -#include -#include -#include -#include -#include - -const int DEFAULT_STRETCH = 1; -const int SPACEBAR_STRETCH = 3; - -KeyboardLayout::KeyboardLayout(QWidget* parent, const std::vector>& layout) : QWidget(parent) { - QVBoxLayout* vlayout = new QVBoxLayout; - vlayout->setMargin(0); - vlayout->setSpacing(35); - - QButtonGroup* btn_group = new QButtonGroup(this); - QObject::connect(btn_group, SIGNAL(buttonClicked(QAbstractButton*)), parent, SLOT(handleButton(QAbstractButton*))); - - for (const auto &s : layout) { - QHBoxLayout *hlayout = new QHBoxLayout; - hlayout->setSpacing(25); - - if (vlayout->count() == 1) { - hlayout->addSpacing(90); - } - - for (const QString &p : s) { - QPushButton* btn = new QPushButton(p); - btn->setFixedHeight(135); - btn_group->addButton(btn); - hlayout->addWidget(btn, p == QString(" ") ? SPACEBAR_STRETCH : DEFAULT_STRETCH); - } - - if (vlayout->count() == 1) { - hlayout->addSpacing(90); - } - - vlayout->addLayout(hlayout); - } - - setStyleSheet(R"( - * { - outline: none; - } - QPushButton { - font-size: 65px; - margin: 0px; - padding: 0px; - border-radius: 30px; - color: #dddddd; - background-color: #444444; - } - QPushButton:pressed { - background-color: #000000; - } - )"); - setLayout(vlayout); -} - -Keyboard::Keyboard(QWidget *parent) : QFrame(parent) { - main_layout = new QStackedLayout; - main_layout->setMargin(0); - - // lowercase - std::vector> lowercase = { - {"q","w","e","r","t","y","u","i","o","p"}, - {"a","s","d","f","g","h","j","k","l"}, - {"⇧","z","x","c","v","b","n","m","⌫"}, - {"123"," ","⏎"}, - }; - main_layout->addWidget(new KeyboardLayout(this, lowercase)); - - // uppercase - std::vector> uppercase = { - {"Q","W","E","R","T","Y","U","I","O","P"}, - {"A","S","D","F","G","H","J","K","L"}, - {"↑","Z","X","C","V","B","N","M","⌫"}, - {"123"," ","⏎"}, - }; - main_layout->addWidget(new KeyboardLayout(this, uppercase)); - - // numbers + specials - std::vector> numbers = { - {"1","2","3","4","5","6","7","8","9","0"}, - {"-","/",":",";","(",")","$","&&","@","\""}, - {"#+=",".",",","?","!","`","⌫"}, - {"ABC"," ","⏎"}, - }; - main_layout->addWidget(new KeyboardLayout(this, numbers)); - - // extra specials - std::vector> specials = { - {"[","]","{","}","#","%","^","*","+","="}, - {"_","\\","|","~","<",">","€","£","¥","•"}, - {"123",".",",","?","!","`","⌫"}, - {"ABC"," ","⏎"}, - }; - main_layout->addWidget(new KeyboardLayout(this, specials)); - - setLayout(main_layout); - main_layout->setCurrentIndex(0); -} - -void Keyboard::handleButton(QAbstractButton* m_button) { - QString id = m_button->text(); - if (!QString::compare(m_button->text(), "↑") || !QString::compare(m_button->text(), "ABC")) { - main_layout->setCurrentIndex(0); - } - if (!QString::compare(m_button->text(), "⇧")) { - main_layout->setCurrentIndex(1); - } - if (!QString::compare(m_button->text(), "123")) { - main_layout->setCurrentIndex(2); - } - if (!QString::compare(m_button->text(), "#+=")) { - main_layout->setCurrentIndex(3); - } - if (!QString::compare(m_button->text(), "⏎")) { - main_layout->setCurrentIndex(0); - } - if ("A" <= id && id <= "Z") { - main_layout->setCurrentIndex(0); - } - emit emitButton(m_button->text()); -} diff --git a/selfdrive/ui/qt/widgets/keyboard.h b/selfdrive/ui/qt/widgets/keyboard.h deleted file mode 100644 index c89f4fc6a..000000000 --- a/selfdrive/ui/qt/widgets/keyboard.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -class KeyboardLayout : public QWidget { - Q_OBJECT - -public: - explicit KeyboardLayout(QWidget* parent, const std::vector>& layout); -}; - -class Keyboard : public QFrame { - Q_OBJECT - -public: - explicit Keyboard(QWidget *parent = 0); - -private: - QStackedLayout* main_layout; - -private slots: - void handleButton(QAbstractButton* m_button); - -signals: - void emitButton(const QString &s); -}; diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.cc b/selfdrive/ui/qt/widgets/offroad_alerts.cc deleted file mode 100644 index 7816b251f..000000000 --- a/selfdrive/ui/qt/widgets/offroad_alerts.cc +++ /dev/null @@ -1,114 +0,0 @@ -#include "offroad_alerts.h" - -#include -#include -#include -#include - -#include "selfdrive/common/util.h" -#include "selfdrive/hardware/hw.h" - -OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) { - QVBoxLayout *layout = new QVBoxLayout; - layout->setMargin(50); - layout->setSpacing(30); - - QWidget *alerts_widget = new QWidget(this); - alerts_layout = new QVBoxLayout; - alerts_layout->setMargin(0); - alerts_layout->setSpacing(30); - alerts_widget->setLayout(alerts_layout); - alerts_widget->setStyleSheet("background-color: transparent;"); - - // release notes - releaseNotes.setWordWrap(true); - releaseNotes.setVisible(false); - releaseNotes.setStyleSheet("font-size: 48px;"); - releaseNotes.setAlignment(Qt::AlignTop); - - releaseNotesScroll = new ScrollView(&releaseNotes, this); - layout->addWidget(releaseNotesScroll); - - alertsScroll = new ScrollView(alerts_widget, this); - layout->addWidget(alertsScroll); - - // bottom footer, dismiss + reboot buttons - QHBoxLayout *footer_layout = new QHBoxLayout(); - layout->addLayout(footer_layout); - - QPushButton *dismiss_btn = new QPushButton("Dismiss"); - dismiss_btn->setFixedSize(400, 125); - footer_layout->addWidget(dismiss_btn, 0, Qt::AlignBottom | Qt::AlignLeft); - QObject::connect(dismiss_btn, &QPushButton::released, this, &OffroadAlert::closeAlerts); - - rebootBtn.setText("Reboot and Update"); - rebootBtn.setFixedSize(600, 125); - rebootBtn.setVisible(false); - footer_layout->addWidget(&rebootBtn, 0, Qt::AlignBottom | Qt::AlignRight); - QObject::connect(&rebootBtn, &QPushButton::released, [=]() { Hardware::reboot(); }); - - setLayout(layout); - setStyleSheet(R"( - * { - font-size: 48px; - color: white; - } - QFrame { - border-radius: 30px; - background-color: #393939; - } - QPushButton { - color: black; - font-weight: 500; - border-radius: 30px; - background-color: white; - } - )"); -} - -void OffroadAlert::refresh() { - if (alerts.empty()) { - // setup labels for each alert - QString json = QString::fromStdString(util::read_file("../controls/lib/alerts_offroad.json")); - QJsonObject obj = QJsonDocument::fromJson(json.toUtf8()).object(); - for (auto &k : obj.keys()) { - QLabel *l = new QLabel(this); - alerts[k.toStdString()] = l; - int severity = obj[k].toObject()["severity"].toInt(); - - l->setMargin(60); - l->setWordWrap(true); - l->setStyleSheet("background-color: " + QString(severity ? "#E22C2C" : "#292929")); - l->setVisible(false); - alerts_layout->addWidget(l); - } - alerts_layout->addStretch(1); - } - - updateAlerts(); - - rebootBtn.setVisible(updateAvailable); - releaseNotesScroll->setVisible(updateAvailable); - releaseNotes.setText(QString::fromStdString(params.get("ReleaseNotes"))); - - alertsScroll->setVisible(!updateAvailable); - for (const auto& [k, label] : alerts) { - label->setVisible(!label->text().isEmpty()); - } -} - -void OffroadAlert::updateAlerts() { - alertCount = 0; - updateAvailable = params.getBool("UpdateAvailable"); - for (const auto& [key, label] : alerts) { - auto bytes = params.get(key.c_str()); - if (bytes.size()) { - QJsonDocument doc_par = QJsonDocument::fromJson(QByteArray(bytes.data(), bytes.size())); - QJsonObject obj = doc_par.object(); - label->setText(obj.value("text").toString()); - alertCount++; - } else { - label->setText(""); - } - } -} diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.h b/selfdrive/ui/qt/widgets/offroad_alerts.h deleted file mode 100644 index 88a69c8da..000000000 --- a/selfdrive/ui/qt/widgets/offroad_alerts.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include - -#include "selfdrive/common/params.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - -class OffroadAlert : public QFrame { - Q_OBJECT - -public: - explicit OffroadAlert(QWidget *parent = 0); - int alertCount = 0; - bool updateAvailable; - -private: - void updateAlerts(); - - Params params; - std::map alerts; - - QLabel releaseNotes; - QPushButton rebootBtn; - ScrollView *alertsScroll; - ScrollView *releaseNotesScroll; - QVBoxLayout *alerts_layout; - -signals: - void closeAlerts(); - -public slots: - void refresh(); -}; diff --git a/selfdrive/ui/qt/widgets/scrollview.cc b/selfdrive/ui/qt/widgets/scrollview.cc deleted file mode 100644 index 31be17c7b..000000000 --- a/selfdrive/ui/qt/widgets/scrollview.cc +++ /dev/null @@ -1,47 +0,0 @@ -#include "scrollview.h" - -#include - -ScrollView::ScrollView(QWidget *w, QWidget *parent) : QScrollArea(parent){ - setWidget(w); - setWidgetResizable(true); - setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setStyleSheet("ScrollView { background-color:transparent; }"); - - QString style = R"( - QScrollBar:vertical { - border: none; - background: transparent; - width:10px; - margin: 0; - } - QScrollBar::handle:vertical { - min-height: 0px; - border-radius: 4px; - background-color: white; - } - QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { - height: 0px; - } - QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { - background: none; - } - )"; - - verticalScrollBar()->setStyleSheet(style); - horizontalScrollBar()->setStyleSheet(style); - - QScroller *scroller = QScroller::scroller(this->viewport()); - QScrollerProperties sp = scroller->scrollerProperties(); - - sp.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QVariant::fromValue(QScrollerProperties::OvershootAlwaysOff)); - sp.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QVariant::fromValue(QScrollerProperties::OvershootAlwaysOff)); - - scroller->grabGesture(this->viewport(), QScroller::LeftMouseButtonGesture); - scroller->setScrollerProperties(sp); -} - -void ScrollView::hideEvent(QHideEvent *e){ - verticalScrollBar()->setValue(0); -} diff --git a/selfdrive/ui/qt/widgets/scrollview.h b/selfdrive/ui/qt/widgets/scrollview.h deleted file mode 100644 index 755ed646f..000000000 --- a/selfdrive/ui/qt/widgets/scrollview.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include - -class ScrollView : public QScrollArea { - Q_OBJECT - -public: - explicit ScrollView(QWidget *w = nullptr, QWidget *parent = nullptr); -protected: - void hideEvent(QHideEvent *e) override; -}; diff --git a/selfdrive/ui/qt/widgets/setup.cc b/selfdrive/ui/qt/widgets/setup.cc deleted file mode 100644 index 2633220ea..000000000 --- a/selfdrive/ui/qt/widgets/setup.cc +++ /dev/null @@ -1,283 +0,0 @@ -#include "setup.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "selfdrive/common/params.h" -#include "selfdrive/ui/qt/request_repeater.h" - -using qrcodegen::QrCode; - -PairingQRWidget::PairingQRWidget(QWidget* parent) : QWidget(parent) { - qrCode = new QLabel; - qrCode->setScaledContents(true); - QVBoxLayout* v = new QVBoxLayout; - v->addWidget(qrCode, 0, Qt::AlignCenter); - setLayout(v); - - QTimer* timer = new QTimer(this); - timer->start(30 * 1000); - connect(timer, &QTimer::timeout, this, &PairingQRWidget::refresh); -} - -void PairingQRWidget::showEvent(QShowEvent *event){ - refresh(); -} - -void PairingQRWidget::refresh(){ - Params params; - QString IMEI = QString::fromStdString(params.get("IMEI")); - QString serial = QString::fromStdString(params.get("HardwareSerial")); - - if (std::min(IMEI.length(), serial.length()) <= 5) { - qrCode->setText("Error getting serial: contact support"); - qrCode->setWordWrap(true); - qrCode->setStyleSheet(R"(font-size: 60px;)"); - return; - } - QString pairToken = CommaApi::create_jwt({{"pair", true}}); - - QString qrString = IMEI + "--" + serial + "--" + pairToken; - this->updateQrCode(qrString); -} - -void PairingQRWidget::updateQrCode(QString text) { - QrCode qr = QrCode::encodeText(text.toUtf8().data(), QrCode::Ecc::LOW); - qint32 sz = qr.getSize(); - // make the image larger so we can have a white border - QImage im(sz + 2, sz + 2, QImage::Format_RGB32); - QRgb black = qRgb(0, 0, 0); - QRgb white = qRgb(255, 255, 255); - - for (int y = 0; y < sz + 2; y++) { - for (int x = 0; x < sz + 2; x++) { - im.setPixel(x, y, white); - } - } - for (int y = 0; y < sz; y++) { - for (int x = 0; x < sz; x++) { - im.setPixel(x + 1, y + 1, qr.getModule(x, y) ? black : white); - } - } - // Integer division to prevent anti-aliasing - int approx500 = (500 / (sz + 2)) * (sz + 2); - qrCode->setPixmap(QPixmap::fromImage(im.scaled(approx500, approx500, Qt::KeepAspectRatio, Qt::FastTransformation), Qt::MonoOnly)); - qrCode->setFixedSize(approx500, approx500); -} - -PrimeUserWidget::PrimeUserWidget(QWidget* parent) : QWidget(parent) { - mainLayout = new QVBoxLayout; - mainLayout->setMargin(30); - - QLabel* commaPrime = new QLabel("COMMA PRIME"); - mainLayout->addWidget(commaPrime, 0, Qt::AlignTop); - - username = new QLabel(); - username->setStyleSheet("font-size: 55px;"); // TODO: fit width - mainLayout->addWidget(username, 0, Qt::AlignTop); - - mainLayout->addSpacing(100); - - QLabel* commaPoints = new QLabel("COMMA POINTS"); - commaPoints->setStyleSheet(R"( - color: #b8b8b8; - )"); - mainLayout->addWidget(commaPoints, 0, Qt::AlignTop); - - points = new QLabel(); - mainLayout->addWidget(points, 0, Qt::AlignTop); - - setLayout(mainLayout); - setStyleSheet(R"( - QLabel { - font-size: 70px; - font-weight: 500; - } - )"); - - // set up API requests - QString dongleId = QString::fromStdString(Params().get("DongleId")); - if (!dongleId.length()) { - return; - } - - QString url = "https://api.commadotai.com/v1/devices/" + dongleId + "/owner"; - RequestRepeater *repeater = new RequestRepeater(this, url, "ApiCache_Owner", 6); - QObject::connect(repeater, &RequestRepeater::receivedResponse, this, &PrimeUserWidget::replyFinished); -} - -void PrimeUserWidget::replyFinished(const QString &response) { - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); - if (doc.isNull()) { - qDebug() << "JSON Parse failed on getting username and points"; - return; - } - - QJsonObject json = doc.object(); - QString points_str = QString::number(json["points"].toInt()); - QString username_str = json["username"].toString(); - if (username_str.length()) { - username_str = "@" + username_str; - } - - username->setText(username_str); - points->setText(points_str); -} - -PrimeAdWidget::PrimeAdWidget(QWidget* parent) : QWidget(parent) { - QVBoxLayout* vlayout = new QVBoxLayout; - vlayout->setMargin(30); - vlayout->setSpacing(15); - - vlayout->addWidget(new QLabel("Upgrade now"), 1, Qt::AlignTop); - - QLabel* description = new QLabel("Become a comma prime member at my.comma.ai and get premium features!"); - description->setStyleSheet(R"( - font-size: 50px; - color: #b8b8b8; - )"); - description->setWordWrap(true); - vlayout->addWidget(description, 2, Qt::AlignTop); - - QVector features = {"✓ REMOTE ACCESS", "✓ 14 DAYS OF STORAGE", "✓ DEVELOPER PERKS"}; - for (auto &f: features) { - QLabel* feature = new QLabel(f); - feature->setStyleSheet(R"(font-size: 40px;)"); - vlayout->addWidget(feature, 0, Qt::AlignBottom); - } - - setLayout(vlayout); -} - - -SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { - mainLayout = new QStackedWidget; - - // Unpaired, registration prompt layout - - QVBoxLayout* finishRegistationLayout = new QVBoxLayout; - finishRegistationLayout->setMargin(30); - - QLabel* registrationDescription = new QLabel("Pair your device with the comma connect app"); - registrationDescription->setWordWrap(true); - registrationDescription->setAlignment(Qt::AlignCenter); - registrationDescription->setStyleSheet(R"( - font-size: 55px; - font-weight: 400; - )"); - - finishRegistationLayout->addWidget(registrationDescription); - - QPushButton* finishButton = new QPushButton("Finish setup"); - finishButton->setFixedHeight(200); - finishButton->setStyleSheet(R"( - border-radius: 30px; - font-size: 55px; - font-weight: 500; - background: #585858; - )"); - finishRegistationLayout->addWidget(finishButton); - QObject::connect(finishButton, &QPushButton::released, this, &SetupWidget::showQrCode); - - QWidget* finishRegistration = new QWidget; - finishRegistration->setLayout(finishRegistationLayout); - mainLayout->addWidget(finishRegistration); - - // Pairing QR code layout - - QVBoxLayout* qrLayout = new QVBoxLayout; - - qrLayout->addSpacing(30); - QLabel* qrLabel = new QLabel("Scan with comma connect!"); - qrLabel->setWordWrap(true); - qrLabel->setAlignment(Qt::AlignHCenter); - qrLabel->setStyleSheet(R"( - font-size: 55px; - font-weight: 400; - )"); - qrLayout->addWidget(qrLabel, 0, Qt::AlignTop); - - qrLayout->addWidget(new PairingQRWidget, 1); - - QWidget* q = new QWidget; - q->setLayout(qrLayout); - mainLayout->addWidget(q); - - primeAd = new PrimeAdWidget; - mainLayout->addWidget(primeAd); - - primeUser = new PrimeUserWidget; - mainLayout->addWidget(primeUser); - - mainLayout->setCurrentWidget(primeAd); - - QVBoxLayout *layout = new QVBoxLayout; - layout->addWidget(mainLayout); - setLayout(layout); - - setStyleSheet(R"( - SetupWidget { - background-color: #292929; - } - * { - font-size: 90px; - font-weight: 500; - border-radius: 40px; - } - )"); - - // Retain size while hidden - QSizePolicy sp_retain = sizePolicy(); - sp_retain.setRetainSizeWhenHidden(true); - setSizePolicy(sp_retain); - - // set up API requests - QString dongleId = QString::fromStdString(Params().get("DongleId")); - QString url = "https://api.commadotai.com/v1.1/devices/" + dongleId + "/"; - RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_Device", 5); - - QObject::connect(repeater, &RequestRepeater::receivedResponse, this, &SetupWidget::replyFinished); - QObject::connect(repeater, &RequestRepeater::failedResponse, this, &SetupWidget::parseError); - hide(); // Only show when first request comes back -} - -void SetupWidget::parseError(const QString &response) { - show(); - showQr = false; - mainLayout->setCurrentIndex(0); -} - -void SetupWidget::showQrCode(){ - showQr = true; - mainLayout->setCurrentIndex(1); -} - -void SetupWidget::replyFinished(const QString &response) { - show(); - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); - if (doc.isNull()) { - qDebug() << "JSON Parse failed on getting pairing and prime status"; - return; - } - - QJsonObject json = doc.object(); - bool is_paired = json["is_paired"].toBool(); - bool is_prime = json["prime"].toBool(); - - if (!is_paired) { - mainLayout->setCurrentIndex(showQr); - } else if (!is_prime) { - showQr = false; - mainLayout->setCurrentWidget(primeAd); - } else { - showQr = false; - mainLayout->setCurrentWidget(primeUser); - } -} diff --git a/selfdrive/ui/qt/widgets/setup.h b/selfdrive/ui/qt/widgets/setup.h deleted file mode 100644 index 169dd594f..000000000 --- a/selfdrive/ui/qt/widgets/setup.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "selfdrive/ui/qt/api.h" - -class PairingQRWidget : public QWidget { - Q_OBJECT - -public: - explicit PairingQRWidget(QWidget* parent = 0); - -private: - QLabel* qrCode; - void updateQrCode(QString text); - void showEvent(QShowEvent *event) override; - -private slots: - void refresh(); -}; - -class PrimeUserWidget : public QWidget { - Q_OBJECT -public: - explicit PrimeUserWidget(QWidget* parent = 0); - -private: - QVBoxLayout* mainLayout; - QLabel* username; - QLabel* points; - CommaApi* api; - -private slots: - void replyFinished(const QString &response); -}; - -class PrimeAdWidget : public QWidget { - Q_OBJECT -public: - explicit PrimeAdWidget(QWidget* parent = 0); -}; - -class SetupWidget : public QFrame { - Q_OBJECT - -public: - explicit SetupWidget(QWidget* parent = 0); - -private: - QStackedWidget* mainLayout; - CommaApi* api; - PrimeAdWidget *primeAd; - PrimeUserWidget *primeUser; - bool showQr = false; - -private slots: - void parseError(const QString &response); - void replyFinished(const QString &response); - void showQrCode(); -}; diff --git a/selfdrive/ui/qt/widgets/ssh_keys.cc b/selfdrive/ui/qt/widgets/ssh_keys.cc deleted file mode 100644 index d180d558c..000000000 --- a/selfdrive/ui/qt/widgets/ssh_keys.cc +++ /dev/null @@ -1,83 +0,0 @@ -#include "ssh_keys.h" - -#include -#include - -#include "selfdrive/common/params.h" -#include "selfdrive/ui/qt/api.h" -#include "selfdrive/ui/qt/widgets/input.h" - -SshControl::SshControl() : AbstractControl("SSH Keys", "Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username.", "") { - - // setup widget - hlayout->addStretch(1); - - username_label.setAlignment(Qt::AlignVCenter); - username_label.setStyleSheet("color: #aaaaaa"); - hlayout->addWidget(&username_label); - - btn.setStyleSheet(R"( - padding: 0; - border-radius: 50px; - font-size: 35px; - font-weight: 500; - color: #E4E4E4; - background-color: #393939; - )"); - btn.setFixedSize(250, 100); - hlayout->addWidget(&btn); - - QObject::connect(&btn, &QPushButton::released, [=]() { - if (btn.text() == "ADD") { - QString username = InputDialog::getText("Enter your GitHub username"); - if (username.length() > 0) { - btn.setText("LOADING"); - btn.setEnabled(false); - getUserKeys(username); - } - } else { - params.remove("GithubUsername"); - params.remove("GithubSshKeys"); - refresh(); - } - }); - - refresh(); -} - -void SshControl::refresh() { - QString param = QString::fromStdString(params.get("GithubSshKeys")); - if (param.length()) { - username_label.setText(QString::fromStdString(params.get("GithubUsername"))); - btn.setText("REMOVE"); - } else { - username_label.setText(""); - btn.setText("ADD"); - } - btn.setEnabled(true); -} - -void SshControl::getUserKeys(const QString &username) { - HttpRequest *request = new HttpRequest(this, "https://github.com/" + username + ".keys", "", false); - QObject::connect(request, &HttpRequest::receivedResponse, [=](const QString &resp) { - if (!resp.isEmpty()) { - Params params; - params.put("GithubUsername", username.toStdString()); - params.put("GithubSshKeys", resp.toStdString()); - } else { - ConfirmationDialog::alert("Username '" + username + "' has no keys on GitHub"); - } - refresh(); - request->deleteLater(); - }); - QObject::connect(request, &HttpRequest::failedResponse, [=] { - ConfirmationDialog::alert("Username '" + username + "' doesn't exist on GitHub"); - refresh(); - request->deleteLater(); - }); - QObject::connect(request, &HttpRequest::timeoutResponse, [=] { - ConfirmationDialog::alert("Request timed out"); - refresh(); - request->deleteLater(); - }); -} diff --git a/selfdrive/ui/qt/widgets/ssh_keys.h b/selfdrive/ui/qt/widgets/ssh_keys.h deleted file mode 100644 index aaa7f80dc..000000000 --- a/selfdrive/ui/qt/widgets/ssh_keys.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#include "selfdrive/hardware/hw.h" -#include "selfdrive/ui/qt/widgets/controls.h" - -// SSH enable toggle -class SshToggle : public ToggleControl { - Q_OBJECT - -public: - SshToggle() : ToggleControl("Enable SSH", "", "", Hardware::get_ssh_enabled()) { - QObject::connect(this, &SshToggle::toggleFlipped, [=](bool state) { - Hardware::set_ssh_enabled(state); - }); - } -}; - -// SSH key management widget -class SshControl : public AbstractControl { - Q_OBJECT - -public: - SshControl(); - -private: - Params params; - - QPushButton btn; - QLabel username_label; - - void refresh(); - void getUserKeys(const QString &username); -}; diff --git a/selfdrive/ui/qt/widgets/toggle.cc b/selfdrive/ui/qt/widgets/toggle.cc deleted file mode 100644 index d4eb215d3..000000000 --- a/selfdrive/ui/qt/widgets/toggle.cc +++ /dev/null @@ -1,81 +0,0 @@ -#include "toggle.h" - -Toggle::Toggle(QWidget *parent) : QAbstractButton(parent), -_height(80), -_height_rect(60), -on(false), -_anim(new QPropertyAnimation(this, "offset_circle", this)) -{ - _radius = _height / 2; - _x_circle = _radius; - _y_circle = _radius; - _y_rect = (_height - _height_rect)/2; - circleColor = QColor(0xffffff); // placeholder - green = QColor(0xffffff); // placeholder - setEnabled(true); -} - -void Toggle::paintEvent(QPaintEvent *e) { - this->setFixedHeight(_height); - QPainter p(this); - p.setPen(Qt::NoPen); - p.setRenderHint(QPainter::Antialiasing, true); - - // Draw toggle background left - p.setBrush(green); - p.drawRoundedRect(QRect(0, _y_rect, _x_circle + _radius, _height_rect), _height_rect/2, _height_rect/2); - - // Draw toggle background right - p.setBrush(QColor(0x393939)); - p.drawRoundedRect(QRect(_x_circle - _radius, _y_rect, width() - (_x_circle - _radius), _height_rect), _height_rect/2, _height_rect/2); - - // Draw toggle circle - p.setBrush(circleColor); - p.drawEllipse(QRectF(_x_circle - _radius, _y_circle - _radius, 2 * _radius, 2 * _radius)); -} - -void Toggle::mouseReleaseEvent(QMouseEvent *e) { - if(!enabled){ - return; - } - const int left = _radius; - const int right = width() - _radius; - if(_x_circle != left && _x_circle != right){ - //Don't parse touch events, while the animation is running - return; - } - if (e->button() & Qt::LeftButton) { - togglePosition(); - emit stateChanged(on); - } -} - -void Toggle::togglePosition() { - on = !on; - const int left = _radius; - const int right = width() - _radius; - _anim->setStartValue(on ? left + immediateOffset : right - immediateOffset); - _anim->setEndValue(on ? right : left); - _anim->setDuration(animation_duration); - _anim->start(); - repaint(); -} - -void Toggle::enterEvent(QEvent *e) { - QAbstractButton::enterEvent(e); -} - -bool Toggle::getEnabled(){ - return enabled; -} - -void Toggle::setEnabled(bool value){ - enabled = value; - if(value){ - circleColor.setRgb(0xfafafa); - green.setRgb(0x33ab4c); - }else{ - circleColor.setRgb(0x888888); - green.setRgb(0x227722); - } -} \ No newline at end of file diff --git a/selfdrive/ui/qt/widgets/toggle.h b/selfdrive/ui/qt/widgets/toggle.h deleted file mode 100644 index d2773f207..000000000 --- a/selfdrive/ui/qt/widgets/toggle.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include - -class Toggle : public QAbstractButton { - Q_OBJECT - Q_PROPERTY(int offset_circle READ offset_circle WRITE set_offset_circle CONSTANT) - -public: - Toggle(QWidget* parent = nullptr); - void togglePosition(); - bool on; - int animation_duration = 150; - int immediateOffset = 0; - int offset_circle() const { - return _x_circle; - } - - void set_offset_circle(int o) { - _x_circle = o; - update(); - } - bool getEnabled(); - void setEnabled(bool value); - -protected: - void paintEvent(QPaintEvent*) override; - void mouseReleaseEvent(QMouseEvent*) override; - void enterEvent(QEvent*) override; - -private: - QColor circleColor; - QColor green; - bool enabled = true; - int _x_circle, _y_circle; - int _height, _radius; - int _height_rect, _y_rect; - QPropertyAnimation *_anim = nullptr; - -signals: - void stateChanged(bool new_state); -}; diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc deleted file mode 100644 index fe7539616..000000000 --- a/selfdrive/ui/qt/window.cc +++ /dev/null @@ -1,97 +0,0 @@ -#include "window.h" - -#include "selfdrive/hardware/hw.h" - -MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { - main_layout = new QStackedLayout; - main_layout->setMargin(0); - - homeWindow = new HomeWindow(this); - main_layout->addWidget(homeWindow); - QObject::connect(homeWindow, &HomeWindow::openSettings, this, &MainWindow::openSettings); - QObject::connect(homeWindow, &HomeWindow::closeSettings, this, &MainWindow::closeSettings); - QObject::connect(&qs, &QUIState::uiUpdate, homeWindow, &HomeWindow::update); - QObject::connect(&qs, &QUIState::offroadTransition, homeWindow, &HomeWindow::offroadTransition); - QObject::connect(&qs, &QUIState::offroadTransition, homeWindow, &HomeWindow::offroadTransitionSignal); - QObject::connect(&device, &Device::displayPowerChanged, homeWindow, &HomeWindow::displayPowerChanged); - - settingsWindow = new SettingsWindow(this); - main_layout->addWidget(settingsWindow); - QObject::connect(settingsWindow, &SettingsWindow::closeSettings, this, &MainWindow::closeSettings); - QObject::connect(&qs, &QUIState::offroadTransition, settingsWindow, &SettingsWindow::offroadTransition); - QObject::connect(settingsWindow, &SettingsWindow::reviewTrainingGuide, this, &MainWindow::reviewTrainingGuide); - QObject::connect(settingsWindow, &SettingsWindow::showDriverView, [=] { - homeWindow->showDriverView(true); - }); - - onboardingWindow = new OnboardingWindow(this); - onboardingDone = onboardingWindow->isOnboardingDone(); - main_layout->addWidget(onboardingWindow); - - main_layout->setCurrentWidget(onboardingWindow); - QObject::connect(onboardingWindow, &OnboardingWindow::onboardingDone, [=](){ - onboardingDone = true; - closeSettings(); - }); - onboardingWindow->updateActiveScreen(); - - device.setAwake(true, true); - QObject::connect(&qs, &QUIState::uiUpdate, &device, &Device::update); - QObject::connect(&qs, &QUIState::offroadTransition, this, &MainWindow::offroadTransition); - QObject::connect(&device, &Device::displayPowerChanged, this, &MainWindow::closeSettings); - - // load fonts - QFontDatabase::addApplicationFont("../assets/fonts/opensans_regular.ttf"); - QFontDatabase::addApplicationFont("../assets/fonts/opensans_bold.ttf"); - QFontDatabase::addApplicationFont("../assets/fonts/opensans_semibold.ttf"); - - // no outline to prevent the focus rectangle - setLayout(main_layout); - setStyleSheet(R"( - * { - font-family: Inter; - outline: none; - } - )"); -} - -void MainWindow::offroadTransition(bool offroad){ - if(!offroad){ - closeSettings(); - } -} - -void MainWindow::openSettings() { - main_layout->setCurrentWidget(settingsWindow); -} - -void MainWindow::closeSettings() { - if(onboardingDone) { - main_layout->setCurrentWidget(homeWindow); - } -} - -void MainWindow::reviewTrainingGuide() { - onboardingDone = false; - main_layout->setCurrentWidget(onboardingWindow); - onboardingWindow->updateActiveScreen(); -} - -bool MainWindow::eventFilter(QObject *obj, QEvent *event){ - // wake screen on tap - if (event->type() == QEvent::MouseButtonPress) { - device.setAwake(true, true); - } - -#ifdef QCOM - // filter out touches while in android activity - const static QSet filter_events({QEvent::MouseButtonPress, QEvent::MouseMove, QEvent::TouchBegin, QEvent::TouchUpdate, QEvent::TouchEnd}); - if (HardwareEon::launched_activity && filter_events.contains(event->type())) { - HardwareEon::check_activity(); - if (HardwareEon::launched_activity) { - return true; - } - } -#endif - return false; -} diff --git a/selfdrive/ui/qt/window.h b/selfdrive/ui/qt/window.h deleted file mode 100644 index 5a40e94bb..000000000 --- a/selfdrive/ui/qt/window.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include - -#include "selfdrive/ui/qt/home.h" -#include "selfdrive/ui/qt/offroad/onboarding.h" -#include "selfdrive/ui/qt/offroad/settings.h" -#include "selfdrive/ui/ui.h" - -class MainWindow : public QWidget { - Q_OBJECT - -protected: - bool eventFilter(QObject *obj, QEvent *event) override; - -public: - explicit MainWindow(QWidget *parent = 0); - -private: - Device device; - QUIState qs; - - QStackedLayout *main_layout; - HomeWindow *homeWindow; - SettingsWindow *settingsWindow; - OnboardingWindow *onboardingWindow; - bool onboardingDone = false; - -public slots: - void offroadTransition(bool offroad); - void openSettings(); - void closeSettings(); - void reviewTrainingGuide(); -}; diff --git a/selfdrive/ui/spinner b/selfdrive/ui/spinner index 4a75ca25a..11a7222e5 100755 --- a/selfdrive/ui/spinner +++ b/selfdrive/ui/spinner @@ -4,6 +4,8 @@ if [ -f /EON ] && [ ! -f qt/spinner ]; then cp qt/spinner_aarch64 qt/spinner elif [ -f /TICI ] && [ ! -f qt/spinner ]; then cp qt/spinner_larch64 qt/spinner +elif [ -f /JETSON ] && [ ! -f qt/spinner ]; then + cp qt/spinner_larch64 qt/spinner fi export LD_LIBRARY_PATH="/system/lib64:$LD_LIBRARY_PATH" diff --git a/selfdrive/ui/text b/selfdrive/ui/text index a7177c656..396ff4b60 100755 --- a/selfdrive/ui/text +++ b/selfdrive/ui/text @@ -4,6 +4,8 @@ if [ -f /EON ] && [ ! -f qt/text ]; then cp qt/text_aarch64 qt/text elif [ -f /TICI ] && [ ! -f qt/text ]; then cp qt/text_larch64 qt/text +elif [ -f /JETSON ] && [ ! -f qt/text ]; then + cp qt/text_larch64 qt/text fi export LD_LIBRARY_PATH="/system/lib64:$LD_LIBRARY_PATH" diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc deleted file mode 100644 index 5468a0863..000000000 --- a/selfdrive/ui/ui.cc +++ /dev/null @@ -1,382 +0,0 @@ -#include "selfdrive/ui/ui.h" - -#include -#include -#include - -#include - -#include "selfdrive/common/swaglog.h" -#include "selfdrive/common/util.h" -#include "selfdrive/common/visionimg.h" -#include "selfdrive/common/watchdog.h" -#include "selfdrive/hardware/hw.h" -#include "selfdrive/ui/paint.h" -#include "selfdrive/ui/qt/qt_window.h" - -#define BACKLIGHT_DT 0.25 -#define BACKLIGHT_TS 2.00 -#define BACKLIGHT_OFFROAD 75 - - -// Projects a point in car to space to the corresponding point in full frame -// image space. -static bool calib_frame_to_full_frame(const UIState *s, float in_x, float in_y, float in_z, vertex_data *out) { - const float margin = 500.0f; - const vec3 pt = (vec3){{in_x, in_y, in_z}}; - const vec3 Ep = matvecmul3(s->scene.view_from_calib, pt); - const vec3 KEp = matvecmul3(s->wide_camera ? ecam_intrinsic_matrix : fcam_intrinsic_matrix, Ep); - - // Project. - float x = KEp.v[0] / KEp.v[2]; - float y = KEp.v[1] / KEp.v[2]; - - nvgTransformPoint(&out->x, &out->y, s->car_space_transform, x, y); - return out->x >= -margin && out->x <= s->fb_w + margin && out->y >= -margin && out->y <= s->fb_h + margin; -} - -static void ui_init_vision(UIState *s) { - // Invisible until we receive a calibration message. - s->scene.world_objects_visible = false; - - for (int i = 0; i < s->vipc_client->num_buffers; i++) { - s->texture[i].reset(new EGLImageTexture(&s->vipc_client->buffers[i])); - - glBindTexture(GL_TEXTURE_2D, s->texture[i]->frame_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - // BGR - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); - } - assert(glGetError() == GL_NO_ERROR); -} - -static int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line, const float path_height) { - const auto line_x = line.getX(); - int max_idx = 0; - for (int i = 0; i < TRAJECTORY_SIZE && line_x[i] < path_height; ++i) { - max_idx = i; - } - return max_idx; -} - -static void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, std::optional line) { - for (int i = 0; i < 2; ++i) { - auto lead_data = (i == 0) ? radar_state.getLeadOne() : radar_state.getLeadTwo(); - if (lead_data.getStatus()) { - float z = line ? (*line).getZ()[get_path_length_idx(*line, lead_data.getDRel())] : 0.0; - // negative because radarState uses left positive convention - calib_frame_to_full_frame(s, lead_data.getDRel(), -lead_data.getYRel(), z + 1.22, &s->scene.lead_vertices[i]); - } - } -} - -static void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Reader &line, - float y_off, float z_off, line_vertices_data *pvd, int max_idx) { - const auto line_x = line.getX(), line_y = line.getY(), line_z = line.getZ(); - vertex_data *v = &pvd->v[0]; - for (int i = 0; i <= max_idx; i++) { - v += calib_frame_to_full_frame(s, line_x[i], line_y[i] - y_off, line_z[i] + z_off, v); - } - for (int i = max_idx; i >= 0; i--) { - v += calib_frame_to_full_frame(s, line_x[i], line_y[i] + y_off, line_z[i] + z_off, v); - } - pvd->cnt = v - pvd->v; - assert(pvd->cnt < std::size(pvd->v)); -} - -static void update_model(UIState *s, const cereal::ModelDataV2::Reader &model) { - UIScene &scene = s->scene; - auto model_position = model.getPosition(); - float max_distance = std::clamp(model_position.getX()[TRAJECTORY_SIZE - 1], - MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE); - - // update lane lines - const auto lane_lines = model.getLaneLines(); - const auto lane_line_probs = model.getLaneLineProbs(); - int max_idx = get_path_length_idx(lane_lines[0], max_distance); - for (int i = 0; i < std::size(scene.lane_line_vertices); i++) { - scene.lane_line_probs[i] = lane_line_probs[i]; - update_line_data(s, lane_lines[i], 0.025 * scene.lane_line_probs[i], 0, &scene.lane_line_vertices[i], max_idx); - } - - // update road edges - const auto road_edges = model.getRoadEdges(); - const auto road_edge_stds = model.getRoadEdgeStds(); - for (int i = 0; i < std::size(scene.road_edge_vertices); i++) { - scene.road_edge_stds[i] = road_edge_stds[i]; - update_line_data(s, road_edges[i], 0.025, 0, &scene.road_edge_vertices[i], max_idx); - } - - // update path - auto lead_one = (*s->sm)["radarState"].getRadarState().getLeadOne(); - if (lead_one.getStatus()) { - const float lead_d = lead_one.getDRel() * 2.; - max_distance = std::clamp((float)(lead_d - fmin(lead_d * 0.35, 10.)), 0.0f, max_distance); - } - max_idx = get_path_length_idx(model_position, max_distance); - update_line_data(s, model_position, 0.5, 1.22, &scene.track_vertices, max_idx); -} - -static void update_sockets(UIState *s){ - s->sm->update(0); -} - -static void update_state(UIState *s) { - SubMaster &sm = *(s->sm); - UIScene &scene = s->scene; - - // update engageability and DM icons at 2Hz - if (sm.frame % (UI_FREQ / 2) == 0) { - scene.engageable = sm["controlsState"].getControlsState().getEngageable(); - scene.dm_active = sm["driverMonitoringState"].getDriverMonitoringState().getIsActiveMode(); - } - if (sm.updated("radarState")) { - std::optional line; - if (sm.rcv_frame("modelV2") > 0) { - line = sm["modelV2"].getModelV2().getPosition(); - } - update_leads(s, sm["radarState"].getRadarState(), line); - } - if (sm.updated("liveCalibration")) { - scene.world_objects_visible = true; - auto rpy_list = sm["liveCalibration"].getLiveCalibration().getRpyCalib(); - Eigen::Vector3d rpy; - rpy << rpy_list[0], rpy_list[1], rpy_list[2]; - Eigen::Matrix3d device_from_calib = euler2rot(rpy); - Eigen::Matrix3d view_from_device; - view_from_device << 0,1,0, - 0,0,1, - 1,0,0; - Eigen::Matrix3d view_from_calib = view_from_device * device_from_calib; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - scene.view_from_calib.v[i*3 + j] = view_from_calib(i,j); - } - } - } - if (sm.updated("modelV2")) { - update_model(s, sm["modelV2"].getModelV2()); - } - if (sm.updated("pandaState")) { - auto pandaState = sm["pandaState"].getPandaState(); - scene.pandaType = pandaState.getPandaType(); - scene.ignition = pandaState.getIgnitionLine() || pandaState.getIgnitionCan(); - } else if ((s->sm->frame - s->sm->rcv_frame("pandaState")) > 5*UI_FREQ) { - scene.pandaType = cereal::PandaState::PandaType::UNKNOWN; - } - if (sm.updated("ubloxGnss")) { - auto data = sm["ubloxGnss"].getUbloxGnss(); - if (data.which() == cereal::UbloxGnss::MEASUREMENT_REPORT) { - scene.satelliteCount = data.getMeasurementReport().getNumMeas(); - } - } - if (sm.updated("gpsLocationExternal")) { - scene.gpsAccuracy = sm["gpsLocationExternal"].getGpsLocationExternal().getAccuracy(); - } - if (sm.updated("carParams")) { - scene.longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl(); - } - if (sm.updated("sensorEvents")) { - for (auto sensor : sm["sensorEvents"].getSensorEvents()) { - if (!scene.started && sensor.which() == cereal::SensorEventData::ACCELERATION) { - auto accel = sensor.getAcceleration().getV(); - if (accel.totalSize().wordCount){ // TODO: sometimes empty lists are received. Figure out why - scene.accel_sensor = accel[2]; - } - } else if (!scene.started && sensor.which() == cereal::SensorEventData::GYRO_UNCALIBRATED) { - auto gyro = sensor.getGyroUncalibrated().getV(); - if (gyro.totalSize().wordCount){ - scene.gyro_sensor = gyro[1]; - } - } - } - } - if (sm.updated("roadCameraState")) { - auto camera_state = sm["roadCameraState"].getRoadCameraState(); - - float max_lines = Hardware::EON() ? 5408 : 1757; - float gain = camera_state.getGainFrac(); - - if (Hardware::TICI()) { - // gainFrac can go up to 4, with another 2.5x multiplier based on globalGain. Scale back to 0 - 1 - gain *= (camera_state.getGlobalGain() > 100 ? 2.5 : 1.0) / 10.0; - } - - scene.light_sensor = std::clamp((1023.0 / max_lines) * (max_lines - camera_state.getIntegLines() * gain), 0.0, 1023.0); - } - scene.started = sm["deviceState"].getDeviceState().getStarted(); -} - -static void update_params(UIState *s) { - const uint64_t frame = s->sm->frame; - UIScene &scene = s->scene; - if (frame % (5*UI_FREQ) == 0) { - scene.is_metric = Params().getBool("IsMetric"); - } -} - -static void update_vision(UIState *s) { - if (!s->vipc_client->connected && s->scene.started) { - if (s->vipc_client->connect(false)){ - ui_init_vision(s); - } - } - - if (s->vipc_client->connected){ - VisionBuf * buf = s->vipc_client->recv(); - if (buf != nullptr){ - s->last_frame = buf; - } else if (!Hardware::PC()) { - LOGE("visionIPC receive timeout"); - } - } -} - -static void update_status(UIState *s) { - if (s->scene.started && s->sm->updated("controlsState")) { - auto controls_state = (*s->sm)["controlsState"].getControlsState(); - auto alert_status = controls_state.getAlertStatus(); - if (alert_status == cereal::ControlsState::AlertStatus::USER_PROMPT) { - s->status = STATUS_WARNING; - } else if (alert_status == cereal::ControlsState::AlertStatus::CRITICAL) { - s->status = STATUS_ALERT; - } else { - s->status = controls_state.getEnabled() ? STATUS_ENGAGED : STATUS_DISENGAGED; - } - } - - // Handle onroad/offroad transition - static bool started_prev = false; - if (s->scene.started != started_prev) { - if (s->scene.started) { - s->status = STATUS_DISENGAGED; - s->scene.started_frame = s->sm->frame; - - s->scene.end_to_end = Params().getBool("EndToEndToggle"); - s->wide_camera = Hardware::TICI() ? Params().getBool("EnableWideCamera") : false; - - // Update intrinsics matrix after possible wide camera toggle change - if (s->vg) { - ui_resize(s, s->fb_w, s->fb_h); - } - - // Choose vision ipc client - if (s->wide_camera){ - s->vipc_client = s->vipc_client_wide; - } else { - s->vipc_client = s->vipc_client_rear; - } - } else { - s->vipc_client->connected = false; - } - } - started_prev = s->scene.started; -} - - -QUIState::QUIState(QObject *parent) : QObject(parent) { - ui_state.sm = std::make_unique>({ - "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "liveLocationKalman", - "pandaState", "carParams", "driverMonitoringState", "sensorEvents", "carState", "ubloxGnss", - "gpsLocationExternal", "roadCameraState", - }); - - ui_state.fb_w = vwp_w; - ui_state.fb_h = vwp_h; - ui_state.scene.started = false; - ui_state.last_frame = nullptr; - ui_state.wide_camera = Hardware::TICI() ? Params().getBool("EnableWideCamera") : false; - - ui_state.vipc_client_rear = new VisionIpcClient("camerad", VISION_STREAM_RGB_BACK, true); - ui_state.vipc_client_wide = new VisionIpcClient("camerad", VISION_STREAM_RGB_WIDE, true); - - ui_state.vipc_client = ui_state.vipc_client_rear; - - // update timer - timer = new QTimer(this); - QObject::connect(timer, &QTimer::timeout, this, &QUIState::update); - timer->start(0); -} - -void QUIState::update() { - update_params(&ui_state); - update_sockets(&ui_state); - update_state(&ui_state); - update_status(&ui_state); - update_vision(&ui_state); - - if (ui_state.scene.started != started_prev || ui_state.sm->frame == 1) { - started_prev = ui_state.scene.started; - emit offroadTransition(!ui_state.scene.started); - - // Change timeout to 0 when onroad, this will call update continously. - // This puts visionIPC in charge of update frequency, reducing video latency - timer->start(ui_state.scene.started ? 0 : 1000 / UI_FREQ); - } - - watchdog_kick(); - emit uiUpdate(ui_state); -} - -Device::Device(QObject *parent) : brightness_filter(BACKLIGHT_OFFROAD, BACKLIGHT_TS, BACKLIGHT_DT), QObject(parent) { -} - -void Device::update(const UIState &s) { - updateBrightness(s); - updateWakefulness(s); - - // TODO: remove from UIState and use signals - QUIState::ui_state.awake = awake; -} - -void Device::setAwake(bool on, bool reset) { - if (on != awake) { - awake = on; - Hardware::set_display_power(awake); - LOGD("setting display power %d", awake); - emit displayPowerChanged(awake); - } - - if (reset) { - awake_timeout = 30 * UI_FREQ; - } -} - -void Device::updateBrightness(const UIState &s) { - float brightness_b = 10; - float brightness_m = 0.1; - float clipped_brightness = std::min(100.0f, (s.scene.light_sensor * brightness_m) + brightness_b); - if (!s.scene.started) { - clipped_brightness = BACKLIGHT_OFFROAD; - } - - int brightness = brightness_filter.update(clipped_brightness); - if (!awake) { - brightness = 0; - } - - if (brightness != last_brightness) { - std::thread{Hardware::set_brightness, brightness}.detach(); - } - last_brightness = brightness; -} - -void Device::updateWakefulness(const UIState &s) { - awake_timeout = std::max(awake_timeout - 1, 0); - - bool should_wake = s.scene.started || s.scene.ignition; - if (!should_wake) { - // tap detection while display is off - bool accel_trigger = abs(s.scene.accel_sensor - accel_prev) > 0.2; - bool gyro_trigger = abs(s.scene.gyro_sensor - gyro_prev) > 0.15; - should_wake = accel_trigger && gyro_trigger; - gyro_prev = s.scene.gyro_sensor; - accel_prev = (accel_prev * (accel_samples - 1) + s.scene.accel_sensor) / accel_samples; - } - - setAwake(awake_timeout, should_wake); -} diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h deleted file mode 100644 index a8bcccf3d..000000000 --- a/selfdrive/ui/ui.h +++ /dev/null @@ -1,195 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -#include "nanovg.h" - -#include "cereal/messaging/messaging.h" -#include "cereal/visionipc/visionipc.h" -#include "cereal/visionipc/visionipc_client.h" -#include "common/transformations/orientation.hpp" -#include "selfdrive/camerad/cameras/camera_common.h" -#include "selfdrive/common/glutil.h" -#include "selfdrive/common/mat.h" -#include "selfdrive/common/modeldata.h" -#include "selfdrive/common/params.h" -#include "selfdrive/common/util.h" -#include "selfdrive/common/visionimg.h" - -#define COLOR_BLACK nvgRGBA(0, 0, 0, 255) -#define COLOR_BLACK_ALPHA(x) nvgRGBA(0, 0, 0, x) -#define COLOR_WHITE nvgRGBA(255, 255, 255, 255) -#define COLOR_WHITE_ALPHA(x) nvgRGBA(255, 255, 255, x) -#define COLOR_RED_ALPHA(x) nvgRGBA(201, 34, 49, x) -#define COLOR_YELLOW nvgRGBA(218, 202, 37, 255) -#define COLOR_RED nvgRGBA(201, 34, 49, 255) - -// TODO: this is also hardcoded in common/transformations/camera.py -// TODO: choose based on frame input size -const float y_offset = Hardware::TICI() ? 150.0 : 0.0; -const float zoom = Hardware::TICI() ? 2912.8 : 2138.5; - -typedef struct Rect { - int x, y, w, h; - int centerX() const { return x + w / 2; } - int centerY() const { return y + h / 2; } - int right() const { return x + w; } - int bottom() const { return y + h; } - bool ptInRect(int px, int py) const { - return px >= x && px < (x + w) && py >= y && py < (y + h); - } -} Rect; - -const int bdr_s = 30; -const int header_h = 420; -const int footer_h = 280; - -const int UI_FREQ = 20; // Hz - -typedef enum UIStatus { - STATUS_DISENGAGED, - STATUS_ENGAGED, - STATUS_WARNING, - STATUS_ALERT, -} UIStatus; - -const QColor bg_colors [] = { - [STATUS_DISENGAGED] = QColor(0x17, 0x33, 0x49, 0xc8), - [STATUS_ENGAGED] = QColor(0x17, 0x86, 0x44, 0xf1), - [STATUS_WARNING] = QColor(0xDA, 0x6F, 0x25, 0xf1), - [STATUS_ALERT] = QColor(0xC9, 0x22, 0x31, 0xf1), -}; - -typedef struct { - float x, y; -} vertex_data; - -typedef struct { - vertex_data v[TRAJECTORY_SIZE * 2]; - int cnt; -} line_vertices_data; - -typedef struct UIScene { - - mat3 view_from_calib; - bool world_objects_visible; - - cereal::PandaState::PandaType pandaType; - - // gps - int satelliteCount; - float gpsAccuracy; - - // modelV2 - float lane_line_probs[4]; - float road_edge_stds[2]; - line_vertices_data track_vertices; - line_vertices_data lane_line_vertices[4]; - line_vertices_data road_edge_vertices[2]; - - bool dm_active, engageable; - - // lead - vertex_data lead_vertices[2]; - - float light_sensor, accel_sensor, gyro_sensor; - bool started, ignition, is_metric, longitudinal_control, end_to_end; - uint64_t started_frame; -} UIScene; - -typedef struct UIState { - VisionIpcClient * vipc_client; - VisionIpcClient * vipc_client_rear; - VisionIpcClient * vipc_client_wide; - VisionBuf * last_frame; - - // framebuffer - int fb_w, fb_h; - - // NVG - NVGcontext *vg; - - // images - std::map images; - - std::unique_ptr sm; - - UIStatus status; - UIScene scene; - - // graphics - std::unique_ptr gl_shader; - std::unique_ptr texture[UI_BUF_COUNT]; - - GLuint frame_vao, frame_vbo, frame_ibo; - mat4 rear_frame_mat; - - bool awake; - - Rect video_rect, viz_rect; - float car_space_transform[6]; - bool wide_camera; - float zoom; -} UIState; - - -class QUIState : public QObject { - Q_OBJECT - -public: - QUIState(QObject* parent = 0); - - // TODO: get rid of this, only use signal - inline static UIState ui_state = {0}; - -signals: - void uiUpdate(const UIState &s); - void offroadTransition(bool offroad); - -private slots: - void update(); - -private: - QTimer *timer; - bool started_prev = true; -}; - - -// device management class - -class Device : public QObject { - Q_OBJECT - -public: - Device(QObject *parent = 0); - -private: - // auto brightness - const float accel_samples = 5*UI_FREQ; - - bool awake; - int awake_timeout = 0; - float accel_prev = 0; - float gyro_prev = 0; - float last_brightness = 0; - FirstOrderFilter brightness_filter; - - QTimer *timer; - - void updateBrightness(const UIState &s); - void updateWakefulness(const UIState &s); - -signals: - void displayPowerChanged(bool on); - -public slots: - void setAwake(bool on, bool reset); - void update(const UIState &s); -}; diff --git a/selfdrive/updated.py b/selfdrive/updated.py index ad2d88010..52cf35c46 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -113,7 +113,7 @@ def set_params(new_version: bool, failed_count: int, exception: Optional[str]) - if new_version: try: - with open(os.path.join(FINALIZED, "RELEASES.md"), "rb") as f: + with open(os.path.join(FINALIZED, f"CHANGELOGS-DEV.md"), "rb") as f: r = f.read() r = r[:r.find(b'\n\n')] # Slice latest release notes params.put("ReleaseNotes", r + b"\n") @@ -197,9 +197,9 @@ def init_overlay() -> None: else: run(mount_cmd) - git_diff = run(["git", "diff"], OVERLAY_MERGED, low_priority=True) - params.put("GitDiff", git_diff) - cloudlog.info(f"git diff output:\n{git_diff}") + #git_diff = run(["git", "diff"], OVERLAY_MERGED, low_priority=True) + params.put("GitDiff", "") + #cloudlog.info(f"git diff output:\n{git_diff}") def finalize_update() -> None: diff --git a/selfdrive/version.py b/selfdrive/version.py index 4289d5ca9..688d4947b 100644 --- a/selfdrive/version.py +++ b/selfdrive/version.py @@ -76,7 +76,7 @@ if (origin is not None) and (branch is not None): # Log dirty files if dirty and comma_remote: try: - dirty_files = run_cmd(["git", "diff-index", branch, "--"]) + dirty_files = ""#run_cmd(["git", "diff-index", branch, "--"]) cloudlog.event("dirty comma branch", version=version, dirty=dirty, origin=origin, branch=branch, dirty_files=dirty_files, commit=commit, origin_commit=get_git_commit(branch)) except subprocess.CalledProcessError: diff --git a/tools/openpilot_env.sh b/tools/openpilot_env.sh new file mode 100755 index 000000000..ca25706b8 --- /dev/null +++ b/tools/openpilot_env.sh @@ -0,0 +1,16 @@ +if [ -z "$OPENPILOT_ENV" ]; then + export PYTHONPATH="$HOME/openpilot" + + unamestr=`uname` + if [[ "$unamestr" == 'Linux' ]]; then + export PATH="$HOME/.pyenv/bin:$PATH" + eval "$(pyenv virtualenv-init -)" + elif [[ "$unamestr" == 'Darwin' ]]; then + # msgq doesn't work on mac + export ZMQ=1 + export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES + fi + eval "$(pyenv init -)" + + export OPENPILOT_ENV=1 +fi