diff --git a/apk/ai.comma.plus.offroad.apk b/apk/ai.comma.plus.offroad.apk index 54c3a94bf..65899d328 100644 Binary files a/apk/ai.comma.plus.offroad.apk and b/apk/ai.comma.plus.offroad.apk differ diff --git a/apk/cn.dragonpilot.gpsservice.apk b/apk/cn.dragonpilot.gpsservice.apk index fdd719c93..b098b4c89 100644 Binary files a/apk/cn.dragonpilot.gpsservice.apk and b/apk/cn.dragonpilot.gpsservice.apk differ diff --git a/common/android.py b/common/android.py index e88080884..a4b8b836e 100644 --- a/common/android.py +++ b/common/android.py @@ -4,6 +4,7 @@ import itertools import re import struct import subprocess +import random ANDROID = os.path.isfile('/EON') @@ -17,9 +18,10 @@ def get_imei(slot): if slot not in ("0", "1"): raise ValueError("SIM slot must be 0 or 1") - ret = parse_service_call_string(["iphonesubinfo", "3" ,"i32", str(slot)]) + ret = parse_service_call_string(service_call(["iphonesubinfo", "3" ,"i32", str(slot)])) if not ret: - ret = "000000000000000" + # allow non android to be identified differently + ret = "%015d" % random.randint(0, 1<<32) return ret def get_serial(): @@ -29,7 +31,7 @@ def get_serial(): return ret def get_subscriber_info(): - ret = parse_service_call_string(["iphonesubinfo", "7"]) + ret = parse_service_call_string(service_call(["iphonesubinfo", "7"])) if ret is None or len(ret) < 8: return "" return ret @@ -47,15 +49,23 @@ def reboot(reason=None): "i32", "1" # wait ]) -def parse_service_call_unpack(call, fmt): - r = parse_service_call_bytes(call) +def service_call(call): + if not ANDROID: + return None + + ret = subprocess.check_output(["service", "call", *call], encoding='utf8').strip() + if 'Parcel' not in ret: + return None + + return parse_service_call_bytes(ret) + +def parse_service_call_unpack(r, fmt): try: return struct.unpack(fmt, r)[0] except Exception: return None -def parse_service_call_string(call): - r = parse_service_call_bytes(call) +def parse_service_call_string(r): try: r = r[8:] # Cut off length field r = r.decode('utf_16_be') @@ -71,13 +81,7 @@ def parse_service_call_string(call): except Exception: return None -def parse_service_call_bytes(call): - if not ANDROID: - return None - ret = subprocess.check_output(["service", "call", *call], encoding='utf8').strip() - if 'Parcel' not in ret: - return None - +def parse_service_call_bytes(ret): try: r = b"" for hex_part in re.findall(r'[ (]([0-9a-f]{8})', ret): diff --git a/common/apk.py b/common/apk.py index e9ef98268..b01f5f48d 100644 --- a/common/apk.py +++ b/common/apk.py @@ -32,6 +32,7 @@ def start_frame(): def set_package_permissions(): pm_grant("ai.comma.plus.offroad", "android.permission.ACCESS_FINE_LOCATION") + pm_grant("ai.comma.plus.offroad", "android.permission.READ_PHONE_STATE") appops_set("ai.comma.plus.offroad", "SU", "allow") appops_set("ai.comma.plus.offroad", "WIFI_SCAN", "allow") appops_set("ai.comma.plus.offroad", "READ_EXTERNAL_STORAGE", "allow") diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index 76d4a9ed3..bf3836d07 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -204,8 +204,8 @@ def getSimInfo(): network_type = android.getprop("gsm.network.type").split(',') mcc_mnc = android.getprop("gsm.sim.operator.numeric") or None - sim_id = android.parse_service_call_string(['iphonesubinfo', '11']) - cell_data_state = android.parse_service_call_unpack(['phone', '46'], ">q") + sim_id = android.parse_service_call_string(android.service_call(['iphonesubinfo', '11'])) + cell_data_state = android.parse_service_call_unpack(android.service_call(['phone', '46']), ">q") cell_data_connected = (cell_data_state == 2) return { diff --git a/selfdrive/dragonpilot/appd/appd.py b/selfdrive/dragonpilot/appd/appd.py index 5bb4c5040..0260f0d80 100644 --- a/selfdrive/dragonpilot/appd/appd.py +++ b/selfdrive/dragonpilot/appd/appd.py @@ -5,6 +5,7 @@ import cereal import cereal.messaging as messaging ThermalStatus = cereal.log.ThermalData.ThermalStatus from selfdrive.swaglog import cloudlog +from common.realtime import sec_since_boot from common.params import Params, put_nonblocking params = Params() @@ -13,8 +14,9 @@ class App(): # app type TYPE_GPS = 0 TYPE_SERVICE = 1 - TYPE_FULLSCREEN = 2 - TYPE_UTIL = 3 + TYPE_GPS_SERVICE = 2 + TYPE_FULLSCREEN = 3 + TYPE_UTIL = 4 # frame app FRAME = "ai.comma.plus.frame" @@ -70,33 +72,38 @@ class App(): self.set_package_permissions() self.system("pm disable %s" % self.app) + self.last_ts = sec_since_boot() def read_params(self): - self.last_is_enabled = self.is_enabled - if self.enable_param is None: - self.is_enabled = False - else: - self.is_enabled = True if params.get(self.enable_param, encoding='utf8') == "1" else False - - if self.is_enabled: - # a service app should run automatically and not manual controllable. - if self.app_type == App.TYPE_SERVICE: - self.is_auto_runnable = True - self.manual_ctrl_status = self.MANUAL_IDLE + cur_time = sec_since_boot() + if cur_time - self.last_ts > 5: + self.last_is_enabled = self.is_enabled + if self.enable_param is None: + self.is_enabled = False else: - if self.manual_ctrl_param is None: + self.is_enabled = True if params.get(self.enable_param, encoding='utf8') == "1" else False + + if self.is_enabled: + # a service app should run automatically and not manual controllable. + if self.app_type in [App.TYPE_SERVICE, App.TYPE_GPS_SERVICE]: + self.is_auto_runnable = True self.manual_ctrl_status = self.MANUAL_IDLE else: - self.manual_ctrl_status = params.get(self.manual_ctrl_param, encoding='utf8') + if self.manual_ctrl_param is None: + self.manual_ctrl_status = self.MANUAL_IDLE + else: + self.manual_ctrl_status = params.get(self.manual_ctrl_param, encoding='utf8') - if self.auto_run_param is None: - self.is_auto_runnable = False - else: - self.is_auto_runnable = True if params.get(self.auto_run_param, encoding='utf8') == "1" else False - else: - self.is_auto_runnable = False - self.manual_ctrl_status = self.MANUAL_IDLE - self.manually_ctrled = False + if self.auto_run_param is None: + self.is_auto_runnable = False + else: + self.is_auto_runnable = True if params.get(self.auto_run_param, encoding='utf8') == "1" else False + else: + self.is_auto_runnable = False + self.manual_ctrl_status = self.MANUAL_IDLE + self.manually_ctrled = False + + self.last_ts = cur_time def run(self, force = False): if force or self.is_enabled: @@ -110,17 +117,19 @@ class App(): if force or not self.is_running: # if it's a full screen app, we need to stop frame and offroad to get keyboard access if self.app_type == self.TYPE_FULLSCREEN: - self.system("pkill %s" % self.FRAME) + self.system("pm disable %s" % self.FRAME) self.system("am start -n %s/%s" % (self.OFFROAD, self.OFFROAD_MAIN)) self.system("pm enable %s" % self.app) - if self.app_type == self.TYPE_SERVICE: + if self.app_type == self.TYPE_GPS_SERVICE: + self.appops_set(self.app, "android:mock_location", "allow") + + if self.app_type in [self.TYPE_SERVICE, self.TYPE_GPS_SERVICE]: self.system("am startservice %s/%s" % (self.app, self.activity)) else: self.system("am start -n %s/%s" % (self.app, self.activity)) - - self.is_running = True + self.is_running = True def kill(self, force = False): if force or self.is_enabled: @@ -139,13 +148,14 @@ class App(): self.system("pm enable %s" % self.FRAME) self.system("am start -n %s/%s" % (self.FRAME, self.FRAME_MAIN)) + if self.app_type == self.TYPE_GPS_SERVICE: + self.appops_set(self.app, "android:mock_location", "deny") self.system("pkill %s" % self.app) self.is_running = False def system(self, cmd): try: - # cloudlog.info("running %s" % cmd) subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) except subprocess.CalledProcessError as e: cloudlog.event("running failed", @@ -227,7 +237,7 @@ def init_apps(apps): "DragonGreyPandaMode", None, None, - App.TYPE_SERVICE, + App.TYPE_GPS_SERVICE, [], [], )) @@ -274,26 +284,40 @@ def main(): last_thermal_status = None thermal_status = None + set_location_provider_allowed = False + while 1: #has_enabled_apps: has_fullscreen_apps = False + has_gps_apps = False + has_gps_service_apps = False for app in apps: # read params loop app.read_params() - if app.last_is_enabled and not app.is_enabled: + if app.last_is_enabled and not app.is_enabled and app.is_running: app.kill(True) if app.is_enabled: - if app.app_type == App.TYPE_FULLSCREEN: + if not has_fullscreen_apps and app.app_type == App.TYPE_FULLSCREEN: has_fullscreen_apps = True + elif not has_gps_apps and app.app_type == App.TYPE_GPS: + has_gps_apps = True + elif not has_gps_service_apps and app.app_type == App.TYPE_GPS_SERVICE: + has_gps_service_apps = True - # process manual ctrl apps - for app in apps: - if app.manual_ctrl_status != App.MANUAL_IDLE: - if app.manual_ctrl_status == App.MANUAL_ON: - app.run(True) - else: - app.kill(True) + # process manual ctrl apps + if app.manual_ctrl_status != App.MANUAL_IDLE: + if app.manual_ctrl_status == App.MANUAL_ON: + app.run(True) + else: + app.kill(True) + + # set location provider accuracy + if not set_location_provider_allowed and (has_gps_apps or has_gps_service_apps): + system(f"settings put secure location_providers_allowed -gps") + system(f"settings put secure location_providers_allowed -network") + system(f"settings put secure location_providers_allowed +gps,network") + set_location_provider_allowed = True msg = messaging.recv_sock(thermal_sock, wait=True) started = msg.thermal.started @@ -320,7 +344,7 @@ def main(): # only run once if last_started != started: for app in apps: - if app.app_type == App.TYPE_SERVICE: + if app.app_type in [App.TYPE_SERVICE, App.TYPE_GPS_SERVICE]: app.run() elif app.app_type == App.TYPE_UTIL: app.kill() diff --git a/selfdrive/dragonpilot/appd/appd_bak.py b/selfdrive/dragonpilot/appd/appd_bak.py deleted file mode 100644 index 99a777bdc..000000000 --- a/selfdrive/dragonpilot/appd/appd_bak.py +++ /dev/null @@ -1,353 +0,0 @@ -#!/usr/bin/env python3 -import time -import subprocess -import cereal -import cereal.messaging as messaging -ThermalStatus = cereal.log.ThermalData.ThermalStatus -from selfdrive.swaglog import cloudlog -from common.params import Params, put_nonblocking -params = Params() - -class App(): - - # app type - TYPE_GPS = 0 - TYPE_SERVICE = 1 - TYPE_FULLSCREEN = 2 - TYPE_UTIL = 3 - - # frame app - FRAME = "ai.comma.plus.frame" - FRAME_MAIN = ".MainActivity" - - # offroad app - OFFROAD = "ai.comma.plus.offroad" - OFFROAD_MAIN = ".MainActivity" - - # manual switch stats - MANUAL_OFF = "-1" - MANUAL_IDLE = "0" - MANUAL_ON = "1" - - def appops_set(self, package, op, mode): - self.system(f"LD_LIBRARY_PATH= appops set {package} {op} {mode}") - - def pm_grant(self, package, permission): - self.system(f"pm grant {package} {permission}") - - def set_package_permissions(self): - if self.permissions is not None: - for permission in self.permissions: - self.pm_grant(self.app, permission) - if self.opts is not None: - for opt in self.opts: - self.appops_set(self.app, opt, "allow") - - def __init__(self, app, activity, enable_param, auto_run_param, manual_ctrl_param, app_type, permissions, opts): - self.app = app - # main activity - self.activity = activity - # read enable param - self.enable_param = enable_param - # read auto run param - self.auto_run_param = auto_run_param - # read manual run param - self.manual_ctrl_param = manual_ctrl_param - # if it's a service app, we do not kill if device is too hot - # if it's a full screen app, we need to do extra process on frame/offroad - self.app_type = app_type - - self.permissions = permissions - self.opts = opts - - self.is_enabled = False - self.last_is_enabled = False - self.is_auto_runnable = False - self.is_running = False - self.manual_ctrl_status = self.MANUAL_IDLE - self.manually_ctrled = False - - self.set_package_permissions() - self.system(f"pm disable %s" % self.app) - - def read_params(self): - self.last_is_enabled = self.is_enabled - if self.enable_param is None: - self.is_enabled = False - else: - self.is_enabled = True if params.get(self.enable_param, encoding='utf8') == "1" else False - - if self.is_enabled: - # a service app should run automatically and not manual controllable. - if self.app_type == App.TYPE_SERVICE: - self.is_auto_runnable = True - self.manual_ctrl_status = self.MANUAL_IDLE - else: - if self.manual_ctrl_param is None: - self.manual_ctrl_status = self.MANUAL_IDLE - else: - self.manual_ctrl_status = params.get(self.manual_ctrl_param, encoding='utf8') - - if self.auto_run_param is None: - self.is_auto_runnable = False - else: - self.is_auto_runnable = True if params.get(self.auto_run_param, encoding='utf8') == "1" else False - else: - self.is_auto_runnable = False - self.manual_ctrl_status = self.MANUAL_IDLE - self.manually_ctrled = False - - def run(self): - if self.is_enabled: - # app is manually ctrl, we record that - if self.manual_ctrl_param is not None and self.manual_ctrl_status == self.MANUAL_ON: - put_nonblocking(self.manual_ctrl_param, '0') - self.manually_ctrled = True - self.is_running = False - - # only run app if it's not running - if not self.is_running: - # if it's a full screen app, we need to stop frame and offroad to get keyboard access - if self.app_type == self.TYPE_FULLSCREEN: - self.system(f"pm disable %s" % self.FRAME) - self.system(f"am start -n %s/%s" % (self.OFFROAD, self.OFFROAD_MAIN)) - - self.system(f"pm enable %s" % self.app) - - if self.app_type == self.TYPE_SERVICE: - self.system(f"am startservice %s/%s" % (self.app, self.activity)) - else: - self.system(f"am start -n %s/%s" % (self.app, self.activity)) - - self.is_running = True - - def kill(self): - if self.is_enabled: - # app is manually ctrl, we record that - if self.manual_ctrl_param is not None and self.manual_ctrl_status == self.MANUAL_OFF: - put_nonblocking(self.manual_ctrl_param, '0') - self.manually_ctrled = True - self.is_running = True - - # only kill app if it's running - if self.is_running: - # if it's a full screen app, we need to restart offroad and frame - if self.app_type == self.TYPE_FULLSCREEN: - self.system(f"pm disable %s" % self.OFFROAD) - self.system(f"pm enable %s" % self.OFFROAD) - self.system(f"pm enable %s" % self.FRAME) - self.system(f"am start -n %s/%s" % (self.FRAME, self.FRAME_MAIN)) - - self.system(f"pm disable %s" % self.app) - self.is_running = False - - def system(self, cmd): - try: - # cloudlog.info("running %s" % cmd) - print(cmd) - subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) - except subprocess.CalledProcessError as e: - cloudlog.event("running failed", - cmd=e.cmd, - output=e.output[-1024:], - returncode=e.returncode) - -def init_apps(apps): - apps.append(App( - # v1.16.2 - "com.tomtom.speedcams.android.map", - "com.tomtom.speedcams.android.activities.SpeedCamActivity", - "DragonEnableTomTom", - "DragonBootTomTom", - "DragonRunTomTom", - App.TYPE_GPS, - [ - "android.permission.ACCESS_FINE_LOCATION", - "android.permission.ACCESS_COARSE_LOCATION", - "android.permission.READ_EXTERNAL_STORAGE", - "android.permission.WRITE_EXTERNAL_STORAGE", - ], - [ - "SYSTEM_ALERT_WINDOW", - ] - )) - apps.append(App( - # v4.3.0.600310 R2098NSLAE - "com.autonavi.amapauto", - "com.autonavi.amapauto.MainMapActivity", - "DragonEnableAutonavi", - "DragonBootAutonavi", - "DragonRunAutonavi", - App.TYPE_GPS, - [ - "android.permission.ACCESS_FINE_LOCATION", - "android.permission.ACCESS_COARSE_LOCATION", - "android.permission.READ_EXTERNAL_STORAGE", - "android.permission.WRITE_EXTERNAL_STORAGE", - ], - [ - "SYSTEM_ALERT_WINDOW", - ] - )) - apps.append(App( - # v6.40.3 - "com.mixplorer", - "com.mixplorer.activities.BrowseActivity", - "DragonEnableMixplorer", - None, - "DragonRunMixplorer", - App.TYPE_UTIL, - [ - "android.permission.READ_EXTERNAL_STORAGE", - "android.permission.WRITE_EXTERNAL_STORAGE", - ], - [], - )) - apps.append(App( - # v2.9.5 build 74 - "tw.com.ainvest.outpack", - "tw.com.ainvest.outpack.ui.MainActivity", - "DragonEnableAegis", - "DragonBootAegis", - "DragonRunAegis", - App.TYPE_GPS, - [ - "android.permission.ACCESS_FINE_LOCATION", - "android.permission.READ_EXTERNAL_STORAGE", - "android.permission.WRITE_EXTERNAL_STORAGE", - ], - [ - "SYSTEM_ALERT_WINDOW", - ] - )) - apps.append(App( - "cn.dragonpilot.gpsservice", - "cn.dragonpilot.gpsservice.MainService", - "DragonGreyPandaMode", - None, - None, - App.TYPE_SERVICE, - [], - [], - )) - apps.append(App( - # v4.57.2.0 - "com.waze", - "com.waze.MainActivity", - "DragonWazeMode", - None, - "DragonRunWaze", - App.TYPE_FULLSCREEN, - [ - "android.permission.ACCESS_FINE_LOCATION", - "android.permission.ACCESS_COARSE_LOCATION", - "android.permission.READ_EXTERNAL_STORAGE", - "android.permission.WRITE_EXTERNAL_STORAGE", - "android.permission.RECORD_AUDIO", - ], - [], - )) - -def main(): - # has_enabled_apps = False - has_fullscreen_apps = False - has_auto_run_apps = False - apps = [] - - init_apps(apps) - - last_started = False - thermal_sock = messaging.sub_sock('thermal') - allow_auto_run = True - - frame = 0 - start_delay = None - stop_delay = None - - - while 1: #has_enabled_apps: - msg = messaging.recv_sock(thermal_sock, wait=True) - started = msg.thermal.started - - for app in apps: - # read params loop - app.read_params() - if app.is_enabled: - if app.app_type == App.TYPE_FULLSCREEN: - has_fullscreen_apps = True - if app.is_auto_runnable: - has_auto_run_apps = True - if app.manual_ctrl_status != App.MANUAL_IDLE: - if app.manual_ctrl_status == App.MANUAL_ON: - app.run() - else: - app.kill() - - # when car is running - if started: - stop_delay = None - if start_delay is None: - start_delay = frame + 5 - - # start service and fullscreen apps and kill the reset - if has_fullscreen_apps: - for app in apps: - if not app.manually_ctrled and app.app_type in [App.TYPE_SERVICE, App.TYPE_FULLSCREEN]: - app.run() - else: - app.kill() - else: - # kill any util apps - for app in apps: - if app.app_type == App.TYPE_UTIL: - app.kill() - - # auto run ctrl for normal apps - if has_auto_run_apps: - thermal_status = msg.thermal.thermalStatus - if not allow_auto_run and thermal_status <= ThermalStatus.yellow: - allow_auto_run = True - - if allow_auto_run and thermal_status >= ThermalStatus.red: - allow_auto_run = False - - if frame > start_delay: - for app in apps: - if app.is_auto_runnable and not app.manually_ctrled: - if allow_auto_run: - if not app.is_running and app.app_type not in [App.TYPE_FULLSCREEN, App.TYPE_UTIL]: - app.run() - else: - if app.is_running and app.app_type not in [App.TYPE_SERVICE]: - app.kill() - - # when car is stopped - else: - start_delay = None - # set delay to 30 seconds - if stop_delay is None: - stop_delay = frame + 30 - - # when car is off, we want to kill full screen app first - if has_fullscreen_apps: - for app in apps: - if not app.manually_ctrled and app.is_running: - app.kill() - else: - # kill rest of the apps after delay - if frame > stop_delay: - for app in apps: - if not app.manually_ctrled and app.is_running: - app.kill() - - if last_started != started: - for app in apps: - app.manually_ctrled = False - - last_started = started - frame += 3 - time.sleep(3) - -if __name__ == "__main__": - main() - diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py index 8f7e0a67a..6067f01ed 100644 --- a/selfdrive/loggerd/uploader.py +++ b/selfdrive/loggerd/uploader.py @@ -67,11 +67,13 @@ def clear_locks(root): def is_on_wifi(): # ConnectivityManager.getActiveNetworkInfo() try: - result = android.parse_service_call_string(["connectivity", "2"]) + # TODO: figure out why the android service call sometimes dies with SIGUSR2 (signal from MSGQ) + result = android.parse_service_call_string(android.service_call(["connectivity", "2"])) if result is None: return True return 'WIFI' in result - except AttributeError: + except (AttributeError, subprocess.CalledProcessError): + cloudlog.exception("is_on_wifi failed") return False def is_on_hotspot(): diff --git a/selfdrive/pandad.py b/selfdrive/pandad.py index e64b99049..2c21bdf72 100755 --- a/selfdrive/pandad.py +++ b/selfdrive/pandad.py @@ -58,7 +58,7 @@ def update_panda(): serial = None panda_version = "bootstub" if panda.bootstub else panda.get_version() - panda_signature = "bootstub" if panda.bootstub else panda.get_signature() + panda_signature = b"" if panda.bootstub else panda.get_signature() cloudlog.warning("Panda %s connected, version: %s, signature %s, expected %s" % ( serial, panda_version, diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc index 417d2ad69..470c0e6ae 100644 --- a/selfdrive/ui/paint.cc +++ b/selfdrive/ui/paint.cc @@ -790,78 +790,75 @@ static void ui_draw_infobar(UIState *s) { int ui_viz_rx = scene->ui_viz_rx; bool hasSidebar = !s->scene.uilayout_sidebarcollapsed; // rect_w = screen_width - sidebar width - int rect_w = vwp_w - (hasSidebar? sbr_w : 0); - if (s->dragon_driving_ui) { - // if driving ui is enabled, rect_w = rect_w - vision start x - small boarder - rect_w = rect_w - ui_viz_rx - bdr_s; - } + + int rect_w = vwp_w - ui_viz_rx - bdr_s; int rect_h = 80; // rect_x = 0 + sidebar width - int rect_x = 0; - if (s->dragon_driving_ui) { - // if driving ui is enabled, rect_x = rect_x + vision start x - rect_x = rect_x + (hasSidebar? sbr_w : 0) + ui_viz_rx; - } + + // if driving ui is enabled, rect_x = rect_x + vision start x + int rect_x = (hasSidebar? (bdr_s+sbr_w) : ui_viz_rx); + // rect_y = screen height - board - background height int rect_y = vwp_h - bdr_s - rect_h; // int text_width; - int text_x = rect_w / 2; - if (s->dragon_driving_ui) { - text_x = text_x + (hasSidebar? sbr_w : 0) + ui_viz_rx; - } + int text_x = rect_w / 2 + ui_viz_rx; int text_y = rect_y + 55; - // Get local time to display - char infobar[68]; - time_t t = time(NULL); - struct tm tm = *localtime(&t); + char infobar[100]; + // create time string + char date_time[17]; + time_t rawtime = time(NULL); + struct tm timeinfo; + localtime_r(&rawtime, &timeinfo); + strftime(date_time, sizeof(date_time),"%D %T", &timeinfo); + + // Create temp string + char temp[6]; + snprintf(temp, sizeof(temp), "%02.0f°C", s->scene.pa0); + + // create battery percentage string + char battery[4]; + snprintf(battery, sizeof(battery), "%02d%%", s->scene.batteryPercent); if (s->dragon_ui_dev_mini) { - char rel_steer[9]; - snprintf(rel_steer, sizeof(rel_steer), "%s%05.1f°", s->scene.angleSteers < 0? "-" : "+", fabs(s->scene.angleSteers)); + char rel_steer[9]; + snprintf(rel_steer, sizeof(rel_steer), "%s%05.1f°", s->scene.angleSteers < 0? "-" : "+", fabs(s->scene.angleSteers)); - char des_steer[9]; - if (s->scene.engaged) { - snprintf(des_steer, sizeof(des_steer), "%s%05.1f°", s->scene.angleSteersDes < 0? "-" : "+", fabs(s->scene.angleSteersDes)); - } else { - snprintf(des_steer, sizeof(des_steer), "%7s", "N/A"); - } + char des_steer[9]; + if (s->scene.engaged) { + snprintf(des_steer, sizeof(des_steer), "%s%05.1f°", s->scene.angleSteersDes < 0? "-" : "+", fabs(s->scene.angleSteersDes)); + } else { + snprintf(des_steer, sizeof(des_steer), "%7s", "-"); + } + char lead_dist[8]; + if (s->scene.lead_status) { + snprintf(lead_dist, sizeof(lead_dist), "%06.2fm", s->scene.lead_d_rel); + } else { + snprintf(lead_dist, sizeof(lead_dist), "%7s", "-"); + } - char lead_dist[8]; - if (s->scene.lead_status) { - snprintf(lead_dist, sizeof(lead_dist), "%06.2fm", s->scene.lead_d_rel); - } else { - snprintf(lead_dist, sizeof(lead_dist), "%7s", "N/A"); - } - - snprintf( - infobar, - sizeof(infobar), - "%04d/%02d/%02d %02d:%02d:%02d | REL: %s | DES: %s | DIST: %s", - tm.tm_year + 1900, - tm.tm_mon + 1, - tm.tm_mday, - tm.tm_hour, - tm.tm_min, - tm.tm_sec, - rel_steer, - des_steer, - lead_dist - ); + snprintf( + infobar, + sizeof(infobar), + "%s /TMP: %s /BAT: %s /REL: %s /DES: %s /DIS: %s", + date_time, + temp, + battery, + rel_steer, + des_steer, + lead_dist + ); } else { - snprintf( - infobar, - sizeof(infobar), - "%04d/%02d/%02d %02d:%02d:%02d", - tm.tm_year + 1900, - tm.tm_mon + 1, - tm.tm_mday, - tm.tm_hour, - tm.tm_min, - tm.tm_sec - ); + snprintf( + infobar, + sizeof(infobar), + "%s /TMP: %s /BAT: %s", + date_time, + temp, + battery + ); } nvgBeginPath(s->vg); @@ -869,7 +866,7 @@ static void ui_draw_infobar(UIState *s) { nvgFillColor(s->vg, nvgRGBA(0, 0, 0, 180)); nvgFill(s->vg); - nvgFontSize(s->vg, hasSidebar? 40:50); + nvgFontSize(s->vg, hasSidebar? 35:42); nvgFontFace(s->vg, "courbd"); nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 180)); nvgTextAlign(s->vg, NVG_ALIGN_CENTER); @@ -1096,7 +1093,7 @@ static void ui_draw_vision_footer(UIState *s) { if (s->dragon_ui_dev) { ui_draw_bbui(s); } - if (s->dragon_ui_dev_mini || s->dragon_enable_dashcam) { + if (s->dragon_ui_dev_mini || s->dragon_enable_dashcam || s->dragon_waze_mode) { ui_draw_infobar(s); } } @@ -1170,7 +1167,9 @@ static void ui_draw_vision(UIState *s) { glScissor(ui_viz_rx, s->fb_h-(box_y+box_h), ui_viz_rw, box_h); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - draw_frame(s); + if (s->dragon_driving_ui) { + draw_frame(s); + } glViewport(0, 0, s->fb_w, s->fb_h); glDisable(GL_SCISSOR_TEST); @@ -1180,12 +1179,14 @@ static void ui_draw_vision(UIState *s) { nvgSave(s->vg); // Draw augmented elements - const int inner_height = viz_w*9/16; - nvgScissor(s->vg, ui_viz_rx, box_y, ui_viz_rw, box_h); - nvgTranslate(s->vg, ui_viz_rx+ui_viz_ro, box_y + (box_h-inner_height)/2.0); - nvgScale(s->vg, (float)viz_w / s->fb_w, (float)inner_height / s->fb_h); - if (!scene->frontview && !scene->fullview) { - ui_draw_world(s); + if (s->dragon_driving_ui) { + const int inner_height = viz_w*9/16; + nvgScissor(s->vg, ui_viz_rx, box_y, ui_viz_rw, box_h); + nvgTranslate(s->vg, ui_viz_rx+ui_viz_ro, box_y + (box_h-inner_height)/2.0); + nvgScale(s->vg, (float)viz_w / s->fb_w, (float)inner_height / s->fb_h); + if (!scene->frontview && !scene->fullview) { + ui_draw_world(s); + } } nvgRestore(s->vg); diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 8685d341e..b8740e01e 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -113,6 +113,7 @@ static void ui_init(UIState *s) { s->livecalibration_sock = SubSocket::create(s->ctx, "liveCalibration"); s->radarstate_sock = SubSocket::create(s->ctx, "radarState"); s->carstate_sock = SubSocket::create(s->ctx, "carState"); + s->thermal_sock = SubSocket::create(s->ctx, "thermal"); assert(s->model_sock != NULL); assert(s->controlsstate_sock != NULL); @@ -120,6 +121,7 @@ static void ui_init(UIState *s) { assert(s->livecalibration_sock != NULL); assert(s->radarstate_sock != NULL); assert(s->carstate_sock != NULL); + assert(s->thermal_sock != NULL); s->poller = Poller::create({ s->model_sock, @@ -127,7 +129,8 @@ static void ui_init(UIState *s) { s->uilayout_sock, s->livecalibration_sock, s->radarstate_sock, - s->carstate_sock + s->carstate_sock, + s->thermal_sock }); #ifdef SHOW_SPEEDLIMIT @@ -481,6 +484,12 @@ void handle_message(UIState *s, Message * msg) { } s->scene.leftBlinker = datad.leftBlinker; s->scene.rightBlinker = datad.rightBlinker; + } else if (eventd.which == cereal_Event_thermal) { + struct cereal_ThermalData datad; + cereal_read_ThermalData(&datad, eventd.thermal); + + s->scene.batteryPercent = datad.batteryPercent; + s->scene.pa0 = datad.pa0; } capn_free(&ctx); } diff --git a/selfdrive/ui/ui.hpp b/selfdrive/ui/ui.hpp index 0f09c4e16..8b63cdd35 100644 --- a/selfdrive/ui/ui.hpp +++ b/selfdrive/ui/ui.hpp @@ -122,6 +122,8 @@ typedef struct UIScene { // for minimal UI float angleSteersDes; float angleSteers; + float pa0; + int batteryPercent; // for blinker, from kegman bool leftBlinker; @@ -255,6 +257,7 @@ typedef struct UIState { // dragonpilot SubSocket *carstate_sock; + SubSocket *thermal_sock; int dragon_ui_speed_timeout; int dragon_ui_event_timeout; int dragon_ui_maxspeed_timeout;