move a bunch of stuff into userspace/root/

This commit is contained in:
Adeeb Shihadeh
2026-04-30 18:15:09 -07:00
parent 84da44b782
commit 5398248de5
97 changed files with 20 additions and 20 deletions
+39
View File
@@ -0,0 +1,39 @@
# Generated by iptables-save v1.8.4 on Thu May 26 16:34:33 2022
*security
:INPUT ACCEPT [232864:1793459837]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [205236:11113001]
COMMIT
# Completed on Thu May 26 16:34:33 2022
# Generated by iptables-save v1.8.4 on Thu May 26 16:34:33 2022
*raw
:PREROUTING ACCEPT [232873:1793461973]
:OUTPUT ACCEPT [205236:11113001]
COMMIT
# Completed on Thu May 26 16:34:33 2022
# Generated by iptables-save v1.8.4 on Thu May 26 16:34:33 2022
*nat
:PREROUTING ACCEPT [92:10264]
:INPUT ACCEPT [83:8128]
:OUTPUT ACCEPT [281:20487]
:POSTROUTING ACCEPT [281:20487]
COMMIT
# Completed on Thu May 26 16:34:33 2022
# Generated by iptables-save v1.8.4 on Thu May 26 16:34:33 2022
*mangle
:PREROUTING ACCEPT [232873:1793461973]
:INPUT ACCEPT [232864:1793459837]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [205236:11113001]
:POSTROUTING ACCEPT [205236:11113001]
COMMIT
# Completed on Thu May 26 16:34:33 2022
# Generated by iptables-save v1.8.4 on Thu May 26 16:34:33 2022
*filter
:INPUT ACCEPT [16:2193]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [108:15364]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i wwan0 -j DROP
COMMIT
# Completed on Thu May 26 16:34:33 2022
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
### GENERATED BY SALT ###
cat << 'EOF'
.~ssos+.
+8888888888i,
{888888888888o.
h8888888888888k
t888888888s888k
`t88888d/ h88k
``` h88l
,88k`
.d8h`
+d8h
_+d8h`
;y8h+`
|-`
EOF
+37
View File
@@ -0,0 +1,37 @@
#!/bin/sh
#
# 00-header - create the header of the MOTD
# Copyright (C) 2009-2010 Canonical Ltd.
#
# Authors: Dustin Kirkland <kirkland@canonical.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
[ -r /etc/lsb-release ] && . /etc/lsb-release
if [ -z "$DISTRIB_DESCRIPTION" ] && [ -x /usr/bin/lsb_release ]; then
# Fall back to using the very slow lsb_release utility
DISTRIB_DESCRIPTION=$(lsb_release -s -d)
fi
AGNOS_DESCRIPTION=$(< /VERSION)
# For CI builds e.g. "11-ade422a"
if [[ "$AGNOS_DESCRIPTION" == *-* ]]; then
AGNOS_DESCRIPTION="${AGNOS_DESCRIPTION%-*} (${AGNOS_DESCRIPTION#*-})"
fi
printf "Welcome to AGNOS v%s\n" "$AGNOS_DESCRIPTION"
printf "Based on %s (%s %s %s)\n" "$DISTRIB_DESCRIPTION" "$(uname -o)" "$(uname -r)" "$(uname -m)"
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
cat << 'EOF'
Here are some useful commands:
Enter the tmux session where the comma service runs
(note: tmux prefix key has been configured to backtick)
└── tmux a
Install Ubuntu packages
└── sudo apt update && sudo apt install <pkg>
Install Python packages
└── pip install <pkg>
When modifying AGNOS, keep in mind that the system partition isn't
particularly large. /data/ is the largest partition, and unlike the
rest of the partitions, it will persist across AGNOS updates.
Want a clean slate? Reflash AGNOS with https://flash.comma.ai.
EOF
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
printf "\n"
+10
View File
@@ -0,0 +1,10 @@
alias l='ls -lah'
alias gup='git pull --rebase'
alias gl='git pull'
alias gp='git push'
alias gcam='git commit -a -m'
alias gst='git status'
alias gco='git checkout'
alias gsu='git submodule update'
alias dump="/data/pythonpath/selfdrive/debug/dump.py"
alias op='/data/openpilot/tools/op.sh "$@"'
+9
View File
@@ -0,0 +1,9 @@
export EDITOR='vim'
export VIMINIT='source $MYVIMRC'
export MYVIMRC="~/.vimrc"
source $HOME/.profile
if [ -d "/data/openpilot" ] && [ "$(tmux display-message -p '#{session_name}')" == "comma" ] ; then
cd /data/openpilot
fi
@@ -0,0 +1,2 @@
[main]
unpackaged=true
@@ -0,0 +1,215 @@
#? Config file for btop v. 1.3.0
#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes.
#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes"
color_theme = "Default"
#* If the theme set background should be shown, set to False if you want terminal background transparency.
theme_background = True
#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false.
truecolor = True
#* Set to true to force tty mode regardless if a real tty has been detected or not.
#* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols.
force_tty = False
#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets.
#* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box.
#* Use whitespace " " as separator between different presets.
#* Example: "cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty"
presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty"
#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists.
#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift.
vim_keys = False
#* Rounded corners on boxes, is ignored if TTY mode is ON.
rounded_corners = True
#* Default symbols to use for graph creation, "braille", "block" or "tty".
#* "braille" offers the highest resolution but might not be included in all fonts.
#* "block" has half the resolution of braille but uses more common characters.
#* "tty" uses only 3 different symbols but will work with most fonts and should work in a real TTY.
#* Note that "tty" only has half the horizontal resolution of the other two, so will show a shorter historical view.
graph_symbol = "braille"
# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty".
graph_symbol_cpu = "default"
# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty".
graph_symbol_mem = "default"
# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty".
graph_symbol_net = "default"
# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty".
graph_symbol_proc = "default"
#* Manually set which boxes to show. Available values are "cpu mem net proc" and "gpu0" through "gpu5", separate values with whitespace.
shown_boxes = "cpu mem net proc"
#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs.
update_ms = 2000
#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct",
#* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly.
proc_sorting = "cpu lazy"
#* Reverse sorting order, True or False.
proc_reversed = False
#* Show processes as a tree.
proc_tree = False
#* Use the cpu graph colors in the process list.
proc_colors = True
#* Use a darkening gradient in the process list.
proc_gradient = True
#* If process cpu usage should be of the core it's running on or usage of the total available cpu power.
proc_per_core = True
#* Show process memory as bytes instead of percent.
proc_mem_bytes = True
#* Show cpu graph for each process.
proc_cpu_graphs = True
#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate)
proc_info_smaps = False
#* Show proc box on left side of screen instead of right.
proc_left = False
#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop).
proc_filter_kernel = False
#* In tree-view, always accumulate child process resources in the parent process.
proc_aggregate = False
#* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available.
#* Select from a list of detected attributes from the options menu.
cpu_graph_upper = "Auto"
#* Sets the CPU stat shown in lower half of the CPU graph, "total" is always available.
#* Select from a list of detected attributes from the options menu.
cpu_graph_lower = "Auto"
#* Toggles if the lower CPU graph should be inverted.
cpu_invert_lower = True
#* Set to True to completely disable the lower CPU graph.
cpu_single_graph = False
#* Show cpu box at bottom of screen instead of top.
cpu_bottom = False
#* Shows the system uptime in the CPU box.
show_uptime = True
#* Show cpu temperature.
check_temp = True
#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors.
cpu_sensor = "Auto"
#* Show temperatures for cpu cores also if check_temp is True and sensors has been found.
show_coretemp = True
#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core.
#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine.
#* Format "x:y" x=core with wrong temp, y=core with correct temp, use space as separator between multiple entries.
#* Example: "4:0 5:1 6:3"
cpu_core_map = ""
#* Which temperature scale to use, available values: "celsius", "fahrenheit", "kelvin" and "rankine".
temp_scale = "celsius"
#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024.
base_10_sizes = False
#* Show CPU frequency.
show_cpu_freq = True
#* Draw a clock at top of screen, formatting according to strftime, empty string to disable.
#* Special formatting: /host = hostname | /user = username | /uptime = system uptime
clock_format = "%X"
#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort.
background_update = False
#* Custom cpu model name, empty string to disable.
custom_cpu_name = ""
#* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with whitespace " ".
#* Begin line with "exclude=" to change to exclude filter, otherwise defaults to "most include" filter. Example: disks_filter="exclude=/boot /home/user".
disks_filter = ""
#* Show graphs instead of meters for memory values.
mem_graphs = True
#* Show mem box below net box instead of above.
mem_below_net = False
#* Count ZFS ARC in cached and available memory.
zfs_arc_cached = True
#* If swap memory should be shown in memory box.
show_swap = True
#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk.
swap_disk = True
#* If mem box should be split to also show disks info.
show_disks = True
#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar.
only_physical = True
#* Read disks list from /etc/fstab. This also disables only_physical.
use_fstab = True
#* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool)
zfs_hide_datasets = False
#* Set to true to show available disk space for privileged users.
disk_free_priv = False
#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view.
show_io_stat = True
#* Toggles io mode for disks, showing big graphs for disk read/write speeds.
io_mode = False
#* Set to True to show combined read/write io graphs in io mode.
io_graph_combined = False
#* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ".
#* Example: "/mnt/media:100 /:20 /boot:1".
io_graph_speeds = ""
#* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False.
net_download = 100
net_upload = 100
#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest.
net_auto = True
#* Sync the auto scaling for download and upload to whichever currently has the highest scale.
net_sync = True
#* Starts with the Network Interface specified here.
net_iface = ""
#* Show battery stats in top right if battery is present.
show_battery = True
#* Which battery to use if multiple are present. "Auto" for auto detection.
selected_battery = "Auto"
#* Set loglevel for "~/.config/btop/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG".
#* The level set includes all lower levels, i.e. "DEBUG" will show all logging info.
log_level = "WARNING"
@@ -0,0 +1,26 @@
# Beware! This file is rewritten by htop when settings are changed in the interface.
# The parser is also very primitive, and not human-friendly.
fields=0 48 17 18 38 39 40 2 37 46 47 49 1
sort_key=46
sort_direction=1
hide_threads=0
hide_kernel_threads=0
hide_userland_threads=0
shadow_other_users=0
show_thread_names=1
show_program_path=1
highlight_base_name=0
highlight_megabytes=1
highlight_threads=1
tree_view=1
header_margin=1
detailed_cpu_time=0
cpu_count_from_zero=1
update_process_names=0
account_guest_in_cpu_meter=0
color_scheme=0
delay=15
left_meters=LeftCPUs Memory Swap
left_meter_modes=1 1 1
right_meters=RightCPUs Tasks LoadAverage Uptime
right_meter_modes=1 2 2 2
+1
View File
@@ -0,0 +1 @@
handle SIGUSR2 nostop noprint
+14
View File
@@ -0,0 +1,14 @@
[user]
email = device@comma.ai
name = Comma Device
[push]
default = simple
[pull]
rebase = false
[url "git@github.com:"]
pushInsteadOf = "https://github.com/"
[filter "lfs"]
clean = git-lfs clean -- %f
smudge = git-lfs smudge -- %f
required = true
process = git-lfs filter-process
+1
View File
@@ -0,0 +1 @@
.ssh
+22
View File
@@ -0,0 +1,22 @@
unbind C-b
set -g prefix `
bind-key ` last-window
bind-key e send-prefix
set -g status-position bottom
set -g status-style bg=colour234,fg=colour137,dim
set -g status-left ''
set -g status-left-length 20
set -g history-limit 7200
set -g status-right '#[fg=colour230,bold]#(cat /data/params/d/DongleId | cut -c 1-16) #[fg=colour233,bg=colour239,bold] #(echo "scale=1; $(cat /sys/devices/virtual/thermal/thermal_zone11/temp)/1000" | bc)°C #[fg=colour233,bg=colour241,bold] %d/%m #[fg=colour233,bg=colour245,bold] %H:%M:%S '
set -g status-right-length 70
setw -g window-status-current-style fg=colour81,bg=colour238,bold
setw -g window-status-current-format ' #I#[fg=colour250]:#[fg=colour255]#W#[fg=colour50]#F '
setw -g window-status-style fg=colour138,bg=colour235
setw -g window-status-format ' #I#[fg=colour237]:#[fg=colour250]#W#[fg=colour244]#F '
setw -g window-status-bell-style fg=colour255,bg=colour1,bold
set -g mouse off
+21
View File
@@ -0,0 +1,21 @@
syntax on
set tabstop=2
set shiftwidth=2
set expandtab
set ai
set number
set hlsearch
set ruler
set mouse=
set viminfo=""
set noswapfile
highlight Comment ctermfg=green
highlight ExtraWhitespace ctermbg=red guibg=red
match ExtraWhitespace /\s\+$/
" syntax highlighting for scons files
au BufRead,BufNewFile SConstruct set filetype=python
au BufRead,BufNewFile SConscript set filetype=python
" auto resize splits
autocmd VimResized * wincmd =
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
*.ko
BIN
View File
Binary file not shown.
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash -e
sudo mount -o rw,remount /
sudo resize2fs $(findmnt -n -o SOURCE /) &>/dev/null || sudo resize2fs $(findmnt -n -o SOURCE /)
sudo mount -o remount,size=1500M /var
sudo cp -r /usr/default/var/lib/dpkg /var/lib/
sudo sed -i '/bionic/s/^/#/' /etc/apt/sources.list
sudo sed -i '/hirsute/s/^/#/' /etc/apt/sources.list
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
sudo mount -o ro,remount / || true
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
# Read the raw device model
RAW_MODEL=$(tr -d '\0' < /sys/firmware/devicetree/base/model)
# Extract the device model (e.g., tici, tizi, mici)
MODEL=$(echo "$RAW_MODEL" | sed 's/comma //g' | awk '{print $1}')
[ -z "$MODEL" ] && MODEL="unknown"
HOSTNAME=$(hostname)
SERVICE_NAME="comma SSH - $MODEL - [$HOSTNAME]"
ALIAS_FILE="/data/params/d_tmp/ApiCache_Device"
ALIAS=$(jq -e -r '.alias // empty' "$ALIAS_FILE" 2>/dev/null | grep -E '\S' || echo "$RAW_MODEL")
# Publish avahi service
exec avahi-publish -s "$SERVICE_NAME" _ssh._tcp 22 "vendor=comma" "device=comma" "model=$MODEL" "alias=$ALIAS"
Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
import time
# limit display brightness with display uptime to prevent burn in
BL_OFF = 4
BL_POWER_PATH = "/sys/class/backlight/panel0-backlight/bl_power"
BRIGHTNESS_PATH = "/sys/class/backlight/panel0-backlight/brightness"
MAX_BRIGHTNESS_PATH= "/sys/devices/platform/soc/soc:qcom,dsi-display@0/max_brightness_percent"
MAX_PERCENT = 90
MIN_PERCENT = 30
HOURLY_PERC_DECREASE = 5
def read(path: str) -> int:
try:
with open(path) as f:
return int(f.read())
except Exception:
return 0
if __name__ == "__main__":
last_perc = None
last_off_ts = time.monotonic()
while True:
try:
# sample brightness and backlight power
bl_power = read(BL_POWER_PATH)
brightness = read(BRIGHTNESS_PATH)
if bl_power == BL_OFF or brightness == 0:
last_off_ts = time.monotonic()
# calculate new max
uptime_hours = (time.monotonic() - last_off_ts) / (60*60)
clipped_perc = MAX_PERCENT - (HOURLY_PERC_DECREASE*uptime_hours)
clipped_perc = int(max(min(clipped_perc, MAX_PERCENT), MIN_PERCENT))
if clipped_perc != last_perc:
with open(MAX_BRIGHTNESS_PATH, 'w') as f:
f.write(f"{int(clipped_perc)}\n")
last_perc = clipped_perc
except Exception:
pass
time.sleep(5)
+109
View File
@@ -0,0 +1,109 @@
#/usr/bin/env bash
source /etc/profile
SETUP="/usr/comma/setup"
RESET="/usr/comma/reset"
CONTINUE="/data/continue.sh"
INSTALLER="/tmp/installer"
RESET_TRIGGER="/data/__system_reset__"
# blip power to ~10W to see if the PSU is stable
sudo timeout --kill-after=2 5 /home/comma/power_burn_max
# use max freq to boot up quickly, then limit
echo 1689600 | sudo tee /sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq
echo 1689600 | sudo tee /sys/devices/system/cpu/cpufreq/policy4/scaling_max_freq
echo "waiting for magic"
for i in {1..200}; do
if systemctl is-active --quiet magic && [ -S /tmp/drmfd.sock ]; then
break
fi
sleep 0.1
done
if systemctl is-active --quiet magic && [ -S /tmp/drmfd.sock ]; then
echo "magic ready after ${SECONDS}s"
else
echo "timed out waiting for magic, ${SECONDS}s"
fi
sudo chown comma: /data
sudo chown comma: /data/media
handle_setup_keys () {
# install default SSH key while still in setup
if [[ ! -e /data/params/d/GithubSshKeys && ! -e /data/continue.sh ]]; then
if [ ! -e /data/params/d ]; then
mkdir -p /data/params/d_tmp
ln -s /data/params/d_tmp /data/params/d
fi
echo -n 1 > /data/params/d/AdbEnabled
echo -n 1 > /data/params/d/SshEnabled
cp /usr/comma/setup_keys /data/params/d/GithubSshKeys
elif [[ -e /data/params/d/GithubSshKeys && -e /data/continue.sh ]]; then
if cmp -s /data/params/d/GithubSshKeys /usr/comma/setup_keys; then
rm /data/params/d/AdbEnabled
rm /data/params/d/SshEnabled
rm /data/params/d/GithubSshKeys
fi
fi
}
# factory reset handling
if [ ! -f /tmp/booted ]; then
touch /tmp/booted
if [ -f "$RESET_TRIGGER" ]; then
echo "launching system reset, reset trigger present"
rm -f $RESET_TRIGGER
$RESET
elif (( "$(cat /sys/class/input/input2/device/touch_count)" > 4 )); then
echo "launching system reset, got taps"
$RESET --tap-reset
elif ! mountpoint -q /data; then
echo "userdata not mounted. loading system reset"
$RESET --recover
fi
fi
# setup /data/tmp
rm -rf /data/tmp
mkdir -p /data/tmp
# symlink vscode to userdata
mkdir -p /data/tmp/vscode-server
ln -s /data/tmp/vscode-server ~/.vscode-server
ln -s /data/tmp/vscode-server ~/.cursor-server
ln -s /data/tmp/vscode-server ~/.windsurf-server
while true; do
pkill -f "$SETUP"
handle_setup_keys
if [ -f $CONTINUE ]; then
exec "$CONTINUE"
fi
sudo abctl --set_success
# cleanup installers from previous runs
rm -f $INSTALLER
pkill -f $INSTALLER
# run setup and wait for installer
$SETUP &
echo "waiting for installer"
while [ ! -f $INSTALLER ]; do
sleep 0.1
done
# run installer and wait for continue.sh
chmod +x $INSTALLER
$INSTALLER &
echo "running installer"
while [ ! -f $CONTINUE ] && ps -p $! > /dev/null; do
sleep 0.1
done
done
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env python3
import os
import shutil
from pathlib import Path
ROOT = Path("/cache/debug/")
if __name__ == "__main__":
os.makedirs(ROOT, exist_ok=True)
boots = sorted(list(ROOT.iterdir()), key=lambda p: int(p.stem, 16), reverse=True)
# limit to 100 boots
for d in boots[100:]:
print("cleaning up", d)
shutil.rmtree(d)
# make a directory for this boot
n = 0
if len(boots):
n = int(boots[0].stem, 16) + 1
boot_dir = ROOT / f"{n:08x}"
boot_dir.mkdir(parents=True)
# log some stuff
pstore = boot_dir / "pstore"
pstore.mkdir()
os.system(f"cp /sys/fs/pstore/* {pstore} 2>/dev/null")
os.system(f"uname -a > {boot_dir / 'uname'}")
shutil.copyfile("/VERSION", boot_dir / "VERSION")
+41
View File
@@ -0,0 +1,41 @@
#!/bin/bash
# Ensure the symlinks in the read only rootfs are
# backed by real files and directories on userdata.
# tmpfiles
systemd-tmpfiles --create /usr/comma/tmpfiles.conf
# /var/log/ tmpfs
mkdir -p /var/log/
chown root:syslog /var/log
mount -t tmpfs -o rw,nosuid,nodev,size=128M,mode=755 tmpfs /var/log
# setup /home
mkdir -p /rwtmp/home_work
mkdir -p /rwtmp/home_upper
chmod 755 /rwtmp/*
mount -t overlay overlay -o lowerdir=/usr/default/home,upperdir=/rwtmp/home_upper,workdir=/rwtmp/home_work /home
# /etc
mkdir -p /data/etc
touch /data/etc/timezone
touch /data/etc/localtime
mkdir -p /data/etc/netplan
mkdir -p /data/etc/NetworkManager/system-connections
# /cache
chown -R comma:comma /cache/
# /data/ssh
mkdir -p /data/ssh
chown comma: /data/ssh
# /data/tmp - clear out
rm -rf /data/tmp/
mkdir -p /data/tmp/
# /data/persist
if [[ ! -d /data/persist ]]; then
sudo cp -r /system/persist /data
fi
+43
View File
@@ -0,0 +1,43 @@
#!/bin/bash
function gpio {
echo "out" > /sys/class/gpio/gpio$1/direction
echo $2 > /sys/class/gpio/gpio$1/value
}
pins=(
# 27 # SW_3V3_EN
# 25 # SW_5V_EN
30 # HUB_RST_N
49 # SOM_ST_IO
134 # ST_BOOT0
41 # PANDA_1V8_EN_N
50 # LTE_RST_N
116 # LTE_PWRKEY
124 # ST_RST_N
34 # GPS_PWR_EN
33 # GPS_SAFEBOOT_N
32 # GPS_RST_N
52 # LTE_BOOT
1264 # POWER ALERT
)
for p in ${pins[@]}; do
echo $p
# this is SSD_3v3 EN on tici
if [ "$p" -eq 41 ] && grep -q "comma tici" /sys/firmware/devicetree/base/model; then
echo "Skipping $p"
continue
fi
echo $p > /sys/class/gpio/export
until [ -d /sys/class/gpio/gpio$p ]
do
sleep .05
done
done
HUB_RST_N=30
gpio $HUB_RST_N 1
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
# don't restart whole SoC on subsystem crash
for i in {0..7}; do
echo "related" | sudo tee /sys/bus/msm_subsys/devices/subsys${i}/restart_level
done
# raise scaling_max so policy=performance can reach the BOOST top step
echo 2649600 | sudo tee /sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq
echo 2649600 | sudo tee /sys/devices/system/cpu/cpufreq/policy4/scaling_max_freq
# boot wifi
echo 1 | sudo tee /sys/kernel/boot_wlan/boot_wlan
+3
View File
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:85f6d9e54286a3842920d6967b187478b4e43d6171c331d72d3fb3102106e101
size 1401224
+106
View File
@@ -0,0 +1,106 @@
#!/bin/bash
function gpio {
echo "out" > /sys/class/gpio/gpio$1/direction
echo $2 > /sys/class/gpio/gpio$1/value
}
HUB_RST_N=30
LTE_RST_N=50
LTE_BOOT=52
LTE_PWRKEY=116
function is_modem_up {
if lsusb -d "0x05c6:" >/dev/null 2>&1 || lsusb -d "0x2c7c:" >/dev/null 2>&1; then
return 0
else
return 1
fi
}
function reset {
echo " Resetting..."
gpio $LTE_RST_N 1
sleep 1
gpio $LTE_RST_N 0
}
function power_button {
echo " Pulsing power button..."
gpio $LTE_PWRKEY 1
sleep 1
gpio $LTE_PWRKEY 0
}
function is_online {
echo " Waiting until the modem comes online..."
for i in {0..30}; do
if is_modem_up; then
echo " Modem is online!"
return 0
fi
echo " Waiting..."
sleep 1
done
return 1
}
function is_offline {
echo " Waiting until the modem goes offline..."
for i in {0..30}; do
if ! is_modem_up; then
echo " Modem is offline!"
return 0
fi
echo " Waiting..."
sleep 1
done
return 1
}
# Boot into the regular mode
gpio $LTE_BOOT 0
case "$1" in
start)
echo "Starting LTE..."
reset
power_button
until is_online; do
reset
power_button
done
;;
stop)
echo "Stopping LTE..."
if is_online; then
power_button
fi
;;
stop_blocking)
echo "Stopping LTE..."
if is_online; then
power_button
fi
until is_offline; do
power_button
done
;;
*)
echo "Specify either start or stop as first argument!"
exit 1
;;
esac
+138
View File
@@ -0,0 +1,138 @@
#!/usr/bin/env python3
import os, socket, struct, subprocess, threading, time
from array import array
import pyray as rl
UPDATER_PATH = "/usr/comma/updater"
WESTON_RUNTIME_DIR = "/var/tmp/weston"
WESTON_SOCK_PATH = os.path.join(WESTON_RUNTIME_DIR, "wayland-0")
SOCK_PATH = "/tmp/drmfd.sock"
DRM_DEVICE = "/dev/dri/card0"
BACKGROUND = "/usr/comma/bg.jpg"
# This is needed to keep the old updater working. Updater used to be stored in
# openpilot directly instead of in AGNOS. This will intercept the old updater
# trying to use a Weston socket and start our own.
def updater_weston():
os.makedirs(WESTON_RUNTIME_DIR, exist_ok=True)
os.chmod(WESTON_RUNTIME_DIR, 0o700)
try:
os.unlink(WESTON_SOCK_PATH)
except FileNotFoundError:
pass
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.bind(WESTON_SOCK_PATH)
server.listen(1)
while True:
try:
client, _ = server.accept()
creds = client.getsockopt(socket.SOL_SOCKET, socket.SO_PEERCRED, struct.calcsize("3i"))
pid, _, _ = struct.unpack("3i", creds)
with open(f"/proc/{pid}/comm", "r") as f:
comm = f.read().strip()
if comm == "updater":
with open(f"/proc/{pid}/cmdline", "rb") as f:
updater, manifest = [p.decode("utf-8") for p in f.read().split(b"\0") if p != b""][1:]
env = os.environ.copy()
env.pop("DRM_FD", None)
subprocess.run([UPDATER_PATH, updater, manifest], env=env)
except Exception:
pass
finally:
try:
client.shutdown(socket.SHUT_RDWR)
client.close()
except Exception:
pass
def power_screen():
try:
with open("/sys/class/backlight/panel0-backlight/bl_power", "w") as f:
f.write("0")
with open("/sys/class/backlight/panel0-backlight/max_brightness") as f:
max_brightness = int((int(f.read().strip()) / 100) * 65)
with open("/sys/class/backlight/panel0-backlight/brightness", "w") as f:
f.write(str(max_brightness))
except Exception:
pass
def show_background(tex, pos):
rl.begin_drawing()
rl.draw_texture(tex, int(pos.x), int(pos.y), rl.WHITE)
rl.end_drawing()
power_screen()
def handle_client(client, drm_master):
try:
drm_master_dup = os.dup(drm_master)
client.sendmsg([b"x"], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array("i", [drm_master_dup]).tobytes())])
client.recv(1)
except Exception:
pass
finally:
try:
os.close(drm_master_dup)
client.close()
except Exception:
pass
def main():
threading.Thread(target=updater_weston, daemon=True).start()
while True:
try:
drm_master = os.open(DRM_DEVICE, os.O_RDWR | os.O_CLOEXEC)
break
except Exception as e:
print(e)
time.sleep(0.1)
os.environ['DRM_FD'] = str(drm_master)
rl.init_window(0, 0, "not weston")
img = rl.load_image(BACKGROUND)
rl.image_resize(img, rl.get_screen_width(), rl.get_screen_width()//2)
tex = rl.load_texture_from_image(img)
rl.set_texture_filter(tex, rl.TextureFilter.TEXTURE_FILTER_BILINEAR)
pos = rl.Vector2((rl.get_screen_width() - tex.width)/2.0, (rl.get_screen_height() - tex.height)/2.0)
rl.unload_image(img)
show_background(tex, pos)
try:
os.unlink(SOCK_PATH)
except FileNotFoundError:
pass
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.bind(SOCK_PATH)
server.settimeout(0.1)
server.listen(1)
clients = set()
need_background = False
while True:
dead = [t for t in list(clients) if not t.is_alive()]
for t in dead:
t.join()
clients.discard(t)
if not clients and need_background:
need_background = False
show_background(tex, pos)
try:
client, _ = server.accept()
except Exception:
continue
need_background = True
t = threading.Thread(target=handle_client, args=(client, drm_master), daemon=True)
t.start()
clients.add(t)
if __name__ == "__main__":
main()
BIN
View File
Binary file not shown.
+125
View File
@@ -0,0 +1,125 @@
#!/usr/bin/env python
import os
import time
import smbus2
import select
import datetime
import subprocess
ALERT_VOLTAGE_THRESHOLD_mV = 4000
POWER_ALERT_GPIO_PIN = 1264
INA231_BUS = 0
INA231_ADDRESS = 0x40
INA231_MASK_REG = 0x06
INA231_LIMIT_REG = 0x07
INA231_MASK_CONFIG = (1 << 12) # Bus undervoltage, not latching
INA231_BUS_VOLTAGE_LSB_mV = 1.25
VOLTAGE_FILE = "/sys/class/hwmon/hwmon1/in1_input"
PARAM_FILE = "/data/params/d/LastPowerDropDetected"
alert_pin_base = f"/sys/class/gpio/gpio{POWER_ALERT_GPIO_PIN}/"
def set_screen_power(on):
with open("/sys/class/backlight/panel0-backlight/bl_power", "w") as f:
f.write("0\n" if on else "4\n")
def get_screen_power():
with open("/sys/class/backlight/panel0-backlight/bl_power", "r") as f:
return f.read(1) == "0"
def swap_word_bytes(val):
return ((val & 0xFF) << 8) | ((val & 0xFF00) >> 8)
def write_once(path, value):
with open(path, 'w') as f:
f.write(value)
def init_alert_pin():
write_once(os.path.join(alert_pin_base, 'direction'), 'in')
write_once(os.path.join(alert_pin_base, 'edge'), 'falling')
def init_voltage_alert():
with smbus2.SMBus(INA231_BUS) as bus:
bus.write_word_data(INA231_ADDRESS, INA231_MASK_REG, swap_word_bytes(INA231_MASK_CONFIG), force=True)
bus.write_word_data(INA231_ADDRESS, INA231_LIMIT_REG, swap_word_bytes(int(ALERT_VOLTAGE_THRESHOLD_mV / INA231_BUS_VOLTAGE_LSB_mV)), force=True)
def read_voltage_mV():
with open(VOLTAGE_FILE, "r") as f:
return int(f.read().strip())
def read_current_mA():
with open("/sys/class/hwmon/hwmon1/curr1_input", "r") as f:
return int(f.read().strip())
def update_param(stage, v_initial, i_initial, v_final, i_final):
try:
os.umask(0)
with open(os.open(PARAM_FILE, os.O_CREAT | os.O_WRONLY, 0o777), 'a') as f:
f.write(f"{stage} {datetime.datetime.now()}, ({v_initial=} mV, {i_initial=} mA) -> ({v_final=} mV, {i_final=} mA)\n")
f.flush()
os.fdatasync(f.fileno())
os.fsync(f.fileno())
except Exception:
print("Failed to update LastControlledShutdown param")
def printk(msg):
with open('/dev/kmsg', 'w') as kmsg:
kmsg.write(f"<3>[power drop monitor] {msg}\n")
print(msg)
def perform_controlled_shutdown():
printk("Power alert received!")
prev_screen_power = get_screen_power()
set_screen_power(False)
v_initial = read_voltage_mV()
i_initial = read_current_mA()
update_param("PREP", v_initial, i_initial, None, None)
# Wait 100ms before checking voltage level again
t = time.monotonic()
while time.monotonic() - t < 0.1:
time.sleep(0.01)
v_now = read_voltage_mV()
i_now = read_current_mA()
if v_now > ALERT_VOLTAGE_THRESHOLD_mV:
printk("Voltage restored. Not shutting down!")
update_param("ABORT", v_initial, i_initial, v_now, i_now)
set_screen_power(prev_screen_power)
return
update_param("SHUTDOWN", v_initial, i_initial, v_now, i_now)
# Kill services that draw a lot of power
printk("Killing services")
subprocess.call(["/usr/bin/systemctl", "kill", "--signal=9", "comma"])
set_screen_power(False)
printk("Halt")
subprocess.call(["/usr/sbin/halt", "-f"])
if __name__ == '__main__':
init_alert_pin()
init_voltage_alert()
# Setup interrupt
f = open(os.path.join(alert_pin_base, 'value'), 'r')
po = select.poll()
po.register(f, select.POLLPRI)
# Interrupt loop
f.read()
while True:
try:
events = po.poll(60000)
if events:
f.seek(0)
state_last = f.read().strip()
if int(state_last) == 0:
perform_controlled_shutdown()
except Exception:
pass
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env python3
import os
import time
import fcntl
import struct
import threading
import subprocess
from datetime import datetime, timedelta
FN = "/var/tmp/power_watchdog"
PARAM_FILE = "/data/params/d/LastAgnosPowerMonitorShutdown"
THRESHOLD = timedelta(hours=1.0)
timestamps = {}
def read(path: str, num: bool = False):
try:
with open(path) as f:
if num:
return float(f.read())
return f.read()
except Exception:
return 0 if num else ""
def check_touches():
global timestamps
event_format = "llHHi"
event_size = struct.calcsize(event_format)
with open("/dev/input/by-path/platform-894000.i2c-event", "rb") as event_file:
fcntl.fcntl(event_file, fcntl.F_SETFL, os.O_NONBLOCK)
while True:
while (event := event_file.read(event_size)):
(sec, usec, etype, code, value) = struct.unpack(event_format, event)
if etype != 0 or code != 0 or value != 0:
timestamps['touch'] = time.monotonic()
time.sleep(60)
def ssh_active():
p = subprocess.run("ss | grep ssh", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return p.returncode == 0
def write_param():
try:
os.umask(0)
with open(os.open(PARAM_FILE, os.O_CREAT | os.O_WRONLY, 0o777), 'a') as f:
f.write(f"SHUTDOWN datetime={datetime.now()}, time.monotonic={time.monotonic()}, {timestamps=}\n")
f.flush()
os.fdatasync(f.fileno())
os.fsync(f.fileno())
except Exception as e:
print(f"Failed to write param: {e}")
if __name__ == "__main__":
# we limit worst-case power usage when openpilot isn't managing it,
# e.g. while building or during setup.
threading.Thread(target=check_touches, daemon=True).start()
timestamps['startup'] = time.monotonic()
while True:
timestamps['watchdog'] = read(FN, True)
if ssh_active():
timestamps['ssh'] = time.monotonic()
if read("/data/params/d/IsEngaged").startswith("1"):
timestamps['engaged'] = time.monotonic()
# store a max such that we can't go backwards
timestamps['max'] = max(timestamps.values())
# time to shutoff?
dt = timedelta(seconds=time.monotonic() - max(timestamps.values()))
if dt > THRESHOLD:
write_param()
os.system("sudo poweroff")
print((THRESHOLD - dt), "until shutdown", f"/ {timestamps=}")
time.sleep(60)
+3
View File
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b22bee10b5c17be9a64affd0d3474d6b0e7e4fcca7d14c083ecd6f3fa8b2975e
size 24709201
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
import os
import struct
GAMMA_CURVES_FILE = "/persist/comma/dwo_gamma_curves"
COMMAND_FILE = "/sys/kernel/debug/dsi_dwo_video_display/mipi_command"
GAMMA_ADDR = [
[(0x00, 0x01), (0x02, 0x03), (0x04, 0x05), (0x06, 0x07), (0x08, 0x09), (0x0A, 0x0B), (0x0C, 0x0D), (0x0E, 0x0F), (0x10, 0x11), (0x12, 0x13), (0x14, 0x15), (0x16, 0x17), (0x18, 0x19), (0x1A, 0x1B), (0x1C, 0x1D), (0x1E, 0x1F), (0x20, 0x21), (0x22, 0x23), (0x24, 0x25), (0x26, 0x27), (0x28, 0x29), (0x2A, 0x2B), (0x2D, 0x2F), (0x30, 0x31), (0x32, 0x33)],
[(0x34, 0x35), (0x36, 0x37), (0x38, 0x39), (0x3A, 0x3B), (0x3D, 0x3F), (0x40, 0x41), (0x42, 0x43), (0x44, 0x45), (0x46, 0x47), (0x48, 0x49), (0x4A, 0x4B), (0x4C, 0x4D), (0x4E, 0x4F), (0x50, 0x51), (0x52, 0x53), (0x54, 0x55), (0x56, 0x58), (0x59, 0x5A), (0x5B, 0x5C), (0x5D, 0x5E), (0x5F, 0x60), (0x61, 0x62), (0x63, 0x64), (0x65, 0x66), (0x67, 0x68)],
[(0x69, 0x6A), (0x6B, 0x6C), (0x6D, 0x6E), (0x6F, 0x70), (0x71, 0x72), (0x73, 0x74), (0x75, 0x76), (0x77, 0x78), (0x79, 0x7A), (0x7B, 0x7C), (0x7D, 0x7E), (0x7F, 0x80), (0x81, 0x82), (0x83, 0x84), (0x85, 0x86), (0x87, 0x88), (0x89, 0x8A), (0x8B, 0x8C), (0x8D, 0x8E), (0x8F, 0x90), (0x91, 0x92), (0x93, 0x94), (0x95, 0x96), (0x97, 0x98), (0x99, 0x9A)],
]
def command_mode(mode):
return f"39 01 00 00 0A 00 02 FE {((0b1010 << 4) | mode):02X}"
def pack_command(command_str):
command_buf = bytes(map(lambda x: int(x, base=16), command_str.strip().split()))
return struct.pack(f"i{len(command_buf)}s", len(command_buf), command_buf)
def set_gamma(gamma):
cmds = [command_mode(2)]
for color_idx in range(3):
for i, val in reversed(list(enumerate(gamma[color_idx]))):
msb, lsb = GAMMA_ADDR[color_idx][i]
cmds.append(f"39 0F 00 00 0A 00 02 {msb:02X} {(val >> 8) & 0xFF:02X}")
cmds.append(f"39 {'01' if i % 10 == 0 else '0F'} 00 00 0A 00 02 {lsb:02X} {val & 0xFF:02X}")
cmds.append(command_mode(0))
data = b"".join(pack_command(c) for c in cmds)
with open(COMMAND_FILE, "wb") as f:
f.write(data)
print("Successfully setup screen calibration")
if __name__ == "__main__":
if not os.path.exists(GAMMA_CURVES_FILE):
print("No gamma curves found")
exit(0)
assert os.path.exists(COMMAND_FILE), "MIPI command interface not found"
with open(GAMMA_CURVES_FILE, "r") as f:
gamma = [[int(x, 16) for x in l.strip().split()] for l in f]
set_gamma(gamma)
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
set -e
SERIAL="$(cat /proc/cmdline | sed -e 's/^.*androidboot.serialno=//' -e 's/ .*$//')"
echo "serial: '$SERIAL'"
sysctl kernel.hostname="comma-$SERIAL"
+72
View File
@@ -0,0 +1,72 @@
#!/bin/bash
setup() {
# Check if /config is already mounted
if ! mountpoint -q /config; then
sudo mount -t configfs none /config
else
echo "/config is already mounted."
fi
# Create USB gadget directory structure
sudo mkdir -p /config/usb_gadget/g1
cd /config/usb_gadget/g1
sudo mkdir -p strings/0x409
sudo mkdir -p configs/c.1/strings/0x409
sudo mkdir -p functions/ncm.0
# Set Vendor and Product ID
echo 0x04D8 | sudo tee idVendor
echo 0x1234 | sudo tee idProduct
# Set strings
echo "$(cat /proc/cmdline | sed -e 's/^.*androidboot.serialno=//' -e 's/ .*$//')" | sudo tee strings/0x409/serialnumber
echo "comma.ai" | sudo tee strings/0x409/manufacturer
echo "Linux USB Gadget" | sudo tee strings/0x409/product
echo 250 | sudo tee configs/c.1/MaxPower
# Create ADB function
sudo mkdir -p functions/ffs.adb
sudo mkdir -p /dev/usb-ffs/adb
if ! mountpoint -q /dev/usb-ffs/adb; then
sudo mount -t functionfs adb /dev/usb-ffs/adb
else
echo "/dev/usb-ffs/adb is already mounted"
fi
# Link both functions to configuration
echo "NCM+ADB" | sudo tee configs/c.1/strings/0x409/configuration
sudo rm -f configs/c.1/ncm.0
sudo rm -f configs/c.1/ffs.adb
sudo ln -s functions/ncm.0 configs/c.1/
sudo ln -s functions/ffs.adb configs/c.1/
}
start() {
setprop service.adb.tcp.port -1
cd /config/usb_gadget/g1
echo "a600000.dwc3" | sudo tee UDC
}
stop() {
if [ -d "/config/usb_gadget/g1" ]; then
cd /config/usb_gadget/g1
echo "" | sudo tee UDC
fi
}
ADB_PARAM="/data/params/d/AdbEnabled"
if [ -f "$ADB_PARAM" ] && [ "$(< $ADB_PARAM)" == "1" ]; then
echo "Enabling ADB"
setup
systemctl start adbd
sleep 1 # adbd does some setup before we can enable the gadget
start
else
echo "Disabling ADB"
systemctl stop adbd
stop
fi
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
SSH_PARAM="/data/params/d/SshEnabled"
if [ -f "$SSH_PARAM" ] && [ "$(< $SSH_PARAM)" == "1" ]; then
echo "Enabling SSH"
systemctl start ssh
else
echo "Disabling SSH"
systemctl stop ssh
fi
+3
View File
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b3efec8b3974e6064c6ddd9100527fcb475a1fcf148550390c77ec97a2bf37ec
size 24709201
+1
View File
@@ -0,0 +1 @@
from="127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+iXXq30Tq+J5NKat3KWHCzcmwZ55nGh6WggAqECa5CasBlM9VeROpVu3beA+5h0MibRgbD4DMtVXBt6gEvZ8nd04E7eLA9LTZyFDZ7SkSOVj4oXOQsT0GnJmKrASW5KslTWqVzTfo2XCtZ+004ikLxmyFeBO8NOcErW1pa8gFdQDToH9FrA7kgysic/XVESTOoe7XlzRoe/eZacEQ+jtnmFd21A4aEADkk00Ahjr0uKaJiLUAPatxs2icIXWpgYtfqqtaKF23wSt61OTu6cAwXbOWr3m+IUSRUO0IRzEIQS3z1jfd1svgzSgSSwZ1Lhj4AoKxIEAIc8qJrO4uymCJ public
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/bash
PIP_PATH=/usr/local/venv/bin/pip
export TMPDIR=/tmp/pip-tmp
# setup large tmp for install
mkdir -p $TMPDIR
sudo mount -o remount,size=2G /tmp
sudo mount -o rw,remount /
sudo resize2fs $(findmnt -n -o SOURCE /) &>/dev/null || sudo resize2fs $(findmnt -n -o SOURCE /)
# run command
sudo TMPDIR=$TMPDIR PIP_NO_CACHE_DIR=1 $PIP_PATH "$@"
# cleanup
sudo mount -o ro,remount /
sudo rm -rf $TMPDIR
sudo mount -o remount /tmp
+1
View File
@@ -0,0 +1 @@
pip
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/bash
UV_PATH=/usr/bin/uv
export TMPDIR=/tmp/uv-tmp
# setup large tmp for install
mkdir -p $TMPDIR
sudo mount -o remount,size=2G /tmp
sudo mount -o rw,remount /
sudo resize2fs $(findmnt -n -o SOURCE /) &>/dev/null || sudo resize2fs $(findmnt -n -o SOURCE /)
# run command
sudo -E TMPDIR=$TMPDIR UV_NO_CACHE=1 $UV_PATH "$@"
# cleanup
sudo mount -o ro,remount /
sudo rm -rf $TMPDIR
sudo mount -o remount /tmp
+68
View File
@@ -0,0 +1,68 @@
#!/bin/sh
###############################################################################
#
# This script is used for administration of the Hexagon DSP
#
# Copyright (c) 2012-2016 Qualcomm Technologies, Inc.
# All Rights Reserved.
# Confidential and Proprietary - Qualcomm Technologies, Inc.
#
###############################################################################
KEEP_ALIVE=0
subsys_name=""
echo -n "/firmware/image" > /sys/module/firmware_class/parameters/path
# Wait for adsp.mdt to show up
count=0
while [ ! -s /firmware/image/adsp.mdt ]; do
sleep 0.1
# wait 10s for /firmware mounted
count=$(( $count + 1 ))
if [ $count -ge 100 ]; then
echo "[ERROR] Can not find the adsp's firmware"
exit 1
fi
done
for subsys in `ls /sys/bus/msm_subsys/devices`; do
name=`cat /sys/bus/msm_subsys/devices/${subsys}/name`
if [ "`cat /sys/bus/msm_subsys/devices/${subsys}/name`" = "adsp" ]; then
subsys_name="${subsys}"
break
fi
done
if [ "$KEEP_ALIVE" = "1" ]; then
if [ -n "${subsys_name}" ]; then
sysctl -w kernel.panic=0
echo 1 > /sys/bus/msm_subsys/devices/${subsys_name}/keep_alive
else
echo "[ERROR] Can not keep adsp alive"
fi
fi
# FIXME: See ATL-3054
echo 1 > /sys/module/subsystem_restart/parameters/enable_debug
# Bring adsp out of reset
echo "[INFO] Bringing adsp out of reset"
echo "${subsys_name}"
echo 1 > /sys/kernel/boot_adsp/boot
# wait boot finished
if [ -n "${subsys_name}" ]; then
count=0
state=`cat /sys/bus/msm_subsys/devices/${subsys_name}/state`
while [ "${state}" != "ONLINE" ]; do
# wait 2s for subsys boot finished
count=$(( $count + 1 ))
if [ $count -ge 200 ]; then
echo "[ERROR] adsp fail to boot"
exit 1
fi
state=`cat /sys/bus/msm_subsys/devices/${subsys_name}/state`
sleep 0.1
done
fi
+161
View File
@@ -0,0 +1,161 @@
#!/usr/bin/env python3
import time
from smbus2 import SMBus
from collections import namedtuple
from typing import List
# https://datasheets.maximintegrated.com/en/ds/MAX98089.pdf
AmpConfig = namedtuple('AmpConfig', ['name', 'value', 'register', 'offset', 'mask'])
EQParams = namedtuple('EQParams', ['K', 'k1', 'k2', 'c1', 'c2'])
def configs_from_eq_params(base, eq_params):
return [
AmpConfig("K (high)", (eq_params.K >> 8), base, 0, 0xFF),
AmpConfig("K (low)", (eq_params.K & 0xFF), base + 1, 0, 0xFF),
AmpConfig("k1 (high)", (eq_params.k1 >> 8), base + 2, 0, 0xFF),
AmpConfig("k1 (low)", (eq_params.k1 & 0xFF), base + 3, 0, 0xFF),
AmpConfig("k2 (high)", (eq_params.k2 >> 8), base + 4, 0, 0xFF),
AmpConfig("k2 (low)", (eq_params.k2 & 0xFF), base + 5, 0, 0xFF),
AmpConfig("c1 (high)", (eq_params.c1 >> 8), base + 6, 0, 0xFF),
AmpConfig("c1 (low)", (eq_params.c1 & 0xFF), base + 7, 0, 0xFF),
AmpConfig("c2 (high)", (eq_params.c2 >> 8), base + 8, 0, 0xFF),
AmpConfig("c2 (low)", (eq_params.c2 & 0xFF), base + 9, 0, 0xFF),
]
BASE_CONFIG = [
AmpConfig("MCLK prescaler", 0b01, 0x10, 4, 0b00110000),
AmpConfig("PM: enable speakers", 0b11, 0x4D, 4, 0b00110000),
AmpConfig("PM: enable DACs", 0b11, 0x4D, 0, 0b00000011),
AmpConfig("Enable PLL1", 0b1, 0x12, 7, 0b10000000),
AmpConfig("Enable PLL2", 0b1, 0x1A, 7, 0b10000000),
AmpConfig("DAI1: I2S mode", 0b00100, 0x14, 2, 0b01111100),
AmpConfig("DAI2: I2S mode", 0b00100, 0x1C, 2, 0b01111100),
AmpConfig("DAI1 Passband filtering: music mode", 0b1, 0x18, 7, 0b10000000),
AmpConfig("DAI1 voice mode gain (DV1G)", 0b00, 0x2F, 4, 0b00110000),
AmpConfig("DAI1 attenuation (DV1)", 0x0, 0x2F, 0, 0b00001111),
AmpConfig("DAI2 attenuation (DV2)", 0x0, 0x31, 0, 0b00001111),
AmpConfig("DAI2: DC blocking", 0b1, 0x20, 0, 0b00000001),
AmpConfig("DAI2: High sample rate", 0b0, 0x20, 3, 0b00001000),
AmpConfig("ALC enable", 0b1, 0x43, 7, 0b10000000),
AmpConfig("ALC/excursion limiter release time", 0b101, 0x43, 4, 0b01110000),
AmpConfig("ALC multiband enable", 0b1, 0x43, 3, 0b00001000),
AmpConfig("DAI1 EQ enable", 0b0, 0x49, 0, 0b00000001),
AmpConfig("DAI2 EQ clip detection disabled", 0b1, 0x32, 4, 0b00010000),
AmpConfig("DAI2 EQ attenuation", 0x5, 0x32, 0, 0b00001111),
AmpConfig("Excursion limiter upper corner freq", 0b100, 0x41, 4, 0b01110000),
AmpConfig("Excursion limiter lower corner freq", 0b00, 0x41, 0, 0b00000011),
AmpConfig("Excursion limiter threshold", 0b000, 0x42, 0, 0b00001111),
AmpConfig("Distortion limit (THDCLP)", 0x6, 0x46, 4, 0b11110000),
AmpConfig("Distortion limiter release time constant", 0b0, 0x46, 0, 0b00000001),
AmpConfig("Right DAC input mixer: DAI1 left", 0b0, 0x22, 3, 0b00001000),
AmpConfig("Right DAC input mixer: DAI1 right", 0b0, 0x22, 2, 0b00000100),
AmpConfig("Right DAC input mixer: DAI2 left", 0b1, 0x22, 1, 0b00000010),
AmpConfig("Right DAC input mixer: DAI2 right", 0b0, 0x22, 0, 0b00000001),
AmpConfig("DAI1 audio port selector", 0b10, 0x16, 6, 0b11000000),
AmpConfig("DAI1 in/output enable", 0b11, 0x16, 0, 0b11),
AmpConfig("DAI2 audio port selector", 0b01, 0x1E, 6, 0b11000000),
AmpConfig("DAI2 in/output enable", 0b11, 0x1E, 0, 0b11),
AmpConfig("Enable left digital microphone", 0b1, 0x48, 5, 0b00100000),
AmpConfig("Enable right digital microphone", 0b1, 0x48, 4, 0b00010000),
AmpConfig("Enhanced volume smoothing disabled", 0b0, 0x49, 7, 0b10000000),
AmpConfig("Volume adjustment smoothing disabled", 0b0, 0x49, 6, 0b01000000),
AmpConfig("Zero-crossing detection disabled", 0b0, 0x49, 5, 0b00100000),
]
CONFIGS = {
"tici": [
AmpConfig("Right speaker output from right DAC", 0b1, 0x2C, 0, 0b11111111),
AmpConfig("Right Speaker Mixer Gain", 0b00, 0x2D, 2, 0b00001100),
AmpConfig("Right speaker output volume", 0x1c, 0x3E, 0, 0b00011111),
AmpConfig("DAI2 EQ enable", 0b1, 0x49, 1, 0b00000010),
*configs_from_eq_params(0x84, EQParams(0x274F, 0xC0FF, 0x3BF9, 0x0B3C, 0x1656)),
*configs_from_eq_params(0x8E, EQParams(0x1009, 0xC6BF, 0x2952, 0x1C97, 0x30DF)),
*configs_from_eq_params(0x98, EQParams(0x0F75, 0xCBE5, 0x0ED2, 0x2528, 0x3E42)),
*configs_from_eq_params(0xA2, EQParams(0x091F, 0x3D4C, 0xCE11, 0x1266, 0x2807)),
*configs_from_eq_params(0xAC, EQParams(0x0A9E, 0x3F20, 0xE573, 0x0A8B, 0x3A3B)),
],
"tizi": [
AmpConfig("Left speaker output from left DAC", 0b1, 0x2B, 0, 0b11111111),
AmpConfig("Right speaker output from right DAC", 0b1, 0x2C, 0, 0b11111111),
AmpConfig("Left Speaker Mixer Gain", 0b00, 0x2D, 0, 0b00000011),
AmpConfig("Right Speaker Mixer Gain", 0b00, 0x2D, 2, 0b00001100),
AmpConfig("Left speaker output volume", 0x17, 0x3D, 0, 0b00011111),
AmpConfig("Right speaker output volume", 0x17, 0x3E, 0, 0b00011111),
AmpConfig("DAI2 EQ enable", 0b0, 0x49, 1, 0b00000010),
AmpConfig("DAI2: DC blocking", 0b0, 0x20, 0, 0b00000001),
AmpConfig("ALC enable", 0b0, 0x43, 7, 0b10000000),
AmpConfig("DAI2 EQ attenuation", 0x2, 0x32, 0, 0b00001111),
AmpConfig("Excursion limiter upper corner freq", 0b001, 0x41, 4, 0b01110000),
AmpConfig("Excursion limiter threshold", 0b100, 0x42, 0, 0b00001111),
AmpConfig("Distortion limit (THDCLP)", 0x0, 0x46, 4, 0b11110000),
AmpConfig("Distortion limiter release time constant", 0b1, 0x46, 0, 0b00000001),
AmpConfig("Left DAC input mixer: DAI1 left", 0b0, 0x22, 7, 0b10000000),
AmpConfig("Left DAC input mixer: DAI1 right", 0b0, 0x22, 6, 0b01000000),
AmpConfig("Left DAC input mixer: DAI2 left", 0b1, 0x22, 5, 0b00100000),
AmpConfig("Left DAC input mixer: DAI2 right", 0b0, 0x22, 4, 0b00010000),
AmpConfig("Right DAC input mixer: DAI2 left", 0b0, 0x22, 1, 0b00000010),
AmpConfig("Right DAC input mixer: DAI2 right", 0b1, 0x22, 0, 0b00000001),
AmpConfig("Volume adjustment smoothing disabled", 0b1, 0x49, 6, 0b01000000),
],
}
class Amplifier:
AMP_I2C_BUS = 0
AMP_ADDRESS = 0x10
def __init__(self, debug=False):
self.debug = debug
def _get_shutdown_config(self, amp_disabled: bool) -> AmpConfig:
return AmpConfig("Global shutdown", 0b0 if amp_disabled else 0b1, 0x51, 7, 0b10000000)
def _set_configs(self, configs: List[AmpConfig]) -> None:
with SMBus(self.AMP_I2C_BUS) as bus:
for config in configs:
if self.debug:
print(f"Setting \"{config.name}\" to {config.value}:")
old_value = bus.read_byte_data(self.AMP_ADDRESS, config.register, force=True)
new_value = (old_value & (~config.mask)) | ((config.value << config.offset) & config.mask)
bus.write_byte_data(self.AMP_ADDRESS, config.register, new_value, force=True)
if self.debug:
print(f" Changed {hex(config.register)}: {hex(old_value)} -> {hex(new_value)}")
def set_configs(self, configs: List[AmpConfig]) -> bool:
# retry in case panda is using the amp
for _ in range(10):
try:
self._set_configs(configs)
return True
except OSError:
print("Failed to set amp config, retrying...")
time.sleep(0.02)
return False
def set_global_shutdown(self, amp_disabled: bool) -> bool:
return self.set_configs([self._get_shutdown_config(amp_disabled), ])
def initialize_configuration(self, model: str) -> bool:
cfgs = [
self._get_shutdown_config(True),
*BASE_CONFIG,
*CONFIGS[model],
self._get_shutdown_config(False),
]
return self.set_configs(cfgs)
if __name__ == "__main__":
with open("/sys/firmware/devicetree/base/model") as f:
model = f.read().strip('\x00')
model = model.split('comma ')[-1]
if model in CONFIGS:
amp = Amplifier()
amp.initialize_configuration(model)
else:
print(f"Skipping, no config for {model}")
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
/usr/comma/sound/adsp-start.sh
echo "waiting for sound card to come online"
while [ ! -d /proc/asound/sdm845tavilsndc ] || [ "$(cat /proc/asound/card0/state 2> /dev/null)" != "ONLINE" ] ; do
sleep 0.01
done
echo "sound card online"
while ! /usr/comma/sound/tinymix controls | grep -q "SEC_MI2S_RX Audio Mixer MultiMedia1"; do
sleep 0.01
done
echo "tinymix controls ready"
/usr/comma/sound/tinymix set "SEC_MI2S_RX Audio Mixer MultiMedia1" 1
if grep -q mici /sys/firmware/devicetree/base/model; then
/usr/comma/sound/tinymix set "MultiMedia1 Mixer SEC_MI2S_TX" 1
else
/usr/comma/sound/tinymix set "MultiMedia1 Mixer TERT_MI2S_TX" 1
/usr/comma/sound/tinymix set "TERT_MI2S_TX Channels" Two
fi
# setup the amplifier registers
/usr/local/venv/bin/python /usr/comma/sound/amplifier.py
Binary file not shown.
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python3
import subprocess
from tabulate import tabulate
# serial with timestamps:
# grabserial -d /dev/serial/by-id/usb-FTDI_FT230X* -t
# systemd-analyze critical-chain comma.service
# boot chart:
# systemd-analyze plot > /tmp/bootup.svg
def get_journal_time(x):
out = subprocess.check_output("journalctl -x -o short-monotonic", shell=True, encoding='utf8')
jlines = out.strip().splitlines()
for l in jlines:
if x in l:
t = l.split('[')[1].split(']')[0]
return float(t)
return None
if __name__ == "__main__":
ts = {
"PON": 1.5, # estimate from powering on to XBL
# these are dumped over serial, use the ones from the XBL
"XBL": 2.4,
"ABL": 3.7, # 3s of this is waiting for fastboot + factory reset tapping
}
def tot_since_kern():
return sum(ts.values()) - (ts['PON'] + ts['XBL'] + ts['ABL'])
out = subprocess.check_output("systemd-analyze", shell=True, encoding='utf8')
l = out.splitlines()[0].split(' ')
ts['kernel'] = float(l[3][:-1])
#ts['systemd'] = float(l[6][:-1])
ts['comma'] = get_journal_time("Starting comma.service") - tot_since_kern()
# print
tot = 0
total = sum(ts.values())
tab = []
for s, t in ts.items():
tot += t
tab.append([
s,
round(t, 2),
round(tot, 2),
str(round(t/total * 100)) + "%",
])
# TODO: add openpilot time-to-onroad
tab.append(['onroad', '?', '?', '-'])
print(tabulate(tab))
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env python3
import json
import time
import subprocess
def run(cmd):
return subprocess.check_output(cmd, shell=True, encoding='utf8')
def test_setup():
# TODO: write some real unit tests for this
proc = subprocess.Popen('/usr/comma/setup', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
time.sleep(5)
assert proc.poll() is None
proc.terminate()
def test_reset():
proc = subprocess.Popen('/usr/comma/reset', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
time.sleep(5)
assert proc.poll() is None
proc.terminate()
def test_modem():
out = run("mmcli -m 0 --output-json")
mm = json.loads(out)
from pprint import pprint
pprint(mm)
# modem is up
g = mm['modem']['generic']
assert g['manufacturer'] == 'QUALCOMM INCORPORATED'
assert g['model'] == 'QUECTEL Mobile Broadband Module'
assert g['revision'] == 'EG25GGBR07A08M2G'
# sim is present
assert g['sim'] == '/org/freedesktop/ModemManager1/SIM/0'
# blue prime is active
out = run("nmcli con show --active")
assert "blue-prime" in out
def test_wifi():
out = run("nmcli dev wifi")
networks = out.strip().splitlines()[1:]
assert len(networks) > 5
def test_python_shims():
subprocess.check_call("cd /data/openpilot && scons -h", shell=True, stdout=subprocess.DEVNULL)
def test_dmesg():
# TODO: ensure no new errors in dmesg. would catch things like the brightness setting bug
pass
def test_systemd_services():
pass
def test_boot_time():
out = subprocess.check_output("systemd-analyze", shell=True, encoding='utf8')
a = out.splitlines()[0]
print(out, a)
# check comma service
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env python3
import os
import json
import subprocess
import time
def mmcli(cmd):
try:
out = subprocess.check_output(["mmcli", "-J", *cmd])
return json.loads(out)
except Exception as e:
raise Exception(f"modem command failed: {cmd}") from e
def test_modem():
# wait for the modem to come back up after flashing
n = 0
cnt = 0
while n == 0:
n = len(mmcli(["-L"])['modem-list'])
if n > 1:
raise Exception(f"Wrong number of modems ({n})")
cnt += 1
if cnt > 100:
raise Exception("Modem never came up")
time.sleep(1)
cnt = 0
while True:
modem = mmcli(["-m", "any"])
if modem['modem']['generic']['sim'] != '--':
break
cnt += 1
if cnt > 100:
raise Exception("SIM missing")
time.sleep(1)
# force to LTE
#os.system("mmcli -m any --set-allowed-modes='4g'")
# set initial eps bearer apn
#sim_id = mmcli(['-i', '0'])['sim']['properties']['iccid']
#if sim_id.startswith('8901410'):
# os.system('mmcli -m any --3gpp-set-initial-eps-bearer-settings="apn=Broadband"')
print("waiting for cell connection")
time.sleep(7)
expected = [
# key, expected value, error msg
(['generic', 'manufacturer'], "QUALCOMM INCORPORATED", "Modem: wrong manufacturer"),
(['generic', 'model'], "QUECTEL Mobile Broadband Module", "Modem: wrong model"),
(['generic', 'revision'], "EG25GGBR07A08M2G", "Modem: wrong revision"),
(['generic', 'carrier-configuration'], ["VoLTE-ATT", "Commercial-TMO_VoLTE"], "Modem: wrong carrier configuration"),
(['generic', 'carrier-configuration-revision'], ["0501033C", "05010505"], "Modem: wrong carrier configuration revision"),
(['generic', 'supported-capabilities'], [['gsm-umts, lte'], ], "Modem: wrong capabilities"),
(['3gpp', 'operator-name'], ["--", "AT&T", "T-Mobile"], "Modem: wrong operator"),
]
for key, val, err_msg in expected:
v = modem['modem']
for k in key:
v = v.get(k)
if isinstance(val, list):
assert v in val, f"{err_msg} ({v})"
else:
assert v == val, f"{err_msg} ({v})"
os.system("date >> /data/tmp/modem_log")
os.system("sudo su -c 'tail /data/tmp/modem_log > /dev/console'")
os.system("sudo su -c 'wc -l /data/tmp/modem_log > /dev/console'")
os.sync()
time.sleep(2)
os.system("sudo reboot")
if __name__ == "__main__":
test_modem()
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
import os
import time
import subprocess
good = """
Starting Sound...
[INFO] Bringing adsp out of reset
subsys4
waiting for sound card to come online
sound card online
sound.service: Succeeded.
Finished Sound.
""".strip()
if __name__ == "__main__":
time.sleep(3)
log = subprocess.check_output("journalctl -o cat -u sound", shell=True, encoding='utf8').strip()
passed = log == good
with open('/data/tmp/sound_log', 'a') as f:
f.write(f"{passed}\n")
os.system("journalctl -u sound.service -o short-monotonic >> /data/tmp/sound_service_log")
os.system("sudo su -c 'tail /data/tmp/sound_log > /dev/console'")
os.system("sudo su -c 'wc -l /data/tmp/sound_log > /dev/console'")
os.sync()
if passed:
time.sleep(2)
os.system("sudo reboot")
+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
set -e
RATE=${1:-1}
log_message() {
# /var/log/syslog
cat /usr/include/sqlite3.h | systemd-cat -t SPAM_TEST
# /var/log/kern.log
#cat /usr/include/sqlite3.h | sudo tee /dev/kmsg > /dev/null
}
# verify config is good
sudo logrotate -d /etc/logrotate.conf
sudo rm -rf /var/log/*
sudo systemctl daemon-reload
sudo systemctl restart rsyslog
sudo systemctl restart systemd-journald
sudo systemctl restart logrotate-hourly.timer
while true; do
for i in $(seq 1 $RATE); do
log_message
done
echo
df -h /var/
sudo du -hs /var/log/* || true
sleep 1
done
@@ -0,0 +1,7 @@
#!/usr/bin/bash
# silences a ruby warning
# https://bugs.launchpad.net/ubuntu/+source/iptables-netflow/+bug/1907932
export RUBYOPT="-W0"
irqtop
+23
View File
@@ -0,0 +1,23 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
# See tmpfiles.d(5) for details
# /var: rebuild enough for services to be happy
d /var/crash 0755 - - -
q /var/tmp 1777 root root 30d
d /var/lib/dpkg 0755 - - -
f /var/lib/dpkg/lock-frontend 0755 - - -
f /var/lib/dpkg/status 0755 - - -
d /var/lib/logrotate 0755 - - -
d /var/spool 0755 - - -
d /var/spool/cron/atjobs 0755 - - -
d /var/cache/pollinate 0755 pollinate daemon -
+3
View File
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3a94ab8395f20d20a9d5a2a2bacca0694f072df8421cf13adca6250d28065bdc
size 24709205
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env python3
import os
import time
if __name__ == "__main__":
# we are the last line of defense for /var/log filling up
while True:
usage = os.statvfs('/var/log')
percent = (usage.f_blocks - usage.f_bavail) / usage.f_blocks * 100
if percent > 70:
for fn in os.listdir('/var/log'):
file_path = os.path.join('/var/log', fn)
if os.path.isfile(file_path):
with open(file_path, 'w'):
pass
time.sleep(1)
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash -e
until [ -e $1 ]
do
sleep 1
done
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.