mirror of https://github.com/commaai/openpilot.git
APK purge (#20446)
* purge begins
* release files
* remove those
* no more android
* only qt
* text and spinner
* neos update script
* update sounds
* update cpu usage
* all done
Co-authored-by: Comma Device <device@comma.ai>
old-commit-hash: e76c80ffa1
This commit is contained in:
parent
5fc14c8db3
commit
51c13aa552
|
@ -3,7 +3,6 @@
|
|||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
*.pb filter=lfs diff=lfs merge=lfs -text
|
||||
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||
*.apk filter=lfs diff=lfs merge=lfs -text
|
||||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.ipynb filter=nbstripout -diff
|
||||
external/ffmpeg/bin/ffmpeg_cuda filter=lfs diff=lfs merge=lfs -text
|
||||
|
@ -39,6 +38,7 @@ third_party/acados/*/t_renderer filter=lfs diff=lfs merge=lfs -text
|
|||
third_party/qt5/larch64/bin/lrelease filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/qt5/larch64/bin/lupdate filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/catch2/include/catch2/catch.hpp filter=lfs diff=lfs merge=lfs -text
|
||||
*.apk filter=lfs diff=lfs merge=lfs -text
|
||||
*.apkpatch filter=lfs diff=lfs merge=lfs -text
|
||||
*.jar filter=lfs diff=lfs merge=lfs -text
|
||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||
|
|
|
@ -59,8 +59,6 @@ notebooks
|
|||
xx
|
||||
hyperthneed
|
||||
panda_jungle
|
||||
apks
|
||||
openpilot-apks
|
||||
|
||||
.coverage*
|
||||
coverage.xml
|
||||
|
|
|
@ -130,8 +130,6 @@ pipeline {
|
|||
["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"],
|
||||
["build devel", "cd release && CI_PUSH=${env.CI_PUSH} ./build_devel.sh"],
|
||||
["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"],
|
||||
["test spinner build", "cd selfdrive/ui/spinner && make clean && make"],
|
||||
["test text window build", "cd selfdrive/ui/text && make clean && make"],
|
||||
])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -312,7 +312,6 @@ And [follow us on Twitter](https://twitter.com/comma_ai).
|
|||
Directory Structure
|
||||
------
|
||||
.
|
||||
├── apk # The apk files used for the UI
|
||||
├── cereal # The messaging spec and libs used for all logs
|
||||
├── common # Library like functionality we've developed here
|
||||
├── installer/updater # Manages auto-updates of openpilot
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:34f8beca20214315be942f67aa3a6f2743174430da06b15706fbca610a9150b5
|
||||
size 13715186
|
|
@ -6,8 +6,6 @@ export NUMEXPR_NUM_THREADS=1
|
|||
export OPENBLAS_NUM_THREADS=1
|
||||
export VECLIB_MAXIMUM_THREADS=1
|
||||
|
||||
export QT=1
|
||||
|
||||
if [ -z "$REQUIRED_NEOS_VERSION" ]; then
|
||||
export REQUIRED_NEOS_VERSION="16.1"
|
||||
fi
|
||||
|
|
|
@ -13,8 +13,6 @@ RELEASES.md
|
|||
SAFETY.md
|
||||
site_scons/site_tools/cython.py
|
||||
|
||||
apk/ai.comma*.apk
|
||||
|
||||
common/.gitignore
|
||||
common/__init__.py
|
||||
common/gpio.py
|
||||
|
@ -267,7 +265,6 @@ selfdrive/hardware/base.h
|
|||
selfdrive/hardware/base.py
|
||||
selfdrive/hardware/hw.h
|
||||
selfdrive/hardware/eon/__init__.py
|
||||
selfdrive/hardware/eon/apk.py
|
||||
selfdrive/hardware/eon/hardware.h
|
||||
selfdrive/hardware/eon/hardware.py
|
||||
selfdrive/hardware/tici/__init__.py
|
||||
|
@ -344,13 +341,6 @@ selfdrive/ui/*.hpp
|
|||
selfdrive/ui/ui
|
||||
selfdrive/ui/text
|
||||
selfdrive/ui/spinner
|
||||
selfdrive/ui/android/spinner/Makefile
|
||||
selfdrive/ui/android/spinner/spinner
|
||||
selfdrive/ui/android/spinner/spinner.c
|
||||
|
||||
selfdrive/ui/android/text/Makefile
|
||||
selfdrive/ui/android/text/text
|
||||
selfdrive/ui/android/text/text.cc
|
||||
|
||||
selfdrive/ui/qt/*.cc
|
||||
selfdrive/ui/qt/*.hpp
|
||||
|
@ -359,9 +349,6 @@ selfdrive/ui/qt/offroad/*.hpp
|
|||
selfdrive/ui/qt/widgets/*.cc
|
||||
selfdrive/ui/qt/widgets/*.hpp
|
||||
|
||||
selfdrive/ui/android/*.cc
|
||||
selfdrive/ui/android/*.hpp
|
||||
|
||||
selfdrive/camerad/SConscript
|
||||
selfdrive/camerad/main.cc
|
||||
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
import os
|
||||
import subprocess
|
||||
import glob
|
||||
import hashlib
|
||||
import shutil
|
||||
from common.basedir import BASEDIR
|
||||
from selfdrive.swaglog import cloudlog
|
||||
|
||||
android_packages = ("ai.comma.plus.offroad",)
|
||||
|
||||
def get_installed_apks():
|
||||
dat = subprocess.check_output(["pm", "list", "packages", "-f"], encoding='utf8').strip().split("\n")
|
||||
ret = {}
|
||||
for x in dat:
|
||||
if x.startswith("package:"):
|
||||
v, k = x.split("package:")[1].split("=")
|
||||
ret[k] = v
|
||||
return ret
|
||||
|
||||
def install_apk(path):
|
||||
# can only install from world readable path
|
||||
install_path = "/sdcard/%s" % os.path.basename(path)
|
||||
shutil.copyfile(path, install_path)
|
||||
|
||||
ret = subprocess.call(["pm", "install", "-r", install_path])
|
||||
os.remove(install_path)
|
||||
return ret == 0
|
||||
|
||||
def start_offroad():
|
||||
set_package_permissions()
|
||||
system("am start -n ai.comma.plus.offroad/.MainActivity")
|
||||
|
||||
def set_package_permissions():
|
||||
try:
|
||||
output = subprocess.check_output(['dumpsys', 'package', 'ai.comma.plus.offroad'], encoding="utf-8")
|
||||
given_permissions = output.split("runtime permissions")[1]
|
||||
except Exception:
|
||||
given_permissions = ""
|
||||
|
||||
wanted_permissions = ["ACCESS_FINE_LOCATION", "READ_PHONE_STATE", "READ_EXTERNAL_STORAGE"]
|
||||
for permission in wanted_permissions:
|
||||
if permission not in given_permissions:
|
||||
pm_grant("ai.comma.plus.offroad", "android.permission."+permission)
|
||||
|
||||
appops_set("ai.comma.plus.offroad", "SU", "allow")
|
||||
appops_set("ai.comma.plus.offroad", "WIFI_SCAN", "allow")
|
||||
|
||||
def appops_set(package, op, mode):
|
||||
system(f"LD_LIBRARY_PATH= appops set {package} {op} {mode}")
|
||||
|
||||
def pm_grant(package, permission):
|
||||
system(f"pm grant {package} {permission}")
|
||||
|
||||
def system(cmd):
|
||||
try:
|
||||
cloudlog.info("running %s" % cmd)
|
||||
subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
cloudlog.event("running failed",
|
||||
cmd=e.cmd,
|
||||
output=e.output[-1024:],
|
||||
returncode=e.returncode)
|
||||
|
||||
# *** external functions ***
|
||||
|
||||
def update_apks():
|
||||
# install apks
|
||||
installed = get_installed_apks()
|
||||
|
||||
install_apks = glob.glob(os.path.join(BASEDIR, "apk/*.apk"))
|
||||
for apk in install_apks:
|
||||
app = os.path.basename(apk)[:-4]
|
||||
if app not in installed:
|
||||
installed[app] = None
|
||||
|
||||
cloudlog.info("installed apks %s" % (str(installed), ))
|
||||
|
||||
for app in installed.keys():
|
||||
apk_path = os.path.join(BASEDIR, "apk/"+app+".apk")
|
||||
if not os.path.exists(apk_path):
|
||||
continue
|
||||
|
||||
h1 = hashlib.sha1(open(apk_path, 'rb').read()).hexdigest()
|
||||
h2 = None
|
||||
if installed[app] is not None:
|
||||
h2 = hashlib.sha1(open(installed[app], 'rb').read()).hexdigest()
|
||||
cloudlog.info("comparing version of %s %s vs %s" % (app, h1, h2))
|
||||
|
||||
if h2 is None or h1 != h2:
|
||||
cloudlog.info("installing %s" % app)
|
||||
|
||||
success = install_apk(apk_path)
|
||||
if not success:
|
||||
cloudlog.info("needing to uninstall %s" % app)
|
||||
system("pm uninstall %s" % app)
|
||||
success = install_apk(apk_path)
|
||||
|
||||
assert success
|
||||
|
||||
def pm_apply_packages(cmd):
|
||||
for p in android_packages:
|
||||
system("pm %s %s" % (cmd, p))
|
||||
|
||||
if __name__ == "__main__":
|
||||
update_apks()
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
ROOT=$PWD/../../..
|
||||
$ROOT/installer/updater/updater "file://$ROOT/installer/updater/update.json"
|
|
@ -12,9 +12,7 @@ from common.basedir import BASEDIR
|
|||
from common.params import Params
|
||||
from common.spinner import Spinner
|
||||
from common.text_window import TextWindow
|
||||
from selfdrive.hardware import EON, HARDWARE
|
||||
from selfdrive.hardware.eon.apk import (pm_apply_packages, start_offroad,
|
||||
update_apks)
|
||||
from selfdrive.hardware import HARDWARE
|
||||
from selfdrive.manager.build import MAX_BUILD_PROGRESS, PREBUILT
|
||||
from selfdrive.manager.helpers import unblock_stdout
|
||||
from selfdrive.manager.process import ensure_running
|
||||
|
@ -60,9 +58,6 @@ def manager_init(spinner=None):
|
|||
if params.get("Passive") is None:
|
||||
raise Exception("Passive must be set to continue")
|
||||
|
||||
if EON:
|
||||
update_apks()
|
||||
|
||||
os.umask(0) # Make sure we can create files with 777 permissions
|
||||
|
||||
# Create folders needed for msgq
|
||||
|
@ -89,13 +84,6 @@ def manager_init(spinner=None):
|
|||
crash.bind_user(id=dongle_id)
|
||||
crash.bind_extra(version=version, dirty=dirty, device=HARDWARE.get_device_type())
|
||||
|
||||
# ensure shared libraries are readable by apks
|
||||
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)
|
||||
|
||||
|
||||
def manager_prepare(spinner=None):
|
||||
# build all processes
|
||||
|
@ -110,9 +98,6 @@ def manager_prepare(spinner=None):
|
|||
|
||||
|
||||
def manager_cleanup():
|
||||
if EON:
|
||||
pm_apply_packages('disable')
|
||||
|
||||
for p in managed_processes.values():
|
||||
p.stop()
|
||||
|
||||
|
@ -132,11 +117,6 @@ def manager_thread(spinner=None):
|
|||
if os.getenv("BLOCK") is not None:
|
||||
ignore += os.getenv("BLOCK").split(",")
|
||||
|
||||
# start offroad
|
||||
if EON and "QT" not in os.environ:
|
||||
pm_apply_packages('enable')
|
||||
start_offroad()
|
||||
|
||||
ensure_running(managed_processes.values(), started=False, not_run=ignore)
|
||||
if spinner: # close spinner when ui has started
|
||||
spinner.close()
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import time
|
||||
import subprocess
|
||||
from functools import wraps
|
||||
from nose.tools import nottest
|
||||
|
||||
from selfdrive.hardware.eon.apk import update_apks, start_offroad, pm_apply_packages, android_packages
|
||||
from selfdrive.hardware import PC
|
||||
from selfdrive.version import training_version, terms_version
|
||||
from selfdrive.manager.process_config import managed_processes
|
||||
|
@ -49,26 +47,3 @@ def with_processes(processes, init_time=0):
|
|||
|
||||
return wrap
|
||||
return wrapper
|
||||
|
||||
|
||||
def with_apks():
|
||||
def wrapper(func):
|
||||
@wraps(func)
|
||||
def wrap():
|
||||
update_apks()
|
||||
pm_apply_packages('enable')
|
||||
start_offroad()
|
||||
|
||||
func()
|
||||
|
||||
try:
|
||||
for package in android_packages:
|
||||
apk_is_running = (subprocess.call(["pidof", package]) == 0)
|
||||
assert apk_is_running, package
|
||||
finally:
|
||||
pm_apply_packages('disable')
|
||||
for package in android_packages:
|
||||
apk_is_not_running = (subprocess.call(["pidof", package]) == 1)
|
||||
assert apk_is_not_running, package
|
||||
return wrap
|
||||
return wrapper
|
||||
|
|
|
@ -18,10 +18,10 @@ PROCS = [
|
|||
("./loggerd", 45.0),
|
||||
("selfdrive.locationd.locationd", 35.0),
|
||||
("selfdrive.controls.plannerd", 20.0),
|
||||
("./_ui", 15.0),
|
||||
("selfdrive.locationd.paramsd", 12.0),
|
||||
("./camerad", 7.07),
|
||||
("./_sensord", 6.17),
|
||||
("./_ui", 5.82),
|
||||
("selfdrive.controls.radard", 5.67),
|
||||
("./_modeld", 4.48),
|
||||
("./boardd", 3.63),
|
||||
|
|
|
@ -4,7 +4,7 @@ import subprocess
|
|||
|
||||
from cereal import log, car
|
||||
import cereal.messaging as messaging
|
||||
from selfdrive.test.helpers import phone_only, with_processes
|
||||
from selfdrive.test.helpers import phone_only, with_processes, set_params_enabled
|
||||
from common.realtime import DT_CTRL
|
||||
from selfdrive.hardware import HARDWARE
|
||||
|
||||
|
@ -13,14 +13,14 @@ AudibleAlert = car.CarControl.HUDControl.AudibleAlert
|
|||
SOUNDS = {
|
||||
# sound: total writes
|
||||
AudibleAlert.none: 0,
|
||||
AudibleAlert.chimeEngage: 85,
|
||||
AudibleAlert.chimeDisengage: 85,
|
||||
AudibleAlert.chimeError: 85,
|
||||
AudibleAlert.chimePrompt: 85,
|
||||
AudibleAlert.chimeWarning1: 80,
|
||||
AudibleAlert.chimeWarning2: 107,
|
||||
AudibleAlert.chimeWarning2Repeat: 177,
|
||||
AudibleAlert.chimeWarningRepeat: 240,
|
||||
AudibleAlert.chimeEngage: 173,
|
||||
AudibleAlert.chimeDisengage: 173,
|
||||
AudibleAlert.chimeError: 173,
|
||||
AudibleAlert.chimePrompt: 173,
|
||||
AudibleAlert.chimeWarning1: 163,
|
||||
AudibleAlert.chimeWarning2: 216,
|
||||
AudibleAlert.chimeWarning2Repeat: 346,
|
||||
AudibleAlert.chimeWarningRepeat: 468,
|
||||
}
|
||||
|
||||
def get_total_writes():
|
||||
|
@ -36,7 +36,7 @@ def test_sound_card_init():
|
|||
@phone_only
|
||||
@with_processes(['ui', 'camerad'])
|
||||
def test_alert_sounds():
|
||||
|
||||
set_params_enabled()
|
||||
pm = messaging.PubMaster(['deviceState', 'controlsState'])
|
||||
|
||||
# make sure they're all defined
|
||||
|
@ -70,3 +70,4 @@ def test_alert_sounds():
|
|||
tolerance = (expected_writes % 100) * 2
|
||||
actual_writes = get_total_writes() - start_writes
|
||||
assert abs(expected_writes - actual_writes) <= tolerance, f"{alert_sounds[sound]}: expected {expected_writes} writes, got {actual_writes}"
|
||||
#print(f"{alert_sounds[sound]}: expected {expected_writes} writes, got {actual_writes}")
|
||||
|
|
|
@ -10,59 +10,50 @@ if arch == 'aarch64':
|
|||
libs += ['log', 'utils', 'gui', 'ui', 'CB', 'gsl', 'adreno_utils',
|
||||
'cutils', 'uuid']
|
||||
|
||||
if arch == 'aarch64' and "QT" not in os.environ:
|
||||
libs += ['EGL', 'GLESv3', 'gnustl_shared', 'hardware', 'OpenSLES', 'cutils', 'uuid']
|
||||
linkflags = ['-Wl,-rpath=/system/lib64,-rpath=/system/comma/usr/lib']
|
||||
qt_base_libs = qt_env["LIBS"] + libs + ["pthread"]
|
||||
if arch == "Darwin":
|
||||
del qt_base_libs[qt_base_libs.index('OpenCL')]
|
||||
qt_env['FRAMEWORKS'] += ['OpenCL']
|
||||
|
||||
src += ["android/ui.cc", "android/sl_sound.cc"]
|
||||
env.Program('_ui', src,
|
||||
LINKFLAGS=linkflags,
|
||||
LIBS=libs)
|
||||
else:
|
||||
qt_base_libs = qt_env["LIBS"] + libs + ["pthread"]
|
||||
if arch == "Darwin":
|
||||
del qt_base_libs[qt_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/qt_sound.cc",
|
||||
"qt/widgets/offroad_alerts.cc", "qt/widgets/setup.cc", "qt/widgets/keyboard.cc",
|
||||
"#phonelibs/qrcode/QrCode.cc"]
|
||||
if arch != 'aarch64':
|
||||
widgets_src += ["qt/offroad/networking.cc", "qt/offroad/wifiManager.cc"]
|
||||
|
||||
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/qt_sound.cc",
|
||||
"qt/widgets/offroad_alerts.cc", "qt/widgets/setup.cc", "qt/widgets/keyboard.cc",
|
||||
"#phonelibs/qrcode/QrCode.cc"]
|
||||
widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=qt_base_libs)
|
||||
qt_libs = qt_base_libs + [widgets]
|
||||
|
||||
if arch != 'aarch64':
|
||||
widgets_src += ["qt/offroad/networking.cc", "qt/offroad/wifiManager.cc"]
|
||||
# spinner and text window
|
||||
qt_env.Program("qt/text", ["qt/text.cc"], LIBS=qt_base_libs)
|
||||
qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=qt_base_libs)
|
||||
|
||||
widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=qt_base_libs)
|
||||
qt_libs = qt_base_libs + [widgets]
|
||||
# build main UI
|
||||
qt_src = ["qt/ui.cc", "qt/window.cc", "qt/home.cc", "qt/api.cc", "qt/offroad/settings.cc",
|
||||
"qt/offroad/onboarding.cc"] + src
|
||||
qt_env.Program("_ui", qt_src, LIBS=qt_libs)
|
||||
|
||||
qt_src = ["qt/ui.cc", "qt/window.cc", "qt/home.cc", "qt/api.cc", "qt/offroad/settings.cc",
|
||||
"qt/offroad/onboarding.cc"] + src
|
||||
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'])
|
||||
|
||||
# spinner and text window
|
||||
qt_env.Program("qt/text", ["qt/text.cc"], LIBS=qt_base_libs)
|
||||
qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=qt_base_libs)
|
||||
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"
|
||||
|
||||
# build setup, factory resetter, and installer
|
||||
if "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()}\\"'
|
||||
qt_env.Program(f"qt/setup/installer_{name}", ["qt/setup/installer.cc"], LIBS=qt_libs, CPPDEFINES=d)
|
||||
import requests
|
||||
r = requests.get("https://github.com/commaci2.keys")
|
||||
r.raise_for_status()
|
||||
d['SSH_KEYS'] = f'\\"{r.text.strip()}\\"'
|
||||
qt_env.Program(f"qt/setup/installer_{name}", ["qt/setup/installer.cc"], LIBS=qt_libs, CPPDEFINES=d)
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <atomic>
|
||||
#include "common/swaglog.h"
|
||||
#include "common/timing.h"
|
||||
|
||||
#include "android/sl_sound.hpp"
|
||||
|
||||
#define LogOnError(func, msg) \
|
||||
if ((func) != SL_RESULT_SUCCESS) { LOGW(msg); }
|
||||
|
||||
#define ReturnOnError(func, msg) \
|
||||
if ((func) != SL_RESULT_SUCCESS) { LOGW(msg); return false; }
|
||||
|
||||
struct SLSound::Player {
|
||||
SLObjectItf player;
|
||||
SLPlayItf playItf;
|
||||
std::atomic<int> repeat;
|
||||
};
|
||||
|
||||
SLSound::SLSound() {
|
||||
if (!init()){
|
||||
throw std::runtime_error("Failed to initialize sound");
|
||||
}
|
||||
}
|
||||
|
||||
bool SLSound::init() {
|
||||
SLEngineOption engineOptions[] = {{SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE}};
|
||||
const SLInterfaceID ids[1] = {SL_IID_VOLUME};
|
||||
const SLboolean req[1] = {SL_BOOLEAN_FALSE};
|
||||
SLEngineItf engineInterface = NULL;
|
||||
ReturnOnError(slCreateEngine(&engine_, 1, engineOptions, 0, NULL, NULL), "Failed to create OpenSL engine");
|
||||
ReturnOnError((*engine_)->Realize(engine_, SL_BOOLEAN_FALSE), "Failed to realize OpenSL engine");
|
||||
ReturnOnError((*engine_)->GetInterface(engine_, SL_IID_ENGINE, &engineInterface), "Failed to get OpenSL engine interface");
|
||||
ReturnOnError((*engineInterface)->CreateOutputMix(engineInterface, &outputMix_, 1, ids, req), "Failed to create output mix");
|
||||
ReturnOnError((*outputMix_)->Realize(outputMix_, SL_BOOLEAN_FALSE), "Failed to realize output mix");
|
||||
|
||||
for (auto &kv : sound_map) {
|
||||
SLDataLocator_URI locUri = {SL_DATALOCATOR_URI, (SLchar *)kv.second.first};
|
||||
SLDataFormat_MIME formatMime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
|
||||
SLDataSource audioSrc = {&locUri, &formatMime};
|
||||
SLDataLocator_OutputMix outMix = {SL_DATALOCATOR_OUTPUTMIX, outputMix_};
|
||||
SLDataSink audioSnk = {&outMix, NULL};
|
||||
|
||||
SLObjectItf player = NULL;
|
||||
SLPlayItf playItf = NULL;
|
||||
ReturnOnError((*engineInterface)->CreateAudioPlayer(engineInterface, &player, &audioSrc, &audioSnk, 0, NULL, NULL), "Failed to create audio player");
|
||||
ReturnOnError((*player)->Realize(player, SL_BOOLEAN_FALSE), "Failed to realize audio player");
|
||||
ReturnOnError((*player)->GetInterface(player, SL_IID_PLAY, &playItf), "Failed to get player interface");
|
||||
ReturnOnError((*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED), "Failed to initialize playstate to SL_PLAYSTATE_PAUSED");
|
||||
|
||||
player_[kv.first] = new SLSound::Player{player, playItf};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event) {
|
||||
SLSound::Player *s = reinterpret_cast<SLSound::Player *>(context);
|
||||
if (event == SL_PLAYEVENT_HEADATEND && s->repeat != 0) {
|
||||
if (s->repeat > 0) --s->repeat;
|
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
|
||||
(*playItf)->SetMarkerPosition(playItf, 0);
|
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
bool SLSound::play(AudibleAlert alert) {
|
||||
if (currentSound_ != AudibleAlert::NONE) {
|
||||
stop();
|
||||
}
|
||||
|
||||
auto player = player_.at(alert);
|
||||
SLPlayItf playItf = player->playItf;
|
||||
|
||||
int loops = sound_map[alert].second;
|
||||
player->repeat = loops > 0 ? loops - 1 : loops;
|
||||
if (player->repeat != 0) {
|
||||
ReturnOnError((*playItf)->RegisterCallback(playItf, slplay_callback, player), "Failed to register callback");
|
||||
ReturnOnError((*playItf)->SetCallbackEventsMask(playItf, SL_PLAYEVENT_HEADATEND), "Failed to set callback event mask");
|
||||
}
|
||||
|
||||
// Reset the audio player
|
||||
ReturnOnError((*playItf)->ClearMarkerPosition(playItf), "Failed to clear marker position");
|
||||
uint32_t states[] = {SL_PLAYSTATE_PAUSED, SL_PLAYSTATE_STOPPED, SL_PLAYSTATE_PLAYING};
|
||||
for (auto state : states) {
|
||||
ReturnOnError((*playItf)->SetPlayState(playItf, state), "Failed to set SL_PLAYSTATE_PLAYING");
|
||||
}
|
||||
currentSound_ = alert;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SLSound::stop() {
|
||||
if (currentSound_ != AudibleAlert::NONE) {
|
||||
auto player = player_.at(currentSound_);
|
||||
player->repeat = 0;
|
||||
LogOnError((*(player->playItf))->SetPlayState(player->playItf, SL_PLAYSTATE_PAUSED), "Failed to set SL_PLAYSTATE_PAUSED");
|
||||
currentSound_ = AudibleAlert::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void SLSound::setVolume(int volume) {
|
||||
if (last_volume_ == volume) return;
|
||||
|
||||
double current_time = nanos_since_boot();
|
||||
if ((current_time - last_set_volume_time_) > (5 * (1e+9))) { // 5s timeout on updating the volume
|
||||
char volume_change_cmd[64];
|
||||
snprintf(volume_change_cmd, sizeof(volume_change_cmd), "service call audio 3 i32 3 i32 %d i32 1 &", volume);
|
||||
system(volume_change_cmd);
|
||||
last_volume_ = volume;
|
||||
last_set_volume_time_ = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
SLSound::~SLSound() {
|
||||
for (auto &kv : player_) {
|
||||
(*(kv.second->player))->Destroy(kv.second->player);
|
||||
delete kv.second;
|
||||
}
|
||||
if (outputMix_) {
|
||||
(*outputMix_)->Destroy(outputMix_);
|
||||
}
|
||||
if (engine_) {
|
||||
(*engine_)->Destroy(engine_);
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
#pragma once
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
|
||||
#include "sound.hpp"
|
||||
|
||||
|
||||
class SLSound : public Sound {
|
||||
public:
|
||||
SLSound();
|
||||
~SLSound();
|
||||
bool play(AudibleAlert alert);
|
||||
void stop();
|
||||
void setVolume(int volume);
|
||||
|
||||
private:
|
||||
bool init();
|
||||
SLObjectItf engine_ = nullptr;
|
||||
SLObjectItf outputMix_ = nullptr;
|
||||
int last_volume_ = 0;
|
||||
double last_set_volume_time_ = 0.;
|
||||
AudibleAlert currentSound_ = AudibleAlert::NONE;
|
||||
struct Player;
|
||||
std::map<AudibleAlert, Player *> player_;
|
||||
friend void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event);
|
||||
};
|
|
@ -1,77 +0,0 @@
|
|||
CC = clang
|
||||
CXX = clang++
|
||||
|
||||
ROOT_DIR = ../../..
|
||||
PHONELIBS = $(ROOT_DIR)/phonelibs
|
||||
COMMON = $(ROOT)/selfdrive/common
|
||||
|
||||
WARN_FLAGS = -Werror=implicit-function-declaration \
|
||||
-Werror=incompatible-pointer-types \
|
||||
-Werror=int-conversion \
|
||||
-Werror=return-type \
|
||||
-Werror=format-extra-args
|
||||
|
||||
CFLAGS = -std=gnu11 -fPIC -O2 $(WARN_FLAGS)
|
||||
CXXFLAGS = -std=c++1z -fPIC -O2 $(WARN_FLAGS)
|
||||
|
||||
NANOVG_FLAGS = -I$(PHONELIBS)/nanovg
|
||||
|
||||
OPENGL_LIBS = -lGLESv3
|
||||
|
||||
FRAMEBUFFER_LIBS = -lutils -lgui -lEGL
|
||||
|
||||
OBJS = spinner.o \
|
||||
$(COMMON)/framebuffer.o \
|
||||
$(COMMON)/util.o \
|
||||
$(PHONELIBS)/nanovg/nanovg.o \
|
||||
$(COMMON)/spinner.o \
|
||||
opensans_semibold.o \
|
||||
img_spinner_track.o \
|
||||
img_spinner_comma.o
|
||||
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
.PHONY: all
|
||||
all: spinner
|
||||
|
||||
spinner: $(OBJS)
|
||||
@echo "[ LINK ] $@"
|
||||
$(CXX) -fPIC -o '$@' $^ \
|
||||
-s \
|
||||
$(FRAMEBUFFER_LIBS) \
|
||||
-L/system/vendor/lib64 \
|
||||
$(OPENGL_LIBS) \
|
||||
-lm -llog
|
||||
|
||||
$(COMMON)/framebuffer.o: $(COMMON)/framebuffer.cc
|
||||
@echo "[ CXX ] $@"
|
||||
$(CXX) $(CXXFLAGS) -MMD \
|
||||
-I$(PHONELIBS)/android_frameworks_native/include \
|
||||
-I$(PHONELIBS)/android_system_core/include \
|
||||
-I$(PHONELIBS)/android_hardware_libhardware/include \
|
||||
-c -o '$@' '$<'
|
||||
|
||||
opensans_semibold.o: $(ROOT_DIR)/selfdrive/assets/fonts/opensans_semibold.ttf
|
||||
@echo "[ bin2o ] $@"
|
||||
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
|
||||
|
||||
img_spinner_track.o: $(ROOT_DIR)/selfdrive/assets/img_spinner_track.png
|
||||
@echo "[ bin2o ] $@"
|
||||
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
|
||||
|
||||
img_spinner_comma.o: $(ROOT_DIR)/selfdrive/assets/img_spinner_comma.png
|
||||
@echo "[ bin2o ] $@"
|
||||
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
|
||||
|
||||
%.o: %.c
|
||||
@echo "[ CC ] $@"
|
||||
$(CC) $(CFLAGS) -MMD \
|
||||
-I../.. \
|
||||
$(NANOVG_FLAGS) \
|
||||
-c -o '$@' '$<'
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f spinner $(OBJS) $(DEPS)
|
||||
|
||||
-include $(DEPS)
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:faaf9aa68d97142708c474a0221f1cd2db020c79d6385bac7749586918db3c99
|
||||
size 551136
|
|
@ -1,182 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <GLES3/gl3.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "nanovg.h"
|
||||
#define NANOVG_GLES3_IMPLEMENTATION
|
||||
#include "nanovg_gl.h"
|
||||
#include "nanovg_gl_utils.h"
|
||||
|
||||
#include "framebuffer.h"
|
||||
#include "spinner.h"
|
||||
|
||||
#define SPINTEXT_LENGTH 128
|
||||
|
||||
// external resources linked in
|
||||
extern const unsigned char _binary_opensans_semibold_ttf_start[];
|
||||
extern const unsigned char _binary_opensans_semibold_ttf_end[];
|
||||
|
||||
extern const unsigned char _binary_img_spinner_track_png_start[];
|
||||
extern const unsigned char _binary_img_spinner_track_png_end[];
|
||||
|
||||
extern const unsigned char _binary_img_spinner_comma_png_start[];
|
||||
extern const unsigned char _binary_img_spinner_comma_png_end[];
|
||||
|
||||
bool stdin_input_available() {
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
select(STDIN_FILENO+1, &fds, NULL, NULL, &timeout);
|
||||
return (FD_ISSET(0, &fds));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
bool draw_progress = false;
|
||||
float progress_val = 0.0;
|
||||
|
||||
char spintext[SPINTEXT_LENGTH];
|
||||
spintext[0] = 0;
|
||||
|
||||
const char* spintext_arg = NULL;
|
||||
if (argc >= 2) {
|
||||
strncpy(spintext, argv[1], SPINTEXT_LENGTH);
|
||||
}
|
||||
|
||||
// spinner
|
||||
int fb_w, fb_h;
|
||||
FramebufferState *fb = framebuffer_init("spinner", 0x00001000, false,
|
||||
&fb_w, &fb_h);
|
||||
assert(fb);
|
||||
framebuffer_set_power(fb, HWC_POWER_MODE_NORMAL);
|
||||
|
||||
NVGcontext *vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
|
||||
assert(vg);
|
||||
|
||||
int font = nvgCreateFontMem(vg, "Bold", (unsigned char*)_binary_opensans_semibold_ttf_start, _binary_opensans_semibold_ttf_end-_binary_opensans_semibold_ttf_start, 0);
|
||||
assert(font >= 0);
|
||||
|
||||
int spinner_img = nvgCreateImageMem(vg, 0, (unsigned char*)_binary_img_spinner_track_png_start, _binary_img_spinner_track_png_end - _binary_img_spinner_track_png_start);
|
||||
assert(spinner_img >= 0);
|
||||
int spinner_img_s = 360;
|
||||
int spinner_img_x = ((fb_w/2)-(spinner_img_s/2));
|
||||
int spinner_img_y = 260;
|
||||
int spinner_img_xc = (fb_w/2);
|
||||
int spinner_img_yc = (fb_h/2)-100;
|
||||
int spinner_comma_img = nvgCreateImageMem(vg, 0, (unsigned char*)_binary_img_spinner_comma_png_start, _binary_img_spinner_comma_png_end - _binary_img_spinner_comma_png_start);
|
||||
assert(spinner_comma_img >= 0);
|
||||
|
||||
for (int cnt = 0; ; cnt++) {
|
||||
// Check stdin for new text
|
||||
if (stdin_input_available()){
|
||||
fgets(spintext, SPINTEXT_LENGTH, stdin);
|
||||
spintext[strcspn(spintext, "\n")] = 0;
|
||||
|
||||
// Check if number (update progress bar)
|
||||
size_t len = strlen(spintext);
|
||||
bool is_number = len > 0;
|
||||
for (int i = 0; i < len; i++){
|
||||
if (!isdigit(spintext[i])){
|
||||
is_number = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_number) {
|
||||
progress_val = (float)(atoi(spintext)) / 100.0;
|
||||
progress_val = fmin(1.0, progress_val);
|
||||
progress_val = fmax(0.0, progress_val);
|
||||
}
|
||||
|
||||
draw_progress = is_number;
|
||||
}
|
||||
|
||||
glClearColor(0.1, 0.1, 0.1, 1.0);
|
||||
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
nvgBeginFrame(vg, fb_w, fb_h, 1.0f);
|
||||
|
||||
// background
|
||||
nvgBeginPath(vg);
|
||||
NVGpaint bg = nvgLinearGradient(vg, fb_w, 0, fb_w, fb_h,
|
||||
nvgRGBA(0, 0, 0, 175), nvgRGBA(0, 0, 0, 255));
|
||||
nvgFillPaint(vg, bg);
|
||||
nvgRect(vg, 0, 0, fb_w, fb_h);
|
||||
nvgFill(vg);
|
||||
|
||||
// spin track
|
||||
nvgSave(vg);
|
||||
nvgTranslate(vg, spinner_img_xc, spinner_img_yc);
|
||||
nvgRotate(vg, (3.75*M_PI * cnt/120.0));
|
||||
nvgTranslate(vg, -spinner_img_xc, -spinner_img_yc);
|
||||
NVGpaint spinner_imgPaint = nvgImagePattern(vg, spinner_img_x, spinner_img_y,
|
||||
spinner_img_s, spinner_img_s, 0, spinner_img, 0.6f);
|
||||
nvgBeginPath(vg);
|
||||
nvgFillPaint(vg, spinner_imgPaint);
|
||||
nvgRect(vg, spinner_img_x, spinner_img_y, spinner_img_s, spinner_img_s);
|
||||
nvgFill(vg);
|
||||
nvgRestore(vg);
|
||||
|
||||
// comma
|
||||
NVGpaint comma_imgPaint = nvgImagePattern(vg, spinner_img_x, spinner_img_y,
|
||||
spinner_img_s, spinner_img_s, 0, spinner_comma_img, 1.0f);
|
||||
nvgBeginPath(vg);
|
||||
nvgFillPaint(vg, comma_imgPaint);
|
||||
nvgRect(vg, spinner_img_x, spinner_img_y, spinner_img_s, spinner_img_s);
|
||||
nvgFill(vg);
|
||||
|
||||
if (draw_progress){
|
||||
// draw progress bar
|
||||
int progress_width = 1000;
|
||||
int progress_x = fb_w/2-progress_width/2;
|
||||
int progress_y = 775;
|
||||
int progress_height = 25;
|
||||
|
||||
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);
|
||||
|
||||
int bar_pos = ((progress_width - 2) * progress_val);
|
||||
|
||||
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);
|
||||
} else {
|
||||
// message
|
||||
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_TOP);
|
||||
nvgFontSize(vg, 96.0f);
|
||||
nvgText(vg, fb_w/2, (fb_h*2/3)+24, spintext, NULL);
|
||||
}
|
||||
|
||||
nvgEndFrame(vg);
|
||||
framebuffer_swap(fb);
|
||||
assert(glGetError() == GL_NO_ERROR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
CC = clang
|
||||
CXX = clang++
|
||||
|
||||
PHONELIBS = ../../../../phonelibs
|
||||
COMMON = ../../../common
|
||||
|
||||
WARN_FLAGS = -Werror=implicit-function-declaration \
|
||||
-Werror=incompatible-pointer-types \
|
||||
-Werror=int-conversion \
|
||||
-Werror=return-type \
|
||||
-Werror=format-extra-args
|
||||
|
||||
CFLAGS = -std=gnu11 -fPIC -O2 $(WARN_FLAGS)
|
||||
CXXFLAGS = -std=c++1z -fPIC -O2 $(WARN_FLAGS)
|
||||
|
||||
NANOVG_FLAGS = -I$(PHONELIBS)/nanovg
|
||||
|
||||
OPENGL_LIBS = -lGLESv3
|
||||
|
||||
FRAMEBUFFER_LIBS = -lutils -lgui -lEGL
|
||||
|
||||
OBJS = text.o \
|
||||
$(COMMON)/framebuffer.o \
|
||||
$(COMMON)/util.o \
|
||||
$(COMMON)/touch.o \
|
||||
$(PHONELIBS)/nanovg/nanovg.o \
|
||||
opensans_regular.o \
|
||||
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
.PHONY: all
|
||||
all: text
|
||||
|
||||
text: $(OBJS)
|
||||
@echo "[ LINK ] $@"
|
||||
$(CXX) -fPIC -o '$@' $^ \
|
||||
-s \
|
||||
$(FRAMEBUFFER_LIBS) \
|
||||
-L/system/vendor/lib64 \
|
||||
$(OPENGL_LIBS) \
|
||||
-lm -llog
|
||||
|
||||
opensans_regular.o: ../../../assets/fonts/opensans_regular.ttf
|
||||
@echo "[ bin2o ] $@"
|
||||
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
|
||||
|
||||
%.o: %.cc
|
||||
mkdir -p $(@D)
|
||||
@echo "[ CXX ] $@"
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) \
|
||||
-I../../../selfdrive \
|
||||
-I../../../ \
|
||||
-I$(PHONELIBS)/android_frameworks_native/include \
|
||||
-I$(PHONELIBS)/android_system_core/include \
|
||||
-I$(PHONELIBS)/android_hardware_libhardware/include \
|
||||
$(NANOVG_FLAGS) \
|
||||
-c -o '$@' '$<'
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f text $(OBJS) $(DEPS)
|
||||
|
||||
-include $(DEPS)
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:be30fb76fbf9a21853c5357757e126210254f46b758ec2fd7438c24604d2bd70
|
||||
size 494112
|
|
@ -1,133 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <memory>
|
||||
#include <GLES3/gl3.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "nanovg.h"
|
||||
#define NANOVG_GLES3_IMPLEMENTATION
|
||||
#include "nanovg_gl.h"
|
||||
#include "nanovg_gl_utils.h"
|
||||
|
||||
#include "common/framebuffer.h"
|
||||
#include "common/touch.h"
|
||||
|
||||
|
||||
#define COLOR_WHITE nvgRGBA(255, 255, 255, 255)
|
||||
#define MAX_TEXT_SIZE 2048
|
||||
|
||||
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");
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int err;
|
||||
|
||||
// spinner
|
||||
int fb_w, fb_h;
|
||||
std::unique_ptr<FrameBuffer> fb = std::make_unique<FrameBuffer>("text", 0x00001000, false,
|
||||
&fb_w, &fb_h);
|
||||
assert(fb);
|
||||
|
||||
NVGcontext *vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
|
||||
assert(vg);
|
||||
|
||||
int font = nvgCreateFontMem(vg, "regular", (unsigned char*)bin_opensans_regular, (bin_opensans_regular_end - bin_opensans_regular), 0);
|
||||
assert(font >= 0);
|
||||
|
||||
// Awake
|
||||
fb->set_power(HWC_POWER_MODE_NORMAL);
|
||||
set_brightness(255);
|
||||
|
||||
glClearColor(0.1, 0.1, 0.1, 1.0);
|
||||
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
nvgBeginFrame(vg, fb_w, fb_h, 1.0f);
|
||||
|
||||
// background
|
||||
nvgBeginPath(vg);
|
||||
NVGpaint bg = nvgLinearGradient(vg, fb_w, 0, fb_w, fb_h,
|
||||
nvgRGBA(0, 0, 0, 175), nvgRGBA(0, 0, 0, 255));
|
||||
nvgFillPaint(vg, bg);
|
||||
nvgRect(vg, 0, 0, fb_w, fb_h);
|
||||
nvgFill(vg);
|
||||
|
||||
|
||||
// Text
|
||||
nvgFillColor(vg, COLOR_WHITE);
|
||||
nvgFontSize(vg, 75.0f);
|
||||
|
||||
if (argc >= 2) {
|
||||
float x = 150;
|
||||
float y = 150;
|
||||
|
||||
// Copy text
|
||||
char * text = (char *)malloc(MAX_TEXT_SIZE);
|
||||
strncpy(text, argv[1], MAX_TEXT_SIZE);
|
||||
|
||||
float lineh;
|
||||
nvgTextMetrics(vg, NULL, NULL, &lineh);
|
||||
|
||||
// nvgTextBox strips leading whitespace. We have to reimplement
|
||||
char * next = strtok(text, "\n");
|
||||
while (next != NULL){
|
||||
nvgText(vg, x, y, next, NULL);
|
||||
y += lineh;
|
||||
next = strtok(NULL, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Button
|
||||
int b_x = 1500;
|
||||
int b_y = 800;
|
||||
int b_w = 300;
|
||||
int b_h = 150;
|
||||
|
||||
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));
|
||||
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
||||
nvgText(vg, b_x+b_w/2, b_y+b_h/2, "Exit", 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 to screen
|
||||
nvgEndFrame(vg);
|
||||
fb->swap();
|
||||
assert(glGetError() == GL_NO_ERROR);
|
||||
|
||||
|
||||
// Wait for button
|
||||
TouchState touch;
|
||||
touch_init(&touch);
|
||||
|
||||
while (true){
|
||||
int touch_x = -1, touch_y = -1;
|
||||
int res = touch_poll(&touch, &touch_x, &touch_y, 0);
|
||||
if (res){
|
||||
|
||||
if (touch_x > b_x && touch_x < b_x + b_w){
|
||||
if (touch_y > b_y && touch_y < b_y + b_h){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
usleep(1000000 / 60);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/framebuffer.h"
|
||||
#include "common/util.h"
|
||||
#include "common/params.h"
|
||||
#include "common/swaglog.h"
|
||||
#include "common/touch.h"
|
||||
#include "common/watchdog.h"
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "paint.hpp"
|
||||
#include "android/sl_sound.hpp"
|
||||
|
||||
ExitHandler do_exit;
|
||||
static void ui_set_brightness(UIState *s, int brightness) {
|
||||
static int last_brightness = -1;
|
||||
if (last_brightness != brightness && (s->awake || brightness == 0)) {
|
||||
if (set_brightness(brightness)) {
|
||||
last_brightness = brightness;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_display_state(UIState *s, FrameBuffer *fb, bool user_input) {
|
||||
static int awake_timeout = 0;
|
||||
|
||||
constexpr float accel_samples = 5*UI_FREQ;
|
||||
static float accel_prev = 0., gyro_prev = 0.;
|
||||
|
||||
bool should_wake = s->scene.started || s->scene.ignition || user_input;
|
||||
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;
|
||||
}
|
||||
|
||||
// determine desired state
|
||||
if (should_wake) {
|
||||
awake_timeout = 30*UI_FREQ;
|
||||
} else if (awake_timeout > 0){
|
||||
--awake_timeout;
|
||||
should_wake = true;
|
||||
}
|
||||
|
||||
// handle state transition
|
||||
if (s->awake != should_wake) {
|
||||
s->awake = should_wake;
|
||||
int display_mode = s->awake ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
|
||||
LOGW("setting display mode %d", display_mode);
|
||||
fb->set_power(display_mode);
|
||||
|
||||
if (s->awake) {
|
||||
system("service call window 18 i32 1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_vision_touch(UIState *s, int touch_x, int touch_y) {
|
||||
if (s->scene.started && (touch_x >= s->viz_rect.x - bdr_s)
|
||||
&& (s->active_app != cereal::UiLayoutState::App::SETTINGS)) {
|
||||
if (!s->scene.driver_view) {
|
||||
s->sidebar_collapsed = !s->sidebar_collapsed;
|
||||
} else {
|
||||
Params().write_db_value("IsDriverViewEnabled", "0", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_sidebar_touch(UIState *s, int touch_x, int touch_y) {
|
||||
if (!s->sidebar_collapsed && touch_x <= sbr_w) {
|
||||
if (settings_btn.ptInRect(touch_x, touch_y)) {
|
||||
s->active_app = cereal::UiLayoutState::App::SETTINGS;
|
||||
} else if (home_btn.ptInRect(touch_x, touch_y)) {
|
||||
if (s->scene.started) {
|
||||
s->active_app = cereal::UiLayoutState::App::NONE;
|
||||
s->sidebar_collapsed = true;
|
||||
} else {
|
||||
s->active_app = cereal::UiLayoutState::App::HOME;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_offroad_layout_state(UIState *s, PubMaster *pm) {
|
||||
static int timeout = 0;
|
||||
static bool prev_collapsed = false;
|
||||
static cereal::UiLayoutState::App prev_app = cereal::UiLayoutState::App::NONE;
|
||||
if (timeout > 0) {
|
||||
timeout--;
|
||||
}
|
||||
if (prev_collapsed != s->sidebar_collapsed || prev_app != s->active_app || timeout == 0) {
|
||||
MessageBuilder msg;
|
||||
auto layout = msg.initEvent().initUiLayoutState();
|
||||
layout.setActiveApp(s->active_app);
|
||||
layout.setSidebarCollapsed(s->sidebar_collapsed);
|
||||
pm->send("offroadLayout", msg);
|
||||
LOGD("setting active app to %d with sidebar %d", (int)s->active_app, s->sidebar_collapsed);
|
||||
prev_collapsed = s->sidebar_collapsed;
|
||||
prev_app = s->active_app;
|
||||
timeout = 2 * UI_FREQ;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
setpriority(PRIO_PROCESS, 0, -14);
|
||||
|
||||
SLSound sound;
|
||||
UIState uistate = {};
|
||||
UIState *s = &uistate;
|
||||
FrameBuffer fb = FrameBuffer("ui", 0, true, &s->fb_w, &s->fb_h);
|
||||
|
||||
ui_init(s);
|
||||
s->sound = &sound;
|
||||
|
||||
TouchState touch = {0};
|
||||
touch_init(&touch);
|
||||
handle_display_state(s, &fb, true);
|
||||
|
||||
PubMaster *pm = new PubMaster({"offroadLayout"});
|
||||
|
||||
// light sensor scaling and volume params
|
||||
float brightness_b = 0, brightness_m = 0;
|
||||
int result = read_param(&brightness_b, "BRIGHTNESS_B", true);
|
||||
result += read_param(&brightness_m, "BRIGHTNESS_M", true);
|
||||
if (result != 0) {
|
||||
brightness_b = 10.0;
|
||||
brightness_m = 2.6;
|
||||
write_param_float(brightness_b, "BRIGHTNESS_B", true);
|
||||
write_param_float(brightness_m, "BRIGHTNESS_M", true);
|
||||
}
|
||||
float smooth_brightness = brightness_b;
|
||||
|
||||
const int MIN_VOLUME = 12;
|
||||
const int MAX_VOLUME = 15;
|
||||
s->sound->setVolume(MIN_VOLUME);
|
||||
|
||||
while (!do_exit) {
|
||||
watchdog_kick();
|
||||
if (!s->scene.started) {
|
||||
util::sleep_for(50);
|
||||
}
|
||||
double u1 = millis_since_boot();
|
||||
|
||||
ui_update(s);
|
||||
|
||||
// poll for touch events
|
||||
int touch_x = -1, touch_y = -1;
|
||||
int touched = touch_poll(&touch, &touch_x, &touch_y, 0);
|
||||
if (touched == 1) {
|
||||
handle_sidebar_touch(s, touch_x, touch_y);
|
||||
handle_vision_touch(s, touch_x, touch_y);
|
||||
}
|
||||
|
||||
// Don't waste resources on drawing in case screen is off
|
||||
handle_display_state(s, &fb, touched == 1);
|
||||
if (!s->awake) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// up one notch every 5 m/s
|
||||
s->sound->setVolume(fmin(MAX_VOLUME, MIN_VOLUME + s->scene.car_state.getVEgo() / 5));
|
||||
|
||||
// set brightness
|
||||
float clipped_brightness = fmin(512, (s->scene.light_sensor*brightness_m) + brightness_b);
|
||||
smooth_brightness = fmin(255, clipped_brightness * 0.01 + smooth_brightness * 0.99);
|
||||
ui_set_brightness(s, (int)smooth_brightness);
|
||||
|
||||
update_offroad_layout_state(s, pm);
|
||||
|
||||
ui_draw(s);
|
||||
double u2 = millis_since_boot();
|
||||
if (!s->scene.driver_view && (u2-u1 > 66)) {
|
||||
// warn on sub 15fps
|
||||
LOGW("slow frame(%llu) time: %.2f", (s->sm)->frame, u2-u1);
|
||||
}
|
||||
fb.swap();
|
||||
}
|
||||
|
||||
handle_display_state(s, &fb, true);
|
||||
delete s->sm;
|
||||
delete pm;
|
||||
return 0;
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c6edce17d54bf9762133e71fdddb5eb112eb182bef5d49c668e478c988aaf572
|
||||
size 439744
|
||||
oid sha256:2bf424d78e157f284cd63f0f8cbd394fee929954fef069c27b09d55ef5ca5233
|
||||
size 603472
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c6edce17d54bf9762133e71fdddb5eb112eb182bef5d49c668e478c988aaf572
|
||||
size 439744
|
|
@ -5,6 +5,7 @@
|
|||
#include <QApplication>
|
||||
|
||||
#include "qt_window.hpp"
|
||||
#include "selfdrive/hardware/hw.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QApplication a(argc, argv);
|
||||
|
@ -21,7 +22,7 @@ int main(int argc, char *argv[]) {
|
|||
#ifdef __aarch64__
|
||||
btn->setText("Reboot");
|
||||
QObject::connect(btn, &QPushButton::released, [=]() {
|
||||
std::system("sudo reboot");
|
||||
Hardware::reboot();
|
||||
});
|
||||
#else
|
||||
btn->setText("Exit");
|
||||
|
@ -32,6 +33,7 @@ int main(int argc, char *argv[]) {
|
|||
window.setLayout(layout);
|
||||
window.setStyleSheet(R"(
|
||||
* {
|
||||
outline: none;
|
||||
color: white;
|
||||
background-color: black;
|
||||
font-size: 60px;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9ade107da94609e36256abf30fc45a6c8ad76804fb0f099f8d3d792e61bc118c
|
||||
size 217160
|
||||
oid sha256:cbd82920a8d9a995d3596406cefb59476c4352012b639515902f93835d659960
|
||||
size 302968
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9ade107da94609e36256abf30fc45a6c8ad76804fb0f099f8d3d792e61bc118c
|
||||
size 217160
|
|
@ -1,12 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ -f /EON ]; then
|
||||
export LD_LIBRARY_PATH="/system/lib64:$LD_LIBRARY_PATH"
|
||||
exec ./android/spinner/spinner "$1"
|
||||
else
|
||||
if [ -f /TICI ] && [ ! -f qt/spinner ]; then
|
||||
cp qt/spinner_aarch64 qt/spinner
|
||||
fi
|
||||
|
||||
exec ./qt/spinner "$1"
|
||||
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
|
||||
fi
|
||||
|
||||
export LD_LIBRARY_PATH="/system/lib64:$LD_LIBRARY_PATH"
|
||||
exec ./qt/spinner "$1"
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ -f /EON ]; then
|
||||
export LD_LIBRARY_PATH="/system/lib64:$LD_LIBRARY_PATH"
|
||||
exec ./android/text/text "$1"
|
||||
else
|
||||
if [ -f /TICI ] && [ ! -f qt/text ]; then
|
||||
cp qt/text_aarch64 qt/text
|
||||
fi
|
||||
|
||||
exec ./qt/text "$1"
|
||||
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
|
||||
fi
|
||||
|
||||
export LD_LIBRARY_PATH="/system/lib64:$LD_LIBRARY_PATH"
|
||||
exec ./qt/text "$1"
|
||||
|
|
Loading…
Reference in New Issue