Compare commits

..

114 Commits

Author SHA1 Message Date
firestar5683 259ac19499 Honda 2026-02-17 21:02:15 -06:00
firestar5683 1a77897c3a no sascm
Revert "no sascm"

This reverts commit 147e752007c6a4f80eec551934bc1cf86510e6dc.

Update interface.py
2026-02-17 20:49:33 -06:00
firestar5683 b5d39c4bc1 Truck Tuning 2026-02-17 19:57:35 -06:00
firestar5683 d4d78c9435 Update frogpilot_acceleration.py 2026-02-17 12:28:29 -06:00
firestar5683 2f29d7ee04 EV Tuning 2026-02-16 23:43:46 -06:00
firestar5683 338a07973b Truck Tuning 2026-02-16 23:39:45 -06:00
firestar5683 f4da6a3e3b silverado 2026-02-16 17:28:35 -06:00
firestar5683 5fbaebc91c brake mismatches 2026-02-16 13:25:23 -06:00
firestarsdog 7dbdb33ed1 Gen2ACC Distance Button Sync for CC_ONLY_CAR 2026-02-15 23:33:15 -06:00
firestar5683 a1cd4954b1 cancel acc bolt with pedal 2026-02-15 23:15:48 -06:00
firestar5683 2bbffc2a38 cruisestatus acc pedal 2026-02-14 22:44:33 -06:00
firestar5683 4d7aee4935 pedal 2026-02-14 15:58:32 -06:00
firestarsdog 41b055d140 Update values.py 2026-02-14 16:24:10 -05:00
firestarsdog bec0c04334 Evil +? 2026-02-14 13:02:22 -05:00
firestar5683 a8499d20fc Separate Non-ACC vs ACC + Pedal 2026-02-13 23:48:41 -06:00
firestar5683 6d0c17f43a Holiday 2026-02-13 22:45:30 -06:00
firestar5683 6dec58237b Fingerprinting 2026-02-13 22:35:10 -06:00
firestarsdog 6a47be1631 Hondadays 2026-02-13 21:38:01 -05:00
firestarsdog 8ea080b4cb Honda attempt from bugsink 2026-02-13 15:35:17 -05:00
firestarsdog a51503f2e4 BugSink Catch - human_lane_changes 2026-02-13 11:16:12 -05:00
firestar5683 07c722553d The Great Merge 2026-02-13 01:52:05 -06:00
firestar5683 14b1793c79 User adjustable offsets 2026-02-07 23:32:26 -06:00
firestar5683 055c223ded Integrator Smooth On Handoff 2026-02-06 15:46:56 -06:00
firestar5683 4d406112f7 Lights 2026-02-05 22:39:42 -06:00
firestar5683 e03f28bba0 New Models 2026-02-05 15:05:18 -06:00
firestar5683 f0cc963c0e Revert "merry christmas"
This reverts commit 8a9d0e5e6a.
2026-02-05 13:33:40 -06:00
firestar5683 cd39ce0305 Increase Fault Resilience 2026-02-05 13:15:39 -06:00
firestarsdog 749b5e06fb Stats 2026-02-02 01:04:19 -05:00
firestarsdog 23121cca0e Stats 2026-02-01 22:46:13 -06:00
firestar5683 6f0502e862 friction threshold 2026-01-29 11:28:30 -06:00
firestar5683 04c59fb18e Lat Updates 2026-01-28 23:51:36 -06:00
firestar5683 844dce2030 Update interface.py 2026-01-20 22:08:07 -06:00
firestar5683 aa77db1fc9 Update override.toml 2026-01-19 21:18:53 -06:00
firestar5683 bee9b2b046 Revert "Mac Update"
This reverts commit 1b5d776464.
2026-01-19 11:43:31 -06:00
firestarsdog 469cd5e528 Add SASCM to vehicle settings detection/stats 2026-01-19 10:32:21 -06:00
firestar5683 23f52644ae Update interface.py 2026-01-18 23:45:59 -06:00
firestar5683 e76b82603b Update interface.py 2026-01-18 23:44:42 -06:00
firestar5683 1b5d776464 Mac Update 2026-01-18 22:22:06 -06:00
firestarsdog 61f4e8b142 Stats 2026-01-18 22:17:42 -06:00
firestar5683 f0fefb6e13 Torque Controller Update 2026-01-18 21:58:43 -06:00
firestar5683 25a7090c3d Update redneck 2026-01-15 22:54:15 -06:00
firestar5683 b0de4d64b4 Split Tune 2026-01-15 19:17:55 -06:00
firestar5683 77ae5b176a fix redneck v2 2026-01-14 13:58:22 -06:00
firestar5683 89de28682c Remove lat smooth seconds 2026-01-14 13:49:35 -06:00
firestar5683 a1d4dcb9a0 frogpilot migration 2026-01-12 22:10:40 -06:00
firestar5683 c8deae75b7 More defaults 2026-01-12 22:04:19 -06:00
firestar5683 8653fb41f2 Update defaults 2026-01-12 22:00:04 -06:00
firestar5683 c064197fde Big Mac 2026-01-11 16:58:25 -06:00
firestar5683 7f878ec1dc Try Higher Friction 2026-01-10 14:04:32 -06:00
firestar5683 140bdd59fb Autotune Off 2026-01-09 22:40:45 -06:00
firestar5683 6f728f935a Revert "Pedal Braking Limits"
This reverts commit 568b72095f.
2025-12-31 20:55:13 -06:00
firestar5683 568b72095f Pedal Braking Limits 2025-12-30 20:17:59 -06:00
firestar5683 0aaf4d1336 merry christmas 2025-12-24 22:04:58 -06:00
firestar5683 bb3f0a3354 ds2 2025-12-24 21:28:40 -06:00
firestar5683 f2aba355b9 Try friction adjustment 2025-12-16 14:38:29 -06:00
firestar5683 e6513efb9b Update frogpilot_tracking.py 2025-12-15 00:55:51 -06:00
firestar5683 872a2c58aa minsteer speed 2025-12-14 14:46:27 -06:00
firestar5683 1630560715 Update Percentages 2025-12-13 19:13:44 -06:00
firestar5683 4cfd893837 Trailer Load Gas Tuning 2025-12-12 10:50:11 -06:00
firestar5683 0e93ceef00 Live Friction 2025-12-11 16:54:11 -06:00
firestar5683 d626f0fe49 Zero error 2025-12-11 15:12:29 -06:00
firestar5683 8dae3d375c Updates
Update latcontrol_torque.py

interp friction threshold
2025-12-09 19:58:46 -06:00
firestar5683 721d39ef1f Change NoEntryAlert message to 'Reverse Gear' 2025-12-06 16:44:30 -06:00
firestar5683 a97c5742b7 Update events.py 2025-12-05 20:13:49 -06:00
firestar5683 488f821983 LattyBoi2.0 2025-12-03 23:30:35 -06:00
firestar5683 190dc98180 Latty Boi
Revert "Latty Boi"

This reverts commit af687e501cc4bdcda7840453d06595d7ea674148.

Reapply "Latty Boi"

This reverts commit ff5566d4439f5e4997fe83f4f21d0be62b75d75d.
2025-12-02 20:29:48 -06:00
firestar5683 0b459d9f0b Recovery Power 2025-12-02 17:18:43 -06:00
firestar5683 3cd594bbe4 New planplus 2025-12-02 12:09:05 -06:00
Woohyun Rho f31082ce2b Update 2025-11-28 17:10:45 -06:00
firestar5683 b51d7ae35d Update interface.py 2025-11-18 20:48:48 -06:00
firestar5683 884fcb8315 New Lateral Changes 2025-11-18 20:48:21 -06:00
firestar5683 77597e60b2 Update 2025-11-15 14:44:07 -06:00
firestar5683 f2fbc8f30b Accel Tests 2025-11-14 20:32:47 -06:00
firestar5683 fffea614a4 Paddle Planner 2025-11-14 01:26:06 -06:00
firestar5683 e7e593cdb2 Revert "Upstream Lateral"
This reverts commit 97f8736605.
2025-11-10 23:07:02 -06:00
firestar5683 97f8736605 Upstream Lateral
Revert "Upstream Lateral"

This reverts commit 20f7d6631bb152860781b46533bb0e96223be132.

Reapply "Upstream Lateral"

This reverts commit 2a7a563e219a1b688529d341919fc377fed5038e.

Update latcontrol_torque.py

more lateral

Update ui
2025-11-07 00:13:34 -06:00
firestar5683 48efc5b97a Update manager.py 2025-10-27 00:58:28 -05:00
firestar5683 4cca6553e4 Update 2025-10-25 15:35:55 -05:00
firestar5683 6eda52b562 Medium Fanta 2025-10-22 22:18:08 -05:00
firestar5683 de9cbc5de6 Update interfaces.py 2025-10-20 13:49:08 -05:00
firestar5683 fee241dc0b no nnff 2025-10-19 17:59:36 -05:00
firestar5683 2094be9a7a Scene Complexity 2025-10-18 14:24:48 -05:00
firestar5683 6ce476025d Update carcontroller.py 2025-10-17 19:10:41 -05:00
firestar5683 dd6c62dbf6 Update interface.py 2025-10-17 18:13:24 -05:00
firestar5683 2ab19dbd4c CEM 2025-10-17 17:39:06 -05:00
firestar5683 3241fbdd8c lite 2025-10-17 17:13:37 -05:00
firestar5683 1f0350e66a Redneck 2.0 2025-10-17 16:55:56 -05:00
firestar5683 ce46776439 Modify torque tuning parameters in interfaces.py
Adjusted torque tuning parameters for improved performance.
2025-10-17 16:53:54 -05:00
firestar5683 afb209a1a8 Hurts Donut 2025-10-16 23:57:08 -05:00
firestar5683 b4e29d4ed6 Smoothy Boi 2025-10-16 23:35:26 -05:00
firestar5683 dada0f2ae6 New change 2025-10-15 22:59:04 -05:00
firestar5683 4532e7f5d1 lat3 2025-10-15 22:20:35 -05:00
firestar5683 78de442ee1 New Lateral Changes 2025-10-10 20:59:23 -05:00
firestar5683 953b343e06 Fix Standard 2025-10-10 19:24:24 -05:00
firestar5683 5b26be2e3c error? 2025-10-08 23:13:32 -05:00
firestar5683 4abe50405c Update interface.py 2025-10-08 23:07:37 -05:00
firestar5683 f2e705413c Fix New Devices 2025-10-08 22:19:43 -05:00
firestar5683 da56f26105 No positive P-response for long control if user-selected parameter set 2025-10-08 07:42:32 -05:00
firestar5683 ab39266180 Automatic updates 2025-10-04 16:04:35 -05:00
firestar5683 dac85dfd3a Steer Alerts 2025-10-04 01:49:22 -05:00
firestar5683 7e539cde38 Update frogpilot_acceleration.py 2025-10-03 22:42:08 -05:00
firestar5683 16a79fbc3d SteerAlerts
Revert "SteerAlerts"

This reverts commit cbaba399c5b9caac5a8faf3917f0929d747a0acc.

Update controlsd.py
2025-10-03 22:14:25 -05:00
firestar5683 9cdf0120cf Donut DM 2025-10-03 20:50:00 -05:00
firestar5683 aa0f0aaac8 Update gm_global_a_powertrain_generated.dbc 2025-10-03 16:41:22 -05:00
firestar5683 aefaafb616 Update 2025-10-03 00:43:40 -05:00
firestar5683 388f63168f firehose 2025-09-30 20:45:47 -05:00
firestar5683 7fe40f6e7f Update 2025-09-30 14:30:04 -05:00
firestar5683 eb2218e733 Dom 2025-09-30 09:25:14 -05:00
firestar5683 aa9364a311 Tinygrad 2025-09-30 08:56:38 -05:00
James 255c89c6ab Compile FrogPilot 2025-09-27 12:00:00 -07:00
James a759abb082 September 27th, 2025 Update 2025-09-27 12:00:00 -07:00
James 73821d9482 FrogPilot 0.9.7 2025-09-27 12:00:00 -07:00
James be881fc77a OPGM
Co-Authored-By: Eric Brown <13560103+nworb-cire@users.noreply.github.com>
2025-09-27 12:00:00 -07:00
James 6d316f2bc7 openpilot v0.9.7 release
date: 2024-06-11T01:36:39
master commit: f8cb04e4a8b032b72a909f68b808a50936184bee
2025-09-27 12:00:00 -07:00
2878 changed files with 1077803 additions and 71520 deletions
+32 -19
View File
@@ -3,6 +3,14 @@ name: Compile FrogPilot
on:
workflow_dispatch:
inputs:
runner:
description: "Select the runner"
required: true
default: "c3"
type: choice
options:
- c3
- c3x
not_vetted:
description: "This branch is not vetted"
required: false
@@ -29,7 +37,7 @@ on:
default: ""
type: string
update_translations:
description: "Update missing translations"
description: "Update missing/outdated translations"
required: false
default: "false"
type: boolean
@@ -46,7 +54,9 @@ env:
jobs:
get_branch:
runs-on: [self-hosted, c3x]
runs-on:
- self-hosted
- ${{ github.event.inputs.runner }}
outputs:
branch: ${{ steps.get_branch.outputs.branch }}
python_version: ${{ steps.get_python_version.outputs.python_version }}
@@ -72,8 +82,8 @@ jobs:
steps:
- name: Configure Git Identity
run: |
git config --global user.name "${{ github.actor }}"
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
git config --global user.name "James"
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
- name: Checkout Required Files
uses: actions/checkout@v4
@@ -101,8 +111,16 @@ jobs:
- name: Update Translations
run: python selfdrive/ui/update_translations.py --vanish
- name: Translate Missing or Outdated Translations
run: python selfdrive/ui/translations/auto_translate.py --all-files $([[ "${{ github.event.inputs.vet_existing_translations }}" == "true" ]] && echo "--vet-translations")
- name: Update Missing Translations
continue-on-error: true
run: python selfdrive/ui/translations/auto_translate.py --all-files
timeout-minutes: 300
- name: Vet Existing Translations
if: github.event.inputs.vet_existing_translations == 'true'
continue-on-error: true
run: python selfdrive/ui/translations/auto_translate.py --all-files --vet-translations
timeout-minutes: 300
- name: Commit and Push Translation Updates
run: |
@@ -122,7 +140,9 @@ jobs:
- get_branch
- translate
if: always()
runs-on: [self-hosted, c3x]
runs-on:
- self-hosted
- ${{ github.event.inputs.runner }}
permissions:
contents: write
defaults:
@@ -133,8 +153,8 @@ jobs:
run: |
git config --global http.postBuffer 104857600
git config --global user.name "${{ github.actor }}"
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
git config --global user.name "James"
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
- name: Update Repository
run: |
@@ -142,8 +162,7 @@ jobs:
if [ "${{ github.event.inputs.update_translations }}" = "true" ]; then
git fetch origin ${{ needs.get_branch.outputs.branch }}
git reset --hard origin/${{ needs.get_branch.outputs.branch }}
git pull origin ${{ needs.get_branch.outputs.branch }}
git reset --hard FETCH_HEAD
fi
- name: Take Ownership of Build
@@ -180,19 +199,12 @@ jobs:
rm -f panda/board/obj/version
find . -name '*.a' -delete
find . -name '*.cc' -delete
find . -name '*.o' -delete
find . -name '*.onnx' -delete
find . -name '*.os' -delete
find . -name '*.pyc' -delete
find . -name 'moc_*' -delete
find . -name '*.h' | while read -r header; do
if [[ "$header" != *"common/version.h" && "$header" != *"system/camerad/sensors/"* ]]; then
rm -f "$header"
fi
done
rm -rf .devcontainer/
rm -rf .vscode/
rm -rf body/
@@ -210,7 +222,8 @@ jobs:
-name 'review_pull_request.yaml' -o \
-name 'schedule_update.yaml' -o \
-name 'update_pr_branch.yaml' -o \
-name 'update_release_branch.yaml' \
-name 'update_release_branch.yaml' -o \
-name 'update_tinygrad.yaml' \
\) \
\) -exec rm -rf {} +
+2 -2
View File
@@ -16,8 +16,8 @@ jobs:
steps:
- name: Configure Git Identity
run: |
git config --global user.name "${{ github.actor }}"
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
git config --global user.name "James"
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
- name: Checkout ${{ env.BRANCH }}
uses: actions/checkout@v3
+22 -36
View File
@@ -6,6 +6,8 @@ on:
- FrogPilot-Staging
env:
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
SOURCE_BRANCH: FrogPilot-Staging
TARGET_BRANCH: MAKE-PRS-HERE
@@ -15,36 +17,31 @@ jobs:
steps:
- name: Configure Git Identity
run: |
git config --global user.name "${{ github.actor }}"
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
git config --global user.name "James"
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
- name: Checkout ${{ env.SOURCE_BRANCH }}
uses: actions/checkout@v3
with:
ref: "${{ env.SOURCE_BRANCH }}"
persist-credentials: false
fetch-depth: 0
ref: ${{ env.SOURCE_BRANCH }}
- name: Find "Compile FrogPilot" Commit in ${{ env.SOURCE_BRANCH }}
id: find_parent
run: |
COMMIT=$(git rev-list HEAD -n 1 --grep="Compile FrogPilot")
if [ -z "$COMMIT" ]; then
echo "Commit with message 'Compile FrogPilot' not found." >&2
exit 1
fi
[ -z "$COMMIT" ] && echo "Compile commit not found." >&2 && exit 1
PARENT=$(git rev-list --parents -n 1 "$COMMIT" | awk '{print $2}')
if [ -z "$PARENT" ]; then
echo "Parent commit not found." >&2
exit 1
fi
[ -z "$PARENT" ] && echo "Parent commit not found." >&2 && exit 1
echo "Compile commit: $COMMIT"
echo "Parent commit: $PARENT"
echo "parent_commit=$PARENT" >> "$GITHUB_OUTPUT"
echo "compile_commit=$COMMIT" >> "$GITHUB_OUTPUT"
- name: Checkout ${{ env.TARGET_BRANCH }}
- name: Fetch and Checkout ${{ env.TARGET_BRANCH }}
run: |
git fetch origin "${{ env.TARGET_BRANCH }}"
git checkout "${{ env.TARGET_BRANCH }}"
@@ -53,17 +50,12 @@ jobs:
run: |
git rm -r --ignore-unmatch .
git clean -fdx
PARENT_COMMIT="${{ steps.find_parent.outputs.parent_commit }}"
git checkout "$PARENT_COMMIT" -- .
git checkout "${{ steps.find_parent.outputs.parent_commit }}" -- .
COMPILE_COMMIT="${{ steps.find_parent.outputs.compile_commit }}"
SOURCE_HEAD=$(git rev-parse "origin/${{ env.SOURCE_BRANCH }}")
if [ "$COMPILE_COMMIT" != "$SOURCE_HEAD" ]; then
echo "Applying changes from '${{ env.SOURCE_BRANCH }}' branch..."
git cherry-pick --no-commit "${COMPILE_COMMIT}".."$SOURCE_HEAD"
fi
[ "$COMPILE_COMMIT" != "$SOURCE_HEAD" ] && git cherry-pick --no-commit "${COMPILE_COMMIT}".."$SOURCE_HEAD"
rm -f .github/update_date
@@ -72,28 +64,22 @@ jobs:
- name: Commit and Push to ${{ env.TARGET_BRANCH }}
run: |
TZ_VALUE="America/Phoenix"
current_day=$(TZ="$TZ_VALUE" date +"%-d")
day=$(TZ="$TZ_VALUE" date +"%-d")
month=$(TZ="$TZ_VALUE" date +"%B")
year=$(TZ="$TZ_VALUE" date +"%Y")
if [[ "$current_day" =~ ^1[123]$ ]]; then
suffix="th"
else
case $(($current_day % 10)) in
1) suffix="st" ;;
2) suffix="nd" ;;
3) suffix="rd" ;;
*) suffix="th" ;;
esac
fi
case $day in
11|12|13) s=th ;;
*) case $((day % 10)) in 1) s=st ;; 2) s=nd ;; 3) s=rd ;; *) s=th ;; esac ;;
esac
commit_message="${month} ${current_day}${suffix}, ${year} Update"
echo "Commit message: $commit_message"
commit_message="${month} ${day}${s}, ${year} Update"
if git log --oneline --format="%s" | grep -q "$commit_message"; then
echo "Existing commit found with message: $commit_message"
if git log -1 --pretty=%s | grep -q "$commit_message"; then
git commit --amend --no-edit
else
git commit -m "$commit_message"
fi
git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}
git push origin "${{ env.TARGET_BRANCH }}" --force
+23 -24
View File
@@ -2,9 +2,11 @@ name: Update FrogPilot Branch
on:
schedule:
- cron: "0 18 * * *"
- cron: "0 18 * * 6"
env:
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
BRANCH_FROGPILOT: FrogPilot
BRANCH_PREVIOUS: FrogPilot-Previous
BRANCH_STAGING: FrogPilot-Staging
@@ -20,7 +22,7 @@ jobs:
update_due: ${{ steps.check_update.outputs.update_due }}
scheduled_date: ${{ steps.check_update.outputs.scheduled_date }}
steps:
- name: Download the 'update_date' File
- name: Download the "update_date" File
id: download_update
run: |
curl -fLsS "https://raw.githubusercontent.com/FrogAi/FrogPilot/${{ env.BRANCH_STAGING }}/${{ env.UPDATE_FILE }}" -o update_date || touch update_date_missing
@@ -29,18 +31,14 @@ jobs:
id: check_update
run: |
if [ -f update_date_missing ]; then
echo "No update_date file found in FrogPilot-Staging."
echo "update_due=false" >> "$GITHUB_OUTPUT"
exit 0
fi
SCHEDULED_DATE=$(cat update_date)
CURRENT_DATE=$(TZ="${{ env.TZ }}" date +%F)
echo "Scheduled Date: $SCHEDULED_DATE"
echo "Current Date: $CURRENT_DATE"
if [ "$SCHEDULED_DATE" != "$CURRENT_DATE" ]; then
echo "Update not due."
echo "update_due=false" >> "$GITHUB_OUTPUT"
exit 0
fi
@@ -55,8 +53,8 @@ jobs:
steps:
- name: Configure Git Identity
run: |
git config --global user.name "${{ github.actor }}"
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
git config --global user.name "James"
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
- name: Checkout ${{ env.BRANCH_STAGING }}
uses: actions/checkout@v3
@@ -64,25 +62,32 @@ jobs:
fetch-depth: 0
ref: ${{ env.BRANCH_STAGING }}
- name: Update README Date and Remove (${{ env.UPDATE_FILE }})
- name: Authenticate with GITHUB_TOKEN
run: |
git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}
- name: Update README Date and Remove update file
run: |
DAY=$(TZ="${{ env.TZ }}" date +'%d' | sed 's/^0//')
case "$DAY" in
1|21|31) SUFFIX="st" ;;
2|22) SUFFIX="nd" ;;
3|23) SUFFIX="rd" ;;
*) SUFFIX="th" ;;
2|22) SUFFIX="nd" ;;
3|23) SUFFIX="rd" ;;
*) SUFFIX="th" ;;
esac
MONTH=$(TZ="${{ env.TZ }}" date +'%B')
YEAR=$(TZ="${{ env.TZ }}" date +'%Y')
NEW_DATE="**${MONTH} ${DAY}${SUFFIX}, ${YEAR}**"
echo "Updating README date to ${NEW_DATE}"
sed -i "/FrogPilot was last updated on:/ { N; N; s/\(\n\)\n.*$/\1\n${NEW_DATE}/; }" README.md
DATE="${MONTH} ${DAY}${SUFFIX}, ${YEAR}"
DATE_ESCAPED=$(printf '%s' "$DATE" | sed -E 's/ /%20/g; s/,/%2C/g')
sed -i -E "s|(Last%20Updated-)[^-)]*|\1${DATE_ESCAPED}|g" README.md
git add README.md
git rm -f "${{ env.UPDATE_FILE }}"
git commit -m "Updated README date to ${NEW_DATE}"
git commit -m "Updated README date to ${DATE}"
- name: Squash Commits
run: |
@@ -102,18 +107,12 @@ jobs:
run: |
git fetch origin ${{ env.BRANCH_PREVIOUS }} ${{ env.BRANCH_FROGPILOT }}
- name: Wait Until Noon ${{ env.TZ }} Before Continuing
- name: Wait Until Noon ${{ env.TZ }}
run: |
NOW=$(TZ="${{ env.TZ }}" date +%s)
TARGET=$(TZ="${{ env.TZ }}" date -d "12:00" +%s)
if [ "$NOW" -lt "$TARGET" ]; then
SLEEP_TIME=$((TARGET - NOW))
echo "Sleeping for $SLEEP_TIME seconds until noon..."
sleep $SLEEP_TIME
else
echo "It is already noon or past noon, proceeding immediately."
fi
[ "$NOW" -lt "$TARGET" ] && sleep $((TARGET - NOW))
- name: Push ${{ env.BRANCH_STAGING }}
run: |
+79
View File
@@ -0,0 +1,79 @@
name: Update Tinygrad
on:
workflow_dispatch:
inputs:
runner:
description: "Select the runner"
required: true
default: "c3"
type: choice
options:
- c3
- c3x
jobs:
update_tinygrad:
name: Update Tinygrad
runs-on:
- self-hosted
- ${{ github.event.inputs.runner }}
steps:
- name: Get version
id: get_version
run: |
VERSION=$(grep -oP '^VERSION\s*=\s*"\K[^"]+' /data/openpilot/frogpilot/assets/model_manager.py)
echo "VERSION=$VERSION"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Clone GitLab repo
env:
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
run: |
rm -rf /data/tmp/frogpilot_tinygrad
mkdir -p /data/tmp/frogpilot_tinygrad
cd /data/tmp/frogpilot_tinygrad
git clone --depth 1 --branch Tinygrad "https://oauth2:${GITLAB_TOKEN}@gitlab.com/FrogAi/FrogPilot-Resources.git"
- name: Create Tinygrad Archive
run: |
set -euo pipefail
cd /data/openpilot
ARCHIVE_DIR="/data/tmp/frogpilot_tinygrad/FrogPilot-Resources"
ARCHIVE_NAME="Tinygrad_${{ steps.get_version.outputs.version }}.tar.gz"
TMPDIR="$(mktemp -d)"
touch "$TMPDIR/SConscript"
tar -czf "$ARCHIVE_NAME" \
--exclude="*.a" \
--exclude="*.o" \
--exclude="*.onnx" \
--exclude="*__pycache__*" \
--exclude="*tests*" \
--exclude="frogpilot/tinygrad_modeld/SConscript" \
frogpilot/tinygrad_modeld tinygrad_repo \
-C "$TMPDIR" \
--transform 's|^SConscript$|frogpilot/tinygrad_modeld/SConscript|' \
SConscript
mv "$ARCHIVE_NAME" "$ARCHIVE_DIR/"
rm -rf "$TMPDIR"
- name: Push updated Tinygrad
run: |
cd /data/tmp/frogpilot_tinygrad/FrogPilot-Resources
git config user.name "James"
git config user.email "91348155+FrogAi@users.noreply.github.com"
git add Tinygrad_*.tar.gz
git commit -m "Updated Tinygrad: ${{ steps.get_version.outputs.version }}" || echo "No changes to commit"
git push origin Tinygrad
- name: Cleanup temporary files
run: |
rm -rf /data/tmp/frogpilot_tinygrad
+206 -182
View File
@@ -1,9 +1,33 @@
[![openpilot on the comma 3X](https://i.imgur.com/Zwv9SaN.png)](https://comma.ai/shop/comma-3x)
<div align="center" style="text-align: center;">
What is openpilot?
------
<h1>openpilot</h1>
[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW), and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models, and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera-based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md).
<p>
<b>openpilot is an operating system for robotics.</b>
<br>
Currently, it upgrades the driver assistance system in 300+ supported cars.
</p>
<h3>
<a href="https://docs.comma.ai">Docs</a>
<span> · </span>
<a href="https://docs.comma.ai/contributing/roadmap/">Roadmap</a>
<span> · </span>
<a href="https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md">Contribute</a>
<span> · </span>
<a href="https://discord.comma.ai">Community</a>
<span> · </span>
<a href="https://comma.ai/shop">Try it on a comma 3X</a>
</h3>
Quick start: `bash <(curl -fsSL openpilot.comma.ai)`
[![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg)](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![X Follow](https://img.shields.io/twitter/follow/comma_ai)](https://x.com/comma_ai)
[![Discord](https://img.shields.io/discord/469524606043160576)](https://discord.comma.ai)
</div>
<table>
<tr>
@@ -13,216 +37,216 @@ What is openpilot?
</tr>
</table>
What is FrogPilot? 🐸
Using openpilot in a car
------
FrogPilot is a fully open-sourced fork of openpilot, featuring clear and concise commits striving to be a resource for the openpilot developer community. It thrives on contributions from both users and developers, focusing on a collaborative, community-led approach to deliver an advanced openpilot experience for everyone!
To use openpilot in a car, you need four things:
1. **Supported Device:** a comma 3/3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x).
2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version.
3. **Supported Car:** Ensure that you have one of [the 275+ supported cars](docs/CARS.md).
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car.
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup). Note that it's possible to run openpilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play.
------
FrogPilot was last updated on:
**April 12th, 2025**
<div align="center" style="text-align: center;">
Features
------
<h1>FrogPilot 🐸</h1>
FrogPilot offers a wide range of customizable features that are easily toggled on or off to suit your preferences. Whether you want a completely stock openpilot experience, or want to add some fun and personal touches, FrogPilot has you covered! Some of the features include:
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/FrogAi/FrogPilot)
[![Discord](https://img.shields.io/discord/1137853399715549214?label=Discord)](https://discord.frogpilot.download)
[![Last Updated](https://img.shields.io/badge/Last%20Updated-August%209th%2C%202025-brightgreen)](https://github.com/FrogAi/FrogPilot/releases/latest)
[![Wiki](https://img.shields.io/badge/Wiki-FrogPilot-blue?logo=wiki)](https://frogpilot.wiki.gg/)
</div>
------
**Advanced Customizations:**
- "Alert Volume Controller" to set the volume level for each of of openpilot's sounds
- Customize the following distance and jerk values for each personality profile
- Fine tune your car's "Steer Ratio" to perfect your lateral control
- Increase the distance when stopped behind lead vehicles
- Increase the max set speed by a custom interval (i.e. 2, 3, 4, 5, 6, etc. instead of just 1)
- Select between past, present, and future openpilot driving models
------
🎨 **Custom Themes:**
**FrogPilot** is a custom frog-themed fork of openpilot that embraces a collaborative, community-driven approach to push the project forward. It delivers bleeding-edge features and experimental improvements far ahead of official releases. As an unofficial and highly experimental version of openpilot, **FrogPilot** should always be used with caution!
- 🐸 Frog theme (with a bonus 🐐 sound effect)
- <img src="https://images.emojiterra.com/google/noto-emoji/unicode-15/color/512px/1f1f7-1f1fa.png" width="15" height="12"> Russia / Joseph Stalin theme
- 🔌 Tesla theme
- Holiday themes! Minor holidays last a day, while major holidays (Easter, Halloween, Thanksgiving, Christmas) last a week
- Random events triggered by specific actions while driving with openpilot
- 📢 Want to add a theme? Request one in the "feature-request" channel in the FrogPilot Discord!
------
🚀 **Conditional Experimental Mode:**
- Auto-activates "Experimental Mode" under several conditions, including:
- Approaching intersections and turns while using navigation
- Approaching slower vehicles to take advantage of "Experimental Mode"'s smoother braking
- Curve and stop light/stop sign detection
- Driving below a set speed
- Turn signal activation below 55mph for turn assistance
------
📊 **Developer UI:**
- Display various driving logics such as the distance, speed, and the desired following distance to your lead vehicle
- Lane measuring of the adjacent lanes for lane detection
- Tap the "VEHICLE ONLINE"/"CPU"/"GPU" gauge to toggle between CPU and GPU monitoring
- Tap the "CONNECT ONLINE"/"MEMORY"/"LEFT"/"USED" gauge to toggle between RAM and storage monitoring
------
🛠 **Device Management:**
- Adjustable screen brightness for both onroad and offroad states
- Adjustable screen timeout times for both onroad and offroad states
- Backup and restore previous versions of FrogPilot
- Backup and restore previous versions of toggle configurations
- Battery level threshold to automatically shut the device down after you car's battery falls below a set voltage limit when offroad
- Delete stored driving data for increased privacy/space via the "Device" panel
- Device can operate offline indefinitely
- Disable logging and/or uploading
- Disable uploads while onroad to help reduce data usage
- Flash the Panda within the "Device" menu
- "Standby Mode" that wakes the screen up between engagement states or when important alerts are triggered
- Timer to automatically shut down after going offroad
------
🚖 **Lateral Adjustments:**
- Activate lateral control by simply pressing the "Cruise Control" button
- Force comma's auto tuning for unsupported vehicles
- Lateral control won't disengage on gas or brake
- Nudgeless lane changes with lane detection to prevent driving into curbs or going offroad
- Pause lateral control when below a set speed
- Pause lateral control when pressing the brake
- Pause lateral control when turn signals are active
- Precise turns by using turn desires when below the minimum lane change speed
- [Twilsonco's NNFF](https://github.com/twilsonco/openpilot) for smoother steering control
------
🚘 **Longitudinal Adjustments:**
- Aggressive acceleration when following a lead vehicle from a stop
- "Map Turn Speed Controller" to slow down for curves based on stored map data
- With an additional toggle to fine tune the speed aggressiveness
- Smoother braking behind slower leads
- "Speed Limit Controller" to adjust your speed to the posted speed limit
- With additional toggles to set offsets for "0-34 mph", "35-54 mph", "55-64 mph", and "65-99 mph"
- "Sport" and "Eco" acceleration and deceleration profiles
- "Traffic Mode" tailored towards driving in traffic
- Tweak the lead detection threshold to detect leads sooner for smoother braking on stopped/slower vehicles
- "Vision Turn Speed Controller" for smoother handling of curves
- With additional toggles to fine tune the speed aggressiveness and curve detection sensitivity
------
🗺️ **Navigation:**
- 3D buildings
- Custom map styles
- Full screen map that takes up the entire screen for a more expansive map view
- iOS shortcuts to quickly set navigation destinations
- Navigate on openpilot without a comma prime subscription
- Offline maps
- "Open Street Maps" integration for speed limit control and road name view
------
🎮 **Onroad UI:**
- Compass that rotates according to the direction you're driving
- FPS counter in the screen's border
- Hide various UI elements on the screen for a cleaner UI
- Pedals on the onroad UI indicate when the gas/brake pedals are being used
- Road UI Customizations:
- Acceleration path to show the model's desired acceleration/deceleration
- Blind spot path when a vehicle is detected in your blind spot
- Increase/decrease the lane line, path, and road edge widths
- Path edge colors based on specific driving statuses:
- 🔵 Blue - Navigation active
- 🟦 Light Blue - "Always On Lateral" active
- 🟢 Green - Default
- 🟠 Orange - "Experimental Mode" active
- 🔴 Red - "Traffic Mode" active
- 🟡 Yellow - "Conditional Experimental Mode" overridden
- "Unlimited" road UI that extends out as far as the model can see
- Sidebar retains it's previous position between reboots/ignition cycles
- Steering wheel icons
- 📢 Request your own steering wheel icon in the "feature-request" channel!
- Steering wheel in the onroad UI rotates alongside your physical steering wheel
------
🚙 **Vehicle Specific Additions:**
- Automatic/manual fingerprint selection to force a selected fingerprint
- Custom longitudinal tunings for GM EVs and trucks for smoother gas and brake control
- Custom longitudinal tunings for Toyota/Lexus for smoother gas and brake control
- Disable openpilot longitudinal control to use your car's stock cruise control
- GM Volt support
- Honda Clarity support
- Increased torque for the Subaru Crosstrek
- Lock doors automatically when in the drive gear for Toyota/Lexus and unlock when in park
- openpilot longitudinal control for GM vehicles without ACC
- Pedal interceptor support for GM vehicles
- "Stop and Go" hack for Toyota's without stop and go functionality
- ZSS support for the Toyota Prius and Sienna
------
🚦 **Quality of Life Features:**
- Automatic updates for a completely "set and forget" experience
- Camera view selection
- Custom alerts for green lights, vehicles in blindspot, lead departing, and the current speed limit changing
- Display the driver camera when in reverse
- Driving statistics to show how many hours and miles you've driven on the home screen
- Fleet Manager to easily access your driving data and screen recordings
- Numerical temperature gauge
- Retain tethering status between reboots
- Screenrecorder
- Toggle "Experimental Mode" via the "Lane Departure Alert" button, holding down the "Distance" button for 0.5+ seconds, or by double tapping the screen
How to Install
openpilot vs **FrogPilot**
------
Easiest way to install FrogPilot is via this URL at the installation screen:
#### Community
| Feature | openpilot | **FrogPilot** |
|---------|:---------:|:---------:|
| A Welcoming Community | ❌ | ✅ |
| Erich / Primary Moderators / 🦇 | ✅ | ❌ |
#### Core Features
| Feature | openpilot | **FrogPilot** |
|---------|:---------:|:---------:|
| Always On Lateral (Steering) | ❌ | ✅ |
| Blind Spot Integration | ✅ | ✅ |
| Conditional Experimental Mode | ❌ | ✅ |
| Custom Themes | ❌ | ✅ |
| Driver Monitoring | ✅ | ✅ |
| Driving Model Selector | ❌ | ✅ |
| Holiday Themes | ❌ | ✅ |
| Speed Limit Support | ❌ | ✅ |
| Weather Detection | ❌ | ✅ |
#### Device & Hardware
| Feature | openpilot | **FrogPilot** |
|---------|:---------:|:---------:|
| Advanced Volume Controller | ❌ | ✅ |
| Automatic Version Backups | ❌ | ✅ |
| C3 Support | ❌ | ✅ |
| comma Pedal Support | ❌ | ✅ |
| High Quality Recordings | ❌ | ✅ |
| SDSU Support | ❌ | ✅ |
| ZSS Support | ❌ | ✅ |
#### Gas/Brake
| Feature | openpilot | **FrogPilot** |
|---------|:---------:|:---------:|
| Adaptive Cruise Control (ACC) | ✅ | ✅ |
| Advanced Live Tuning | ❌ | ✅ |
| Custom Following Distances | ❌ | ✅ |
| Faster Human-Like Acceleration | ❌ | ✅ |
| Human-Like Speed Control in Curves | ❌ | ✅ |
| Smoother Human-Like Braking | ❌ | ✅ |
#### Steering
| Feature | openpilot | **FrogPilot** |
|---------|:---------:|:---------:|
| Advanced Live Tuning | ❌ | ✅ |
| Automatic Lane Changes | ❌ | ✅ |
| Increased Steering Torque* | ❌ | ✅ |
| Lane Centering (LKAS) | ✅ | ✅ |
| Lane Change Assist | ✅ | ✅ |
*Select vehicles only
And much much more!
🌟 Highlight Features
------
### 🚗 Always On Lateral (AOL)
With **"Always On Lateral"**, lane-centering stays active whenever cruise control is on, even when you press the accelerator or brake. This means steering assist won't cut out during manual speed adjustments giving you continuous support through curves, traffic, or mountain roads!
---
### 🧠 Conditional Experimental Mode (CEM)
**["Experimental Mode"](https://blog.comma.ai/090release/#experimental-mode)** lets openpilot drive at the speed it thinks a human would to allow slowing for curves, stopping at stoplights/stop signs, and adapting to traffic. This makes it powerful in complex scenarios, but it's still, well, "experimental" and less predictable than **"Chill Mode"**. But **"Conditional Experimental Mode"** gives you the best of both worlds by automatically switching between **"Chill Mode"** for steady cruising and **"Experimental Mode"** for more advanced situations to help fully automate your driving experience!
**"Conditional Experimental Mode"** switches into **"Experimental Mode"** when conditions like these are met:
- Approaching curves and turns
- Detecting slower or stopped lead vehicles
- Driving below a set speed
- Predicting an upcoming stop (e.g. stoplight or stop sign)
Once conditions clear it returns to **"Chill Mode"** for stability and predictability.
**Note: Stay attentive as "Experimental Mode" is an alpha feature and mistakes are expected!**
---
### 🎭 Driving Personalities
With **"Driving Personalities"**, you choose how the vehicle behaves with four adjustable profiles:
- **Traffic:** Catered towards stop-and-go traffic by minimizing gaps and delays
- **Aggressive:** Aimed to provide tighter following distances and quicker reactions
- **Standard:** Useful for a balanced, all-purpose driving
- **Relaxed:** A smoother driving experience with larger following distance gaps
Each profile can be fine-tuned to change the desired following distance, acceleration, and braking style letting you shape **FrogPilot**'s behavior to match your own driving preferences! Profiles can be switched instantly using the following distance button on the steering wheel, while **"Traffic Mode"** can be enabled by simply holding down the following distance button.
---
### 📏 Speed Limit Controller (SLC)
With **"Speed Limit Controller"**, **FrogPilot** automatically adapts to the road's posted speed using information from downloaded **["OpenStreetMap"](https://www.openstreetmap.org)** maps, online **["Mapbox"](https://www.mapbox.com)** data, and the vehicle's dashboard (if supported).
Offsets let you fine-tune how closely **FrogPilot** follows posted limits across different speed ranges allowing you to cruise slightly above or below for a more natural driving experience. If no speed limit is available, you can choose whether **FrogPilot** drives at the set speed, falls back to the last known speed limit, or uses **"Experimental Mode"** to estimate one with the driving model.
Maps can be downloaded directly in settings and updated automatically on a schedule ensuring your device always has the latest speed limits!
**Note: Speed limits are only as accurate as the available speed limit data. Always stay attentive and adjust your speed when necessary!**
---
### 🎨 Themes
With **"Themes"**, you can personalize **FrogPilot**'s driving screen to make it uniquely yours! Choose from:
- **Color Schemes**
- **Icon Packs**
- **Sound Packs**
- **Turn Signal Animations**
- **Steering Wheel Icons**
Enjoy pre-existing **FrogPilot** and seasonal holiday themes, or you can create your own with the **"Theme Maker"** and even share them with the community! For extra fun, enable features like the Mario Kartstyle **"Rainbow Path"** or **"Random Events"** that add playful visual effects while you drive!
---
And lots more! From safety enhancements to personalization options, **FrogPilot** continues to evolve with features that put you in control. Check it out today for yourself!
---
🔧 Branches
------
| Branch | Install&nbsp;URL | Description | Recommended&nbsp;For |
|----------------------------|---------------------------|--------------------------------------------------------|--------------------------|
| FrogPilot | frogpilot.download | The main release branch. | Everyone |
| FrogPilot&#8209;Staging | staging.frogpilot.download| Beta branch with upcoming features. Expect bugs! | Early&nbsp;Adopters |
| FrogPilot&#8209;Testing | testing.frogpilot.download| Alpha branch with bleeding-edge features. Breaks often!| Advanced&nbsp;Testers |
| FrogPilot&#8209;Development| No :) | Active development branch. Don't use! | **FrogPilot**&nbsp;Developers|
| MAKE&#8209;PRS&#8209;HERE | No :) | Workspace for pull requests. Don't use! | Contributors |
🧰 How to Install
------
The easiest way to install **FrogPilot** is by entering this URL on the installation screen:
```
frogpilot.download
```
DO NOT install the "FrogPilot-Development" branch. I'm constantly breaking things on there, so unless you don't want to use openpilot, NEVER install it!
**DO NOT** install the **FrogPilot-Development** branch. I'm constantly breaking things on there, so unless you don't want to use **FrogPilot**, **NEVER** install it!
![](https://i.imgur.com/swr0kqJ.png)
![](https://i.imgur.com/LTCqRqB.png)
Bug reports / Feature Requests
🐞 Bug Reports / Feature Requests
------
If you encounter any issues or bugs while using FrogPilot, or if you have any suggestions for new features or improvements, please don't hesitate to post about it on the Discord! I'm always looking for ways to improve the fork and provide a better experience for everyone!
If you run into bugs, issues, or have ideas for new features, please post about it on the **[FrogPilot Discord](https://discord.gg/frogpilot)**! Feedback helps improve **FrogPilot** and create a better experience for everyone!
To report a bug or request a new feature, make a post in the #bug-reports or #feature-requests channel respectively on the FrogPilot Discord. Please provide as much detail as possible about the issue you're experiencing or the feature you'd like to see added. Photos, videos, log files, or other relevant information are very helpful!
To report a bug, please post it in [**#bug-reports**](https://discord.com/channels/1137853399715549214/1162100167110053888).
To request a feature, please post it in [**#feature-requests**](https://discord.com/channels/1137853399715549214/1160318669839147259).
I will do my best to respond to bug reports and feature requests in a timely manner, but please understand that I may not be able to address every request immediately. Your feedback and suggestions are valuable, and I appreciate your help in making FrogPilot the best it can be!
Please include as much detail as possible! Photos, videos, log files, or anything that can help explain the issue or idea are very helpful!
Discord
------
I'll do my best to respond promptly, but not every request can be addressed right away. Your feedback is always appreciated and helps make **FrogPilot** the best it can be!
[Join the FrogPilot Community Discord!](https://discord.gg/frogpilot)
Credits
📋 Credits
------
* [Aidenir](https://github.com/Aidenir)
* [AlexandreSato](https://github.com/AlexandreSato)
* [Crwusiz](https://github.com/crwusiz)
* [DragonPilot](https://github.com/dragonpilot-community)
* [cfranyota](https://github.com/cfranyota)
* [cydia2020](https://github.com/cydia2020)
* [dragonpilot-community](https://github.com/dragonpilot-community)
* [ErichMoraga](https://github.com/ErichMoraga)
* [Garrettpall](https://github.com/garrettpall)
* [Mike8643](https://github.com/mike8643)
* [Neokii](https://github.com/Neokii)
* [garrettpall](https://github.com/garrettpall)
* [jakethesnake420](https://github.com/jakethesnake420)
* [jyoung8607](https://github.com/jyoung8607)
* [mike8643](https://github.com/mike8643)
* [neokii](https://github.com/neokii)
* [OPGM](https://github.com/opgm)
* [OPKR](https://github.com/openpilotkr)
* [Pfeiferj](https://github.com/pfeiferj)
* [ServerDummy](https://github.com/ServerDummy)
* [Twilsonco](https://github.com/twilsonco)
* [pfeiferj](https://github.com/pfeiferj)
* [realfast](https://github.com/realfast)
* [syncword](https://github.com/syncword)
* [twilsonco](https://github.com/twilsonco)
Licensing
Star History
------
openpilot is released under the MIT license. Some parts of the software are released under other licenses as specified.
Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys fees and costs) which arise out of, relate to or result from any use of this software by user.
**THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
NO WARRANTY EXPRESSED OR IMPLIED.**
---
<img src="https://d1qb2nb5cznatu.cloudfront.net/startups/i/1061157-bc7e9bf3b246ece7322e6ffe653f6af8-medium_jpg.jpg?buster=1458363130" width="75"></img> <img src="https://cdn-images-1.medium.com/max/1600/1*C87EjxGeMPrkTuVRVWVg4w.png" width="225"></img>
![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg)
[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot)
[![Star History Chart](https://api.star-history.com/svg?repos=FrogAi/FrogPilot&type=Date)](https://www.star-history.com/#FrogAi/FrogPilot&Date)
+3 -49
View File
@@ -118,37 +118,6 @@ struct CarEvent @0x9b1657f34caf3ad3 {
paramsdPermanentError @119;
actuatorsApiUnavailable @120;
# FrogPilot Events
accel30 @122;
accel35 @123;
accel40 @124;
blockUser @125;
customStartupAlert @126;
dejaVuCurve @127;
firefoxSteerSaturated @128;
forcingStop @129;
goatSteerSaturated @130;
greenLight @131;
hal9000 @132;
holidayActive @133;
laneChangeBlockedLoud @134;
leadDeparting @135;
noLaneAvailable @136;
openpilotCrashed @137;
openpilotCrashedRandomEvent @138;
pedalInterceptorNoBrake @139;
speedLimitChanged @140;
thisIsFineSteerSaturated @141;
toBeContinued @142;
torqueNNLoad @143;
trafficModeActive @144;
trafficModeInactive @145;
turningLeft @146;
turningRight @147;
vCruise69 @148;
yourFrogTriedToKillMe @149;
youveGotMail @150;
radarCanErrorDEPRECATED @15;
communityFeatureDisallowedDEPRECATED @62;
radarCommIssueDEPRECATED @67;
@@ -444,22 +413,6 @@ struct CarControl {
prompt @6;
promptRepeat @7;
promptDistracted @8;
# FrogPilot sounds
angry @9;
continued @10;
dejaVu @11;
doc @12;
fart @13;
firefox @14;
goat @15;
hal9000 @16;
mail @17;
nessie @18;
noice @19;
startup @20;
thisIsFine @21;
uwu @22;
}
}
@@ -579,11 +532,12 @@ struct CarParams {
useSteeringAngle @0 :Bool;
kp @1 :Float32;
ki @2 :Float32;
kd @8 : Float32;
friction @3 :Float32;
kf @4 :Float32;
steeringAngleDeadzoneDeg @5 :Float32;
latAccelFactor @6 :Float32;
latAccelOffset @7 :Float32;
kfDEPRECATED @4 :Float32;
}
struct LongitudinalPIDTuning {
@@ -591,7 +545,7 @@ struct CarParams {
kpV @1 :List(Float32);
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
kf @6 :Float32;
kfDEPRECATED @6 :Float32;
deadzoneBP @4 :List(Float32);
deadzoneV @5 :List(Float32);
}
+198 -54
View File
@@ -10,18 +10,109 @@ using Car = import "car.capnp";
# cereal, so use these if you want custom events in your fork.
# you can rename the struct, but don't change the identifier
struct FrogPilotCarParams @0x81c2f05a394cf4af {
fpFlags @0 :UInt32;
openpilotLongitudinalControlDisabled @1 :Bool;
}
struct FrogPilotCarControl {
hudControl @0 :HUDControl;
struct FrogPilotCarState @0xaedffd8f31e7b55d {
struct ButtonEvent {
enum Type {
lkas @0;
struct HUDControl {
audibleAlert @0 :AudibleAlert;
enum AudibleAlert {
none @0;
engage @1;
disengage @2;
refuse @3;
warningSoft @4;
warningImmediate @5;
prompt @6;
promptRepeat @7;
promptDistracted @8;
# Random Events
angry @9;
continued @10;
dejaVu @11;
doc @12;
fart @13;
firefox @14;
goat @15;
hal9000 @16;
mail @17;
nessie @18;
noice @19;
startup @20;
thisIsFine @21;
uwu @22;
}
}
}
struct FrogPilotCarEvent @0x81c2f05a394cf4af {
name @0 :EventName;
enable @1 :Bool;
noEntry @2 :Bool;
warning @3 :Bool;
userDisable @4 :Bool;
softDisable @5 :Bool;
immediateDisable @6 :Bool;
preEnable @7 :Bool;
permanent @8 :Bool;
overrideLateral @10 :Bool;
overrideLongitudinal @9 :Bool;
enum EventName @0xaedffd8f31e7b55d {
blockUser @0;
customStartupAlert @1;
forcingStop @2;
goatSteerSaturated @3;
greenLight @4;
holidayActive @5;
laneChangeBlockedLoud @6;
leadDeparting @7;
noLaneAvailable @8;
openpilotCrashed @9;
pedalInterceptorNoBrake @10;
speedLimitChanged @11;
torqueNNLoad @12;
trafficModeActive @13;
trafficModeInactive @14;
turningLeft @15;
turningRight @16;
# Random Events
accel30 @17;
accel35 @18;
accel40 @19;
dejaVuCurve @20;
firefoxSteerSaturated @21;
hal9000 @22;
openpilotCrashedRandomEvent @23;
thisIsFineSteerSaturated @24;
toBeContinued @25;
vCruise69 @26;
yourFrogTriedToKillMe @27;
youveGotMail @28;
}
}
struct FrogPilotCarParams @0xf35cc4560bbf6ec2 {
canUsePedal @0 :Bool;
canUseSDSU @1 :Bool;
fpFlags @2 :UInt32;
isHDA2 @3 :Bool;
openpilotLongitudinalControlDisabled @4 :Bool;
safetyConfigs @5 :List(SafetyConfig);
canUseSASCM @6 :Bool;
struct SafetyConfig {
safetyParam @0 :UInt16;
}
}
struct FrogPilotCarState @0xda96579883444c35 {
accelPressed @0 :Bool;
alwaysOnLateralAllowed @1 :Bool;
alwaysOnLateralEnabled @2 :Bool;
@@ -36,67 +127,120 @@ struct FrogPilotCarState @0xaedffd8f31e7b55d {
pauseLateral @11 :Bool;
pauseLongitudinal @12 :Bool;
sportGear @13 :Bool;
trafficMode @14 :Bool;
trafficModeEnabled @14 :Bool;
struct ButtonEvent {
enum Type {
lkas @0;
}
}
}
struct FrogPilotDeviceState @0xf35cc4560bbf6ec2 {
struct FrogPilotControlsState @0x80ae746ee2596b11 {
alertStatus @0 :AlertStatus;
alertText1 @1 :Text;
alertText2 @2 :Text;
alertSize @3 :AlertSize;
alertBlinkingRate @4 :Float32;
alertType @5 :Text;
alertSound @6 :Car.CarControl.HUDControl.AudibleAlert;
enum AlertSize {
none @0; # don't display the alert
small @1; # small box
mid @2; # mid screen
full @3; # full screen
}
enum AlertStatus {
normal @0; # low priority alert for user's convenience
userPrompt @1; # mid priority alert that might require user intervention
critical @2; # high priority alert that needs immediate user intervention
frogpilot @3; # FrogPilot startup alert
}
}
struct FrogPilotDeviceState @0xa5cd762cd951a455 {
freeSpace @0 :Int16;
usedSpace @1 :Int16;
}
struct FrogPilotNavigation @0xda96579883444c35 {
struct FrogPilotModelDataV2 @0xf98d843bfd7004a3 {
turnDirection @0 :TurnDirection;
enum TurnDirection {
none @0;
turnLeft @1;
turnRight @2;
}
}
struct FrogPilotNavigation @0xf416ec09499d9d19 {
approachingIntersection @0 :Bool;
approachingTurn @1 :Bool;
navigationSpeedLimit @2 :Float32;
}
struct FrogPilotPlan @0x80ae746ee2596b11 {
struct FrogPilotPlan @0xa1680744031fdb2d {
accelerationJerk @0 :Float32;
accelerationJerkStock @1 :Float32;
dangerJerk @2 :Float32;
desiredFollowDistance @3 :Int64;
experimentalMode @4 :Bool;
forcingStop @5 :Bool;
forcingStopLength @6 :Float32;
frogpilotEvents @7 :List(Car.CarEvent);
lateralCheck @8 :Bool;
laneWidthLeft @9 :Float32;
laneWidthRight @10 :Float32;
maxAcceleration @11 :Float32;
minAcceleration @12 :Float32;
mtscSpeed @13 :Float32;
redLight @14 :Bool;
roadCurvature @15 :Float32;
slcMapSpeedLimit @16 :Float32;
slcMapboxSpeedLimit @17 :Float32;
slcNextSpeedLimit @18 :Float32;
slcOverridden @19 :Bool;
slcOverriddenSpeed @20 :Float32;
slcSpeedLimit @21 :Float32;
slcSpeedLimitOffset @22 :Float32;
slcSpeedLimitSource @23 :Text;
speedJerk @24 :Float32;
speedJerkStock @25 :Float32;
speedLimitChanged @26 :Bool;
tFollow @27 :Float32;
togglesUpdated @28 :Bool;
unconfirmedSlcSpeedLimit @29 :Float32;
vCruise @30 :Float32;
vtscControllingCurve @31 :Bool;
vtscSpeed @32 :Float32;
cscControllingSpeed @2 :Bool;
cscSpeed @3 :Float32;
cscTraining @4 :Bool;
dangerJerk @5 :Float32;
desiredFollowDistance @6 :Int64;
disableThrottle @7 :Bool;
experimentalMode @8 :Bool;
forcingStop @9 :Bool;
forcingStopLength @10 :Float32;
frogpilotEvents @11 :List(FrogPilotCarEvent);
increasedStoppedDistance @12 :Float32;
lateralCheck @13 :Bool;
laneWidthLeft @14 :Float32;
laneWidthRight @15 :Float32;
maxAcceleration @16 :Float32;
minAcceleration @17 :Float32;
redLight @18 :Bool;
roadCurvature @19 :Float32;
slcMapSpeedLimit @20 :Float32;
slcMapboxSpeedLimit @21 :Float32;
slcNextSpeedLimit @22 :Float32;
slcOverriddenSpeed @23 :Float32;
slcSpeedLimit @24 :Float32;
slcSpeedLimitOffset @25 :Float32;
slcSpeedLimitSource @26 :Text;
speedJerk @27 :Float32;
speedJerkStock @28 :Float32;
speedLimitChanged @29 :Bool;
tFollow @30 :Float32;
themeUpdated @31 :Bool;
togglesUpdated @32 :Bool;
trackingLead @33 :Bool;
unconfirmedSlcSpeedLimit @34 :Float32;
vCruise @35 :Float32;
}
struct CustomReserved5 @0xa5cd762cd951a455 {
}
struct FrogPilotRadarState @0xcb9fd56c7057593a {
leadLeft @0 :LeadData;
leadRight @1 :LeadData;
struct CustomReserved6 @0xf98d843bfd7004a3 {
}
struct LeadData {
dRel @0 :Float32;
yRel @1 :Float32;
vRel @2 :Float32;
aRel @3 :Float32;
vLead @4 :Float32;
dPath @6 :Float32;
vLat @7 :Float32;
vLeadK @8 :Float32;
aLeadK @9 :Float32;
fcw @10 :Bool;
status @11 :Bool;
aLeadTau @12 :Float32;
modelProb @13 :Float32;
radar @14 :Bool;
radarTrackId @15 :Int32 = -1;
struct CustomReserved7 @0xb86e6369214c01c8 {
}
struct CustomReserved8 @0xf416ec09499d9d19 {
}
struct CustomReserved9 @0xa1680744031fdb2d {
aLeadDEPRECATED @5 :Float32;
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1556 -968
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
+62 -22
View File
@@ -335,12 +335,6 @@ enum LaneChangeDirection {
right @2;
}
enum TurnDirection {
none @0;
turnLeft @1;
turnRight @2;
}
struct CanData {
address @0 :UInt32;
busTime @1 :UInt16;
@@ -618,8 +612,6 @@ struct RadarState @0x9a185389d6fdd05f {
leadOne @3 :LeadData;
leadTwo @4 :LeadData;
leadLeft @13 :LeadData;
leadRight @14 :LeadData;
cumLagMs @5 :Float32;
struct LeadData {
@@ -753,7 +745,6 @@ struct ControlsState @0x97ff69c53601abf1 {
normal @0; # low priority alert for user's convenience
userPrompt @1; # mid priority alert that might require user intervention
critical @2; # high priority alert that needs immediate user intervention
frogpilot @3; # FrogPilot startup alert
}
enum AlertSize {
@@ -804,7 +795,8 @@ struct ControlsState @0x97ff69c53601abf1 {
saturated @7 :Bool;
actualLateralAccel @9 :Float32;
desiredLateralAccel @10 :Float32;
nnLog @11 :List(Float32);
desiredLateralJerk @11 :Float32;
version @12 :Int32;
}
struct LateralLQRState {
@@ -907,7 +899,6 @@ struct DrivingModelData {
struct MetaData {
laneChangeState @0 :LaneChangeState;
laneChangeDirection @1 :LaneChangeDirection;
turnDirection @2 :TurnDirection;
}
}
@@ -1001,7 +992,6 @@ struct ModelDataV2 {
hardBrakePredicted @7 :Bool;
laneChangeState @8 :LaneChangeState;
laneChangeDirection @9 :LaneChangeDirection;
turnDirection @10 :TurnDirection;
# deprecated
@@ -1269,6 +1259,38 @@ struct LiveLocationKalman {
}
}
struct LivePose {
# More info on reference frames:
# https://github.com/commaai/openpilot/tree/master/common/transformations
orientationNED @0 :XYZMeasurement;
velocityDevice @1 :XYZMeasurement;
accelerationDevice @2 :XYZMeasurement;
angularVelocityDevice @3 :XYZMeasurement;
inputsOK @4 :Bool = false;
posenetOK @5 :Bool = false;
sensorsOK @6 :Bool = false;
filterState @7 :FilterState;
struct XYZMeasurement {
x @0 :Float32;
y @1 :Float32;
z @2 :Float32;
xStd @3 :Float32;
yStd @4 :Float32;
zStd @5 :Float32;
valid @6 :Bool;
}
struct FilterState {
value @0 : List(Float64);
std @1 : List(Float64);
valid @2 : Bool;
}
}
struct ProcLog {
cpuTimes @0 :List(CPUTimes);
mem @1 :Mem;
@@ -2089,6 +2111,22 @@ struct LiveTorqueParametersData {
useParams @12 :Bool;
}
struct LiveDelayData {
lateralDelay @0 :Float32;
validBlocks @1 :Int32;
status @2 :Status;
lateralDelayEstimate @3 :Float32;
lateralDelayEstimateStd @5 :Float32;
points @4 :List(Float32);
enum Status {
unestimated @0;
estimated @1;
invalid @2;
}
}
struct LiveMapDataDEPRECATED {
speedLimitValid @0 :Bool;
speedLimit @1 :Float32;
@@ -2305,12 +2343,14 @@ struct Event {
gnssMeasurements @91 :GnssMeasurements;
liveParameters @61 :LiveParametersData;
liveTorqueParameters @94 :LiveTorqueParametersData;
liveDelay @130 : LiveDelayData;
cameraOdometry @63 :CameraOdometry;
thumbnail @66: Thumbnail;
onroadEvents @68: List(Car.CarEvent);
carParams @69: Car.CarParams;
driverMonitoringState @71: DriverMonitoringState;
liveLocationKalman @72 :LiveLocationKalman;
livePose @129 :LivePose;
modelV2 @75 :ModelDataV2;
drivingModelData @128 :DrivingModelData;
driverStateV2 @92 :DriverStateV2;
@@ -2367,16 +2407,16 @@ struct Event {
customReservedRawData2 @126 :Data;
# *********** Custom: reserved for forks ***********
frogpilotCarParams @107 :Custom.FrogPilotCarParams;
frogpilotCarState @108 :Custom.FrogPilotCarState;
frogpilotDeviceState @109 :Custom.FrogPilotDeviceState;
frogpilotNavigation @110 :Custom.FrogPilotNavigation;
frogpilotPlan @111 :Custom.FrogPilotPlan;
customReserved5 @112 :Custom.CustomReserved5;
customReserved6 @113 :Custom.CustomReserved6;
customReserved7 @114 :Custom.CustomReserved7;
customReserved8 @115 :Custom.CustomReserved8;
customReserved9 @116 :Custom.CustomReserved9;
frogpilotCarControl @107 :Custom.FrogPilotCarControl;
frogpilotCarParams @108 :Custom.FrogPilotCarParams;
frogpilotCarState @109 :Custom.FrogPilotCarState;
frogpilotControlsState @110 :Custom.FrogPilotControlsState;
frogpilotDeviceState @111 :Custom.FrogPilotDeviceState;
frogpilotModelV2 @112 :Custom.FrogPilotModelDataV2;
frogpilotNavigation @113 :Custom.FrogPilotNavigation;
frogpilotOnroadEvents @114: List(Custom.FrogPilotCarEvent);
frogpilotPlan @115 :Custom.FrogPilotPlan;
frogpilotRadarState @116 :Custom.FrogPilotRadarState;
# *********** legacy + deprecated ***********
model @9 :Legacy.ModelData; # TODO: rename modelV2 and mark this as deprecated
Binary file not shown.
+92
View File
@@ -0,0 +1,92 @@
#include <algorithm>
#include <cassert>
#include <csignal>
#include <iostream>
#include <map>
#include <string>
typedef void (*sighandler_t)(int sig);
#include "cereal/services.h"
#include "msgq/impl_msgq.h"
#include "msgq/impl_zmq.h"
std::atomic<bool> do_exit = false;
static void set_do_exit(int sig) {
do_exit = true;
}
void sigpipe_handler(int sig) {
assert(sig == SIGPIPE);
std::cout << "SIGPIPE received" << std::endl;
}
static std::vector<std::string> get_services(std::string whitelist_str, bool zmq_to_msgq) {
std::vector<std::string> service_list;
for (const auto& it : services) {
std::string name = it.second.name;
bool in_whitelist = whitelist_str.find(name) != std::string::npos;
if (name == "plusFrame" || name == "uiLayoutState" || (zmq_to_msgq && !in_whitelist)) {
continue;
}
service_list.push_back(name);
}
return service_list;
}
int main(int argc, char** argv) {
signal(SIGPIPE, (sighandler_t)sigpipe_handler);
signal(SIGINT, (sighandler_t)set_do_exit);
signal(SIGTERM, (sighandler_t)set_do_exit);
bool zmq_to_msgq = argc > 2;
std::string ip = zmq_to_msgq ? argv[1] : "127.0.0.1";
std::string whitelist_str = zmq_to_msgq ? std::string(argv[2]) : "";
Poller *poller;
Context *pub_context;
Context *sub_context;
if (zmq_to_msgq) { // republishes zmq debugging messages as msgq
poller = new ZMQPoller();
pub_context = new MSGQContext();
sub_context = new ZMQContext();
} else {
poller = new MSGQPoller();
pub_context = new ZMQContext();
sub_context = new MSGQContext();
}
std::map<SubSocket*, PubSocket*> sub2pub;
for (auto endpoint : get_services(whitelist_str, zmq_to_msgq)) {
PubSocket * pub_sock;
SubSocket * sub_sock;
if (zmq_to_msgq) {
pub_sock = new MSGQPubSocket();
sub_sock = new ZMQSubSocket();
} else {
pub_sock = new ZMQPubSocket();
sub_sock = new MSGQSubSocket();
}
pub_sock->connect(pub_context, endpoint);
sub_sock->connect(sub_context, endpoint, ip, false);
poller->registerSocket(sub_sock);
sub2pub[sub_sock] = pub_sock;
}
while (!do_exit) {
for (auto sub_sock : poller->poll(100)) {
Message * msg = sub_sock->receive();
if (msg == NULL) continue;
int ret;
do {
ret = sub2pub[sub_sock]->sendMessage(msg);
} while (ret == -1 && errno == EINTR && !do_exit);
assert(ret >= 0 || do_exit);
delete msg;
if (do_exit) break;
}
}
return 0;
}
+112
View File
@@ -0,0 +1,112 @@
#pragma once
#include <cstddef>
#include <map>
#include <string>
#include <vector>
#include <utility>
#include <time.h>
#include <capnp/serialize.h>
#include "cereal/gen/cpp/log.capnp.h"
#include "msgq/ipc.h"
#ifdef __APPLE__
#define CLOCK_BOOTTIME CLOCK_MONOTONIC
#endif
#define MSG_MULTIPLE_PUBLISHERS 100
class SubMaster {
public:
SubMaster(const std::vector<const char *> &service_list, const std::vector<const char *> &poll = {},
const char *address = nullptr, const std::vector<const char *> &ignore_alive = {});
void update(int timeout = 1000);
void update_msgs(uint64_t current_time, const std::vector<std::pair<std::string, cereal::Event::Reader>> &messages);
inline bool allAlive(const std::vector<const char *> &service_list = {}) { return all_(service_list, false, true); }
inline bool allValid(const std::vector<const char *> &service_list = {}) { return all_(service_list, true, false); }
inline bool allAliveAndValid(const std::vector<const char *> &service_list = {}) { return all_(service_list, true, true); }
void drain();
~SubMaster();
uint64_t frame = 0;
bool updated(const char *name) const;
bool alive(const char *name) const;
bool valid(const char *name) const;
uint64_t rcv_frame(const char *name) const;
uint64_t rcv_time(const char *name) const;
cereal::Event::Reader &operator[](const char *name) const;
private:
bool all_(const std::vector<const char *> &service_list, bool valid, bool alive);
Poller *poller_ = nullptr;
struct SubMessage;
std::map<SubSocket *, SubMessage *> messages_;
std::map<std::string, SubMessage *> services_;
};
class MessageBuilder : public capnp::MallocMessageBuilder {
public:
MessageBuilder() = default;
cereal::Event::Builder initEvent(bool valid = true) {
cereal::Event::Builder event = initRoot<cereal::Event>();
struct timespec t;
clock_gettime(CLOCK_BOOTTIME, &t);
uint64_t current_time = t.tv_sec * 1000000000ULL + t.tv_nsec;
event.setLogMonoTime(current_time);
event.setValid(valid);
return event;
}
kj::ArrayPtr<capnp::byte> toBytes() {
heapArray_ = capnp::messageToFlatArray(*this);
return heapArray_.asBytes();
}
size_t getSerializedSize() {
return capnp::computeSerializedSizeInWords(*this) * sizeof(capnp::word);
}
int serializeToBuffer(unsigned char *buffer, size_t buffer_size) {
size_t serialized_size = getSerializedSize();
if (serialized_size > buffer_size) { return -1; }
kj::ArrayOutputStream out(kj::ArrayPtr<capnp::byte>(buffer, buffer_size));
capnp::writeMessage(out, *this);
return serialized_size;
}
private:
kj::Array<capnp::word> heapArray_;
};
class PubMaster {
public:
PubMaster(const std::vector<const char *> &service_list);
inline int send(const char *name, capnp::byte *data, size_t size) { return sockets_.at(name)->send((char *)data, size); }
int send(const char *name, MessageBuilder &msg);
~PubMaster();
private:
std::map<std::string, PubSocket *> sockets_;
};
class AlignedBuffer {
public:
kj::ArrayPtr<const capnp::word> align(const char *data, const size_t size) {
words_size = size / sizeof(capnp::word) + 1;
if (aligned_buf.size() < words_size) {
aligned_buf = kj::heapArray<capnp::word>(words_size < 512 ? 512 : words_size);
}
memcpy(aligned_buf.begin(), data, size);
return aligned_buf.slice(0, words_size);
}
inline kj::ArrayPtr<const capnp::word> align(Message *m) {
return align(m->getData(), m->getSize());
}
private:
kj::Array<capnp::word> aligned_buf;
size_t words_size;
};
+211
View File
@@ -0,0 +1,211 @@
#include <time.h>
#include <assert.h>
#include <stdlib.h>
#include <string>
#include <mutex>
#include "cereal/services.h"
#include "cereal/messaging/messaging.h"
const bool SIMULATION = (getenv("SIMULATION") != nullptr) && (std::string(getenv("SIMULATION")) == "1");
static inline uint64_t nanos_since_boot() {
struct timespec t;
clock_gettime(CLOCK_BOOTTIME, &t);
return t.tv_sec * 1000000000ULL + t.tv_nsec;
}
static inline bool inList(const std::vector<const char *> &list, const char *value) {
for (auto &v : list) {
if (strcmp(value, v) == 0) return true;
}
return false;
}
class MessageContext {
public:
MessageContext() : ctx_(nullptr) {}
~MessageContext() { delete ctx_; }
inline Context *context() {
std::call_once(init_flag, [=]() { ctx_ = Context::create(); });
return ctx_;
}
private:
Context *ctx_;
std::once_flag init_flag;
};
MessageContext message_context;
struct SubMaster::SubMessage {
std::string name;
SubSocket *socket = nullptr;
int freq = 0;
bool updated = false, alive = false, valid = true, ignore_alive;
uint64_t rcv_time = 0, rcv_frame = 0;
void *allocated_msg_reader = nullptr;
bool is_polled = false;
capnp::FlatArrayMessageReader *msg_reader = nullptr;
AlignedBuffer aligned_buf;
cereal::Event::Reader event;
};
SubMaster::SubMaster(const std::vector<const char *> &service_list, const std::vector<const char *> &poll,
const char *address, const std::vector<const char *> &ignore_alive) {
poller_ = Poller::create();
for (auto name : service_list) {
assert(services.count(std::string(name)) > 0);
service serv = services.at(std::string(name));
SubSocket *socket = SubSocket::create(message_context.context(), name, address ? address : "127.0.0.1", true);
assert(socket != 0);
bool is_polled = inList(poll, name) || poll.empty();
if (is_polled) poller_->registerSocket(socket);
SubMessage *m = new SubMessage{
.name = name,
.socket = socket,
.freq = serv.frequency,
.ignore_alive = inList(ignore_alive, name),
.allocated_msg_reader = malloc(sizeof(capnp::FlatArrayMessageReader)),
.is_polled = is_polled};
m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader({});
messages_[socket] = m;
services_[name] = m;
}
}
void SubMaster::update(int timeout) {
for (auto &kv : messages_) kv.second->updated = false;
auto sockets = poller_->poll(timeout);
// add non-polled sockets for non-blocking receive
for (auto &kv : messages_) {
SubMessage *m = kv.second;
SubSocket *s = kv.first;
if (!m->is_polled) sockets.push_back(s);
}
uint64_t current_time = nanos_since_boot();
std::vector<std::pair<std::string, cereal::Event::Reader>> messages;
for (auto s : sockets) {
Message *msg = s->receive(true);
if (msg == nullptr) continue;
SubMessage *m = messages_.at(s);
m->msg_reader->~FlatArrayMessageReader();
capnp::ReaderOptions options;
options.traversalLimitInWords = kj::maxValue; // Don't limit
m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader(m->aligned_buf.align(msg), options);
delete msg;
messages.push_back({m->name, m->msg_reader->getRoot<cereal::Event>()});
}
update_msgs(current_time, messages);
}
void SubMaster::update_msgs(uint64_t current_time, const std::vector<std::pair<std::string, cereal::Event::Reader>> &messages){
if (++frame == UINT64_MAX) frame = 1;
for (auto &kv : messages) {
auto m_find = services_.find(kv.first);
if (m_find == services_.end()){
continue;
}
SubMessage *m = m_find->second;
m->event = kv.second;
m->updated = true;
m->rcv_time = current_time;
m->rcv_frame = frame;
m->valid = m->event.getValid();
if (SIMULATION) m->alive = true;
}
if (!SIMULATION) {
for (auto &kv : messages_) {
SubMessage *m = kv.second;
m->alive = (m->freq <= (1e-5) || ((current_time - m->rcv_time) * (1e-9)) < (10.0 / m->freq));
}
}
}
bool SubMaster::all_(const std::vector<const char *> &service_list, bool valid, bool alive) {
int found = 0;
for (auto &kv : messages_) {
SubMessage *m = kv.second;
if (service_list.size() == 0 || inList(service_list, m->name.c_str())) {
found += (!valid || m->valid) && (!alive || (m->alive || m->ignore_alive));
}
}
return service_list.size() == 0 ? found == messages_.size() : found == service_list.size();
}
void SubMaster::drain() {
while (true) {
auto polls = poller_->poll(0);
if (polls.size() == 0)
break;
for (auto sock : polls) {
Message *msg = sock->receive(true);
delete msg;
}
}
}
bool SubMaster::updated(const char *name) const {
return services_.at(name)->updated;
}
bool SubMaster::alive(const char *name) const {
return services_.at(name)->alive;
}
bool SubMaster::valid(const char *name) const {
return services_.at(name)->valid;
}
uint64_t SubMaster::rcv_frame(const char *name) const {
return services_.at(name)->rcv_frame;
}
uint64_t SubMaster::rcv_time(const char *name) const {
return services_.at(name)->rcv_time;
}
cereal::Event::Reader &SubMaster::operator[](const char *name) const {
return services_.at(name)->event;
}
SubMaster::~SubMaster() {
delete poller_;
for (auto &kv : messages_) {
SubMessage *m = kv.second;
m->msg_reader->~FlatArrayMessageReader();
free(m->allocated_msg_reader);
delete m->socket;
delete m;
}
}
PubMaster::PubMaster(const std::vector<const char *> &service_list) {
for (auto name : service_list) {
assert(services.count(name) > 0);
PubSocket *socket = PubSocket::create(message_context.context(), name);
assert(socket);
sockets_[name] = socket;
}
}
int PubMaster::send(const char *name, MessageBuilder &msg) {
auto bytes = msg.toBytes();
return send(name, bytes.begin(), bytes.size());
}
PubMaster::~PubMaster() {
for (auto s : sockets_) delete s.second;
}
+98
View File
@@ -0,0 +1,98 @@
/* THIS IS AN AUTOGENERATED FILE, PLEASE EDIT services.py */
#ifndef __SERVICES_H
#define __SERVICES_H
#include <map>
#include <string>
struct service { std::string name; bool should_log; int frequency; int decimation; };
static std::map<std::string, service> services = {
{ "gyroscope", {"gyroscope", true, 104, 104}},
{ "gyroscope2", {"gyroscope2", true, 100, 100}},
{ "accelerometer", {"accelerometer", true, 104, 104}},
{ "accelerometer2", {"accelerometer2", true, 100, 100}},
{ "magnetometer", {"magnetometer", true, 25, 25}},
{ "lightSensor", {"lightSensor", true, 100, 100}},
{ "temperatureSensor", {"temperatureSensor", true, 2, 200}},
{ "temperatureSensor2", {"temperatureSensor2", true, 2, 200}},
{ "gpsNMEA", {"gpsNMEA", true, 9, -1}},
{ "deviceState", {"deviceState", true, 2, 1}},
{ "can", {"can", true, 100, 1223}},
{ "controlsState", {"controlsState", true, 100, 10}},
{ "pandaStates", {"pandaStates", true, 10, 1}},
{ "peripheralState", {"peripheralState", true, 2, 1}},
{ "radarState", {"radarState", true, 20, 5}},
{ "roadEncodeIdx", {"roadEncodeIdx", false, 20, 1}},
{ "liveTracks", {"liveTracks", true, 20, -1}},
{ "sendcan", {"sendcan", true, 100, 139}},
{ "logMessage", {"logMessage", true, 0, -1}},
{ "errorLogMessage", {"errorLogMessage", true, 0, 1}},
{ "liveCalibration", {"liveCalibration", true, 4, 4}},
{ "liveTorqueParameters", {"liveTorqueParameters", true, 4, 1}},
{ "liveDelay", {"liveDelay", true, 4, 1}},
{ "androidLog", {"androidLog", true, 0, -1}},
{ "carState", {"carState", true, 100, 10}},
{ "carControl", {"carControl", true, 100, 10}},
{ "carOutput", {"carOutput", true, 100, 10}},
{ "longitudinalPlan", {"longitudinalPlan", true, 20, 5}},
{ "procLog", {"procLog", true, 0, 15}},
{ "gpsLocationExternal", {"gpsLocationExternal", true, 10, 10}},
{ "gpsLocation", {"gpsLocation", true, 1, 1}},
{ "ubloxGnss", {"ubloxGnss", true, 10, -1}},
{ "qcomGnss", {"qcomGnss", true, 2, -1}},
{ "gnssMeasurements", {"gnssMeasurements", true, 10, 10}},
{ "clocks", {"clocks", true, 0, 1}},
{ "ubloxRaw", {"ubloxRaw", true, 20, -1}},
{ "livePose", {"livePose", true, 20, 4}},
{ "liveLocationKalman", {"liveLocationKalman", true, 20, -1}},
{ "liveParameters", {"liveParameters", true, 20, 5}},
{ "cameraOdometry", {"cameraOdometry", true, 20, 5}},
{ "thumbnail", {"thumbnail", true, 0, 1}},
{ "onroadEvents", {"onroadEvents", true, 1, 1}},
{ "carParams", {"carParams", true, 0, 1}},
{ "roadCameraState", {"roadCameraState", true, 20, 20}},
{ "driverCameraState", {"driverCameraState", true, 20, 20}},
{ "driverEncodeIdx", {"driverEncodeIdx", false, 20, 1}},
{ "driverStateV2", {"driverStateV2", true, 20, 10}},
{ "driverMonitoringState", {"driverMonitoringState", true, 20, 10}},
{ "wideRoadEncodeIdx", {"wideRoadEncodeIdx", false, 20, 1}},
{ "wideRoadCameraState", {"wideRoadCameraState", true, 20, 20}},
{ "drivingModelData", {"drivingModelData", true, 20, 10}},
{ "modelV2", {"modelV2", true, 20, 40}},
{ "managerState", {"managerState", true, 2, 1}},
{ "uploaderState", {"uploaderState", true, 0, 1}},
{ "navInstruction", {"navInstruction", true, 1, 10}},
{ "navRoute", {"navRoute", true, 0, -1}},
{ "navThumbnail", {"navThumbnail", true, 0, -1}},
{ "navModel", {"navModel", true, 2, 4}},
{ "mapRenderState", {"mapRenderState", true, 2, 1}},
{ "uiPlan", {"uiPlan", true, 20, 40}},
{ "qRoadEncodeIdx", {"qRoadEncodeIdx", false, 20, -1}},
{ "userFlag", {"userFlag", true, 0, 1}},
{ "microphone", {"microphone", true, 10, 10}},
{ "uiDebug", {"uiDebug", true, 0, 1}},
{ "testJoystick", {"testJoystick", true, 0, -1}},
{ "roadEncodeData", {"roadEncodeData", false, 20, -1}},
{ "driverEncodeData", {"driverEncodeData", false, 20, -1}},
{ "wideRoadEncodeData", {"wideRoadEncodeData", false, 20, -1}},
{ "qRoadEncodeData", {"qRoadEncodeData", false, 20, -1}},
{ "livestreamWideRoadEncodeIdx", {"livestreamWideRoadEncodeIdx", false, 20, -1}},
{ "livestreamRoadEncodeIdx", {"livestreamRoadEncodeIdx", false, 20, -1}},
{ "livestreamDriverEncodeIdx", {"livestreamDriverEncodeIdx", false, 20, -1}},
{ "livestreamWideRoadEncodeData", {"livestreamWideRoadEncodeData", false, 20, -1}},
{ "livestreamRoadEncodeData", {"livestreamRoadEncodeData", false, 20, -1}},
{ "livestreamDriverEncodeData", {"livestreamDriverEncodeData", false, 20, -1}},
{ "customReservedRawData0", {"customReservedRawData0", true, 0, -1}},
{ "customReservedRawData1", {"customReservedRawData1", true, 0, -1}},
{ "customReservedRawData2", {"customReservedRawData2", true, 0, -1}},
{ "frogpilotCarControl", {"frogpilotCarControl", true, 100, 10}},
{ "frogpilotCarParams", {"frogpilotCarParams", true, 0, 1}},
{ "frogpilotCarState", {"frogpilotCarState", true, 100, 10}},
{ "frogpilotControlsState", {"frogpilotControlsState", true, 100, 10}},
{ "frogpilotDeviceState", {"frogpilotDeviceState", true, 2, 1}},
{ "frogpilotModelV2", {"frogpilotModelV2", true, 20, 40}},
{ "frogpilotNavigation", {"frogpilotNavigation", true, 1, 10}},
{ "frogpilotOnroadEvents", {"frogpilotOnroadEvents", true, 1, 1}},
{ "frogpilotPlan", {"frogpilotPlan", true, 20, 5}},
{ "frogpilotRadarState", {"frogpilotRadarState", true, 20, 5}},
};
#endif
+8 -1
View File
@@ -34,6 +34,7 @@ _services: dict[str, tuple] = {
"errorLogMessage": (True, 0., 1),
"liveCalibration": (True, 4., 4),
"liveTorqueParameters": (True, 4., 1),
"liveDelay": (True, 4., 1),
"androidLog": (True, 0.),
"carState": (True, 100., 10),
"carControl": (True, 100., 10),
@@ -47,7 +48,8 @@ _services: dict[str, tuple] = {
"gnssMeasurements": (True, 10., 10),
"clocks": (True, 0.1, 1),
"ubloxRaw": (True, 20.),
"liveLocationKalman": (True, 20., 5),
"livePose": (True, 20., 4),
"liveLocationKalman": (True, 20.),
"liveParameters": (True, 20., 5),
"cameraOdometry": (True, 20., 5),
"thumbnail": (True, 0.2, 1),
@@ -92,11 +94,16 @@ _services: dict[str, tuple] = {
"customReservedRawData2": (True, 0.),
# FrogPilot
"frogpilotCarControl": (True, 100., 10),
"frogpilotCarParams": (True, 0.02, 1),
"frogpilotCarState": (True, 100., 10),
"frogpilotControlsState": (True, 100., 10),
"frogpilotDeviceState": (True, 2., 1),
"frogpilotModelV2": (True, 20., 40),
"frogpilotNavigation": (True, 1., 10),
"frogpilotOnroadEvents": (True, 1., 1),
"frogpilotPlan": (True, 20., 5),
"frogpilotRadarState": (True, 20., 5),
}
SERVICE_LIST = {name: Service(*vals) for
idx, (name, vals) in enumerate(_services.items())}
+204
View File
@@ -0,0 +1,204 @@
#include "common/clutil.h"
#include <cassert>
#include <iostream>
#include <memory>
#include "common/util.h"
#include "common/swaglog.h"
namespace { // helper functions
template <typename Func, typename Id, typename Name>
std::string get_info(Func get_info_func, Id id, Name param_name) {
size_t size = 0;
CL_CHECK(get_info_func(id, param_name, 0, NULL, &size));
std::string info(size, '\0');
CL_CHECK(get_info_func(id, param_name, size, info.data(), NULL));
return info;
}
inline std::string get_platform_info(cl_platform_id id, cl_platform_info name) { return get_info(&clGetPlatformInfo, id, name); }
inline std::string get_device_info(cl_device_id id, cl_device_info name) { return get_info(&clGetDeviceInfo, id, name); }
void cl_print_info(cl_platform_id platform, cl_device_id device) {
size_t work_group_size = 0;
cl_device_type device_type = 0;
clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(work_group_size), &work_group_size, NULL);
clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), &device_type, NULL);
const char *type_str = "Other...";
switch (device_type) {
case CL_DEVICE_TYPE_CPU: type_str ="CL_DEVICE_TYPE_CPU"; break;
case CL_DEVICE_TYPE_GPU: type_str = "CL_DEVICE_TYPE_GPU"; break;
case CL_DEVICE_TYPE_ACCELERATOR: type_str = "CL_DEVICE_TYPE_ACCELERATOR"; break;
}
LOGD("vendor: %s", get_platform_info(platform, CL_PLATFORM_VENDOR).c_str());
LOGD("platform version: %s", get_platform_info(platform, CL_PLATFORM_VERSION).c_str());
LOGD("profile: %s", get_platform_info(platform, CL_PLATFORM_PROFILE).c_str());
LOGD("extensions: %s", get_platform_info(platform, CL_PLATFORM_EXTENSIONS).c_str());
LOGD("name: %s", get_device_info(device, CL_DEVICE_NAME).c_str());
LOGD("device version: %s", get_device_info(device, CL_DEVICE_VERSION).c_str());
LOGD("max work group size: %zu", work_group_size);
LOGD("type = %d, %s", (int)device_type, type_str);
}
void cl_print_build_errors(cl_program program, cl_device_id device) {
cl_build_status status;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_STATUS, sizeof(status), &status, NULL);
size_t log_size;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
std::string log(log_size, '\0');
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, &log[0], NULL);
LOGE("build failed; status=%d, log: %s", status, log.c_str());
}
} // namespace
cl_device_id cl_get_device_id(cl_device_type device_type) {
cl_uint num_platforms = 0;
CL_CHECK(clGetPlatformIDs(0, NULL, &num_platforms));
std::unique_ptr<cl_platform_id[]> platform_ids = std::make_unique<cl_platform_id[]>(num_platforms);
CL_CHECK(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL));
for (size_t i = 0; i < num_platforms; ++i) {
LOGD("platform[%zu] CL_PLATFORM_NAME: %s", i, get_platform_info(platform_ids[i], CL_PLATFORM_NAME).c_str());
// Get first device
if (cl_device_id device_id = NULL; clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL) == 0 && device_id) {
cl_print_info(platform_ids[i], device_id);
return device_id;
}
}
LOGE("No valid openCL platform found");
assert(0);
return nullptr;
}
cl_context cl_create_context(cl_device_id device_id) {
return CL_CHECK_ERR(clCreateContext(NULL, 1, &device_id, NULL, NULL, &err));
}
void cl_release_context(cl_context context) {
clReleaseContext(context);
}
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args) {
return cl_program_from_source(ctx, device_id, util::read_file(path), args);
}
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args) {
const char *csrc = src.c_str();
cl_program prg = CL_CHECK_ERR(clCreateProgramWithSource(ctx, 1, &csrc, NULL, &err));
if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) {
cl_print_build_errors(prg, device_id);
assert(0);
}
return prg;
}
cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args) {
cl_program prg = CL_CHECK_ERR(clCreateProgramWithBinary(ctx, 1, &device_id, &length, &binary, NULL, &err));
if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) {
cl_print_build_errors(prg, device_id);
assert(0);
}
return prg;
}
// Given a cl code and return a string representation
#define CL_ERR_TO_STR(err) case err: return #err
const char* cl_get_error_string(int err) {
switch (err) {
CL_ERR_TO_STR(CL_SUCCESS);
CL_ERR_TO_STR(CL_DEVICE_NOT_FOUND);
CL_ERR_TO_STR(CL_DEVICE_NOT_AVAILABLE);
CL_ERR_TO_STR(CL_COMPILER_NOT_AVAILABLE);
CL_ERR_TO_STR(CL_MEM_OBJECT_ALLOCATION_FAILURE);
CL_ERR_TO_STR(CL_OUT_OF_RESOURCES);
CL_ERR_TO_STR(CL_OUT_OF_HOST_MEMORY);
CL_ERR_TO_STR(CL_PROFILING_INFO_NOT_AVAILABLE);
CL_ERR_TO_STR(CL_MEM_COPY_OVERLAP);
CL_ERR_TO_STR(CL_IMAGE_FORMAT_MISMATCH);
CL_ERR_TO_STR(CL_IMAGE_FORMAT_NOT_SUPPORTED);
CL_ERR_TO_STR(CL_MAP_FAILURE);
CL_ERR_TO_STR(CL_MISALIGNED_SUB_BUFFER_OFFSET);
CL_ERR_TO_STR(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
CL_ERR_TO_STR(CL_COMPILE_PROGRAM_FAILURE);
CL_ERR_TO_STR(CL_LINKER_NOT_AVAILABLE);
CL_ERR_TO_STR(CL_LINK_PROGRAM_FAILURE);
CL_ERR_TO_STR(CL_DEVICE_PARTITION_FAILED);
CL_ERR_TO_STR(CL_KERNEL_ARG_INFO_NOT_AVAILABLE);
CL_ERR_TO_STR(CL_INVALID_VALUE);
CL_ERR_TO_STR(CL_INVALID_DEVICE_TYPE);
CL_ERR_TO_STR(CL_INVALID_PLATFORM);
CL_ERR_TO_STR(CL_INVALID_DEVICE);
CL_ERR_TO_STR(CL_INVALID_CONTEXT);
CL_ERR_TO_STR(CL_INVALID_QUEUE_PROPERTIES);
CL_ERR_TO_STR(CL_INVALID_COMMAND_QUEUE);
CL_ERR_TO_STR(CL_INVALID_HOST_PTR);
CL_ERR_TO_STR(CL_INVALID_MEM_OBJECT);
CL_ERR_TO_STR(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
CL_ERR_TO_STR(CL_INVALID_IMAGE_SIZE);
CL_ERR_TO_STR(CL_INVALID_SAMPLER);
CL_ERR_TO_STR(CL_INVALID_BINARY);
CL_ERR_TO_STR(CL_INVALID_BUILD_OPTIONS);
CL_ERR_TO_STR(CL_INVALID_PROGRAM);
CL_ERR_TO_STR(CL_INVALID_PROGRAM_EXECUTABLE);
CL_ERR_TO_STR(CL_INVALID_KERNEL_NAME);
CL_ERR_TO_STR(CL_INVALID_KERNEL_DEFINITION);
CL_ERR_TO_STR(CL_INVALID_KERNEL);
CL_ERR_TO_STR(CL_INVALID_ARG_INDEX);
CL_ERR_TO_STR(CL_INVALID_ARG_VALUE);
CL_ERR_TO_STR(CL_INVALID_ARG_SIZE);
CL_ERR_TO_STR(CL_INVALID_KERNEL_ARGS);
CL_ERR_TO_STR(CL_INVALID_WORK_DIMENSION);
CL_ERR_TO_STR(CL_INVALID_WORK_GROUP_SIZE);
CL_ERR_TO_STR(CL_INVALID_WORK_ITEM_SIZE);
CL_ERR_TO_STR(CL_INVALID_GLOBAL_OFFSET);
CL_ERR_TO_STR(CL_INVALID_EVENT_WAIT_LIST);
CL_ERR_TO_STR(CL_INVALID_EVENT);
CL_ERR_TO_STR(CL_INVALID_OPERATION);
CL_ERR_TO_STR(CL_INVALID_GL_OBJECT);
CL_ERR_TO_STR(CL_INVALID_BUFFER_SIZE);
CL_ERR_TO_STR(CL_INVALID_MIP_LEVEL);
CL_ERR_TO_STR(CL_INVALID_GLOBAL_WORK_SIZE);
CL_ERR_TO_STR(CL_INVALID_PROPERTY);
CL_ERR_TO_STR(CL_INVALID_IMAGE_DESCRIPTOR);
CL_ERR_TO_STR(CL_INVALID_COMPILER_OPTIONS);
CL_ERR_TO_STR(CL_INVALID_LINKER_OPTIONS);
CL_ERR_TO_STR(CL_INVALID_DEVICE_PARTITION_COUNT);
case -69: return "CL_INVALID_PIPE_SIZE";
case -70: return "CL_INVALID_DEVICE_QUEUE";
case -71: return "CL_INVALID_SPEC_ID";
case -72: return "CL_MAX_SIZE_RESTRICTION_EXCEEDED";
case -1002: return "CL_INVALID_D3D10_DEVICE_KHR";
case -1003: return "CL_INVALID_D3D10_RESOURCE_KHR";
case -1004: return "CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR";
case -1005: return "CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR";
case -1006: return "CL_INVALID_D3D11_DEVICE_KHR";
case -1007: return "CL_INVALID_D3D11_RESOURCE_KHR";
case -1008: return "CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR";
case -1009: return "CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR";
case -1010: return "CL_INVALID_DX9_MEDIA_ADAPTER_KHR";
case -1011: return "CL_INVALID_DX9_MEDIA_SURFACE_KHR";
case -1012: return "CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR";
case -1013: return "CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR";
case -1093: return "CL_INVALID_EGL_OBJECT_KHR";
case -1092: return "CL_EGL_RESOURCE_NOT_ACQUIRED_KHR";
case -1001: return "CL_PLATFORM_NOT_FOUND_KHR";
case -1057: return "CL_DEVICE_PARTITION_FAILED_EXT";
case -1058: return "CL_INVALID_PARTITION_COUNT_EXT";
case -1059: return "CL_INVALID_PARTITION_NAME_EXT";
case -1094: return "CL_INVALID_ACCELERATOR_INTEL";
case -1095: return "CL_INVALID_ACCELERATOR_TYPE_INTEL";
case -1096: return "CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL";
case -1097: return "CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL";
case -1000: return "CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR";
case -1098: return "CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL";
case -1099: return "CL_INVALID_VA_API_MEDIA_SURFACE_INTEL";
case -1100: return "CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL";
case -1101: return "CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL";
default: return "CL_UNKNOWN_ERROR";
}
}
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#ifdef __APPLE__
#include <OpenCL/cl.h>
#else
#include <CL/cl.h>
#endif
#include <string>
#define CL_CHECK(_expr) \
do { \
assert(CL_SUCCESS == (_expr)); \
} while (0)
#define CL_CHECK_ERR(_expr) \
({ \
cl_int err = CL_INVALID_VALUE; \
__typeof__(_expr) _ret = _expr; \
assert(_ret&& err == CL_SUCCESS); \
_ret; \
})
cl_device_id cl_get_device_id(cl_device_type device_type);
cl_context cl_create_context(cl_device_id device_id);
void cl_release_context(cl_context context);
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args = nullptr);
cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args = nullptr);
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args);
const char* cl_get_error_string(int err);
+2
View File
@@ -14,6 +14,8 @@ class Conversions:
# Distance
METER_TO_FOOT = 3.28084
FOOT_TO_METER = 1. / METER_TO_FOOT
METER_TO_MILE = METER_TO_FOOT / 5280
MILE_TO_METER = 1. / METER_TO_MILE
CM_TO_INCH = 1. / 2.54
INCH_TO_CM = 1. / CM_TO_INCH
+84
View File
@@ -0,0 +1,84 @@
#include "common/gpio.h"
#include <string>
#ifdef __APPLE__
int gpio_init(int pin_nr, bool output) {
return 0;
}
int gpio_set(int pin_nr, bool high) {
return 0;
}
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) {
return 0;
}
#else
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <linux/gpio.h>
#include <sys/ioctl.h>
#include "common/util.h"
#include "common/swaglog.h"
int gpio_init(int pin_nr, bool output) {
char pin_dir_path[50];
int pin_dir_path_len = snprintf(pin_dir_path, sizeof(pin_dir_path),
"/sys/class/gpio/gpio%d/direction", pin_nr);
if (pin_dir_path_len <= 0) {
return -1;
}
const char *value = output ? "out" : "in";
return util::write_file(pin_dir_path, (void*)value, strlen(value));
}
int gpio_set(int pin_nr, bool high) {
char pin_val_path[50];
int pin_val_path_len = snprintf(pin_val_path, sizeof(pin_val_path),
"/sys/class/gpio/gpio%d/value", pin_nr);
if (pin_val_path_len <= 0) {
return -1;
}
return util::write_file(pin_val_path, (void*)(high ? "1" : "0"), 1);
}
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) {
// Assumed that all interrupt pins are unexported and rights are given to
// read from gpiochip0.
std::string gpiochip_path = "/dev/gpiochip" + std::to_string(gpiochiop_id);
int fd = open(gpiochip_path.c_str(), O_RDONLY);
if (fd < 0) {
LOGE("Error opening gpiochip0 fd");
return -1;
}
// Setup event
struct gpioevent_request rq;
rq.lineoffset = pin_nr;
rq.handleflags = GPIOHANDLE_REQUEST_INPUT;
/* Requesting both edges as the data ready pulse from the lsm6ds sensor is
very short(75us) and is mostly detected as falling edge instead of rising.
So if it is detected as rising the following falling edge is skipped. */
rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
strncpy(rq.consumer_label, consumer_label, std::size(rq.consumer_label) - 1);
int ret = util::safe_ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &rq);
if (ret == -1) {
LOGE("Unable to get line event from ioctl : %s", strerror(errno));
close(fd);
return -1;
}
close(fd);
return rq.fd;
}
#endif
+33
View File
@@ -0,0 +1,33 @@
#pragma once
// Pin definitions
#ifdef QCOM2
#define GPIO_HUB_RST_N 30
#define GPIO_UBLOX_RST_N 32
#define GPIO_UBLOX_SAFEBOOT_N 33
#define GPIO_GNSS_PWR_EN 34 /* SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN */
#define GPIO_STM_RST_N 124
#define GPIO_STM_BOOT0 134
#define GPIO_BMX_ACCEL_INT 21
#define GPIO_BMX_GYRO_INT 23
#define GPIO_BMX_MAGN_INT 87
#define GPIO_LSM_INT 84
#define GPIOCHIP_INT 0
#else
#define GPIO_HUB_RST_N 0
#define GPIO_UBLOX_RST_N 0
#define GPIO_UBLOX_SAFEBOOT_N 0
#define GPIO_GNSS_PWR_EN 0 /* SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN */
#define GPIO_STM_RST_N 0
#define GPIO_STM_BOOT0 0
#define GPIO_BMX_ACCEL_INT 0
#define GPIO_BMX_GYRO_INT 0
#define GPIO_BMX_MAGN_INT 0
#define GPIO_LSM_INT 0
#define GPIOCHIP_INT 0
#endif
int gpio_init(int pin_nr, bool output);
int gpio_set(int pin_nr, bool high);
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr);
+92
View File
@@ -0,0 +1,92 @@
#include "common/i2c.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <cassert>
#include <cstdio>
#include <stdexcept>
#include "common/swaglog.h"
#include "common/util.h"
#define UNUSED(x) (void)(x)
#ifdef QCOM2
// TODO: decide if we want to install libi2c-dev everywhere
extern "C" {
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
}
I2CBus::I2CBus(uint8_t bus_id) {
char bus_name[20];
snprintf(bus_name, 20, "/dev/i2c-%d", bus_id);
i2c_fd = HANDLE_EINTR(open(bus_name, O_RDWR));
if (i2c_fd < 0) {
throw std::runtime_error("Failed to open I2C bus");
}
}
I2CBus::~I2CBus() {
if (i2c_fd >= 0) {
close(i2c_fd);
}
}
int I2CBus::read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len) {
std::lock_guard lk(m);
int ret = 0;
ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address));
if (ret < 0) { goto fail; }
ret = i2c_smbus_read_i2c_block_data(i2c_fd, register_address, len, buffer);
if ((ret < 0) || (ret != len)) { goto fail; }
fail:
return ret;
}
int I2CBus::set_register(uint8_t device_address, uint register_address, uint8_t data) {
std::lock_guard lk(m);
int ret = 0;
ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address));
if (ret < 0) { goto fail; }
ret = i2c_smbus_write_byte_data(i2c_fd, register_address, data);
if (ret < 0) { goto fail; }
fail:
return ret;
}
#else
I2CBus::I2CBus(uint8_t bus_id) {
UNUSED(bus_id);
i2c_fd = -1;
}
I2CBus::~I2CBus() {}
int I2CBus::read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len) {
UNUSED(device_address);
UNUSED(register_address);
UNUSED(buffer);
UNUSED(len);
return -1;
}
int I2CBus::set_register(uint8_t device_address, uint register_address, uint8_t data) {
UNUSED(device_address);
UNUSED(register_address);
UNUSED(data);
return -1;
}
#endif
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
#include <mutex>
#include <sys/types.h>
class I2CBus {
private:
int i2c_fd;
std::mutex m;
public:
I2CBus(uint8_t bus_id);
~I2CBus();
int read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len);
int set_register(uint8_t device_address, uint register_address, uint8_t data);
};
+85
View File
@@ -0,0 +1,85 @@
#pragma once
typedef struct vec3 {
float v[3];
} vec3;
typedef struct vec4 {
float v[4];
} vec4;
typedef struct mat3 {
float v[3*3];
} mat3;
typedef struct mat4 {
float v[4*4];
} mat4;
static inline mat3 matmul3(const mat3 &a, const mat3 &b) {
mat3 ret = {{0.0}};
for (int r=0; r<3; r++) {
for (int c=0; c<3; c++) {
float v = 0.0;
for (int k=0; k<3; k++) {
v += a.v[r*3+k] * b.v[k*3+c];
}
ret.v[r*3+c] = v;
}
}
return ret;
}
static inline vec3 matvecmul3(const mat3 &a, const vec3 &b) {
vec3 ret = {{0.0}};
for (int r=0; r<3; r++) {
for (int c=0; c<3; c++) {
ret.v[r] += a.v[r*3+c] * b.v[c];
}
}
return ret;
}
static inline mat4 matmul(const mat4 &a, const mat4 &b) {
mat4 ret = {{0.0}};
for (int r=0; r<4; r++) {
for (int c=0; c<4; c++) {
float v = 0.0;
for (int k=0; k<4; k++) {
v += a.v[r*4+k] * b.v[k*4+c];
}
ret.v[r*4+c] = v;
}
}
return ret;
}
static inline vec4 matvecmul(const mat4 &a, const vec4 &b) {
vec4 ret = {{0.0}};
for (int r=0; r<4; r++) {
for (int c=0; c<4; c++) {
ret.v[r] += a.v[r*4+c] * b.v[c];
}
}
return ret;
}
// scales the input and output space of a transformation matrix
// that assumes pixel-center origin.
static inline mat3 transform_scale_buffer(const mat3 &in, float s) {
// in_pt = ( transform(out_pt/s + 0.5) - 0.5) * s
mat3 transform_out = {{
1.0f/s, 0.0f, 0.5f,
0.0f, 1.0f/s, 0.5f,
0.0f, 0.0f, 1.0f,
}};
mat3 transform_in = {{
s, 0.0f, -0.5f*s,
0.0f, s, -0.5f*s,
0.0f, 0.0f, 1.0f,
}};
return matmul3(transform_in, matmul3(in, transform_out));
}
+747
View File
@@ -0,0 +1,747 @@
#include "common/params.h"
#include <dirent.h>
#include <sys/file.h>
#include <algorithm>
#include <cassert>
#include <csignal>
#include <unordered_map>
#include "common/queue.h"
#include "common/swaglog.h"
#include "common/util.h"
#include "system/hardware/hw.h"
namespace {
volatile sig_atomic_t params_do_exit = 0;
void params_sig_handler(int signal) {
params_do_exit = 1;
}
int fsync_dir(const std::string &path) {
int result = -1;
int fd = HANDLE_EINTR(open(path.c_str(), O_RDONLY, 0755));
if (fd >= 0) {
result = fsync(fd);
close(fd);
}
return result;
}
bool create_params_path(const std::string &param_path, const std::string &key_path) {
// Make sure params path exists
if (!util::file_exists(param_path) && !util::create_directories(param_path, 0775)) {
return false;
}
// See if the symlink exists, otherwise create it
if (!util::file_exists(key_path)) {
// 1) Create temp folder
// 2) Symlink it to temp link
// 3) Move symlink to <params>/d
std::string tmp_path = param_path + "/.tmp_XXXXXX";
// this should be OK since mkdtemp just replaces characters in place
char *tmp_dir = mkdtemp((char *)tmp_path.c_str());
if (tmp_dir == NULL) {
return false;
}
std::string link_path = std::string(tmp_dir) + ".link";
if (symlink(tmp_dir, link_path.c_str()) != 0) {
return false;
}
// don't return false if it has been created by other
if (rename(link_path.c_str(), key_path.c_str()) != 0 && errno != EEXIST) {
return false;
}
}
return true;
}
std::string ensure_params_path(const std::string &prefix, const std::string &path = {}) {
std::string params_path = path.empty() ? Path::params() : path;
if (!create_params_path(params_path, params_path + prefix)) {
throw std::runtime_error(util::string_format(
"Failed to ensure params path, errno=%d, path=%s, param_prefix=%s",
errno, params_path.c_str(), prefix.c_str()));
}
return params_path;
}
class FileLock {
public:
FileLock(const std::string &fn) {
if (fn.rfind("/cache", 0) == 0 || fn.rfind("/data/params_backup", 0) == 0) {
return;
}
fd_ = HANDLE_EINTR(open(fn.c_str(), O_CREAT, 0775));
if (fd_ < 0 || HANDLE_EINTR(flock(fd_, LOCK_EX)) < 0) {
LOGE("Failed to lock file %s, errno=%d", fn.c_str(), errno);
}
}
~FileLock() { close(fd_); }
private:
int fd_ = -1;
};
std::unordered_map<std::string, uint32_t> keys = {
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
{"AlwaysOnDM", PERSISTENT},
{"ApiCache_Device", PERSISTENT},
{"ApiCache_NavDestinations", PERSISTENT},
{"AssistNowToken", PERSISTENT},
{"AthenadPid", PERSISTENT},
{"AthenadUploadQueue", PERSISTENT},
{"AthenadRecentlyViewedRoutes", PERSISTENT},
{"BootCount", PERSISTENT},
{"CalibrationParams", PERSISTENT},
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
{"CarBatteryCapacity", PERSISTENT},
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"CarParamsCache", CLEAR_ON_MANAGER_START},
{"CarParamsPersistent", PERSISTENT},
{"CarParamsPrevRoute", PERSISTENT},
{"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"CompletedTrainingVersion", PERSISTENT},
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"CurrentBootlog", PERSISTENT},
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"DisablePowerDown", PERSISTENT},
{"DisableUpdates", PERSISTENT},
{"DisengageOnAccelerator", PERSISTENT},
{"DmModelInitialized", CLEAR_ON_ONROAD_TRANSITION},
{"DongleId", PERSISTENT},
{"DoReboot", CLEAR_ON_MANAGER_START},
{"DoShutdown", CLEAR_ON_MANAGER_START},
{"DoUninstall", CLEAR_ON_MANAGER_START},
{"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY},
{"ExperimentalMode", PERSISTENT},
{"ExperimentalModeConfirmed", PERSISTENT},
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"ForcePowerDown", PERSISTENT},
{"GitBranch", PERSISTENT},
{"GitCommit", PERSISTENT},
{"GitCommitDate", PERSISTENT},
{"GitDiff", PERSISTENT},
{"GithubSshKeys", PERSISTENT},
{"GithubUsername", PERSISTENT},
{"GitRemote", PERSISTENT},
{"GsmApn", PERSISTENT},
{"GsmMetered", PERSISTENT},
{"GsmRoaming", PERSISTENT},
{"HardwareSerial", PERSISTENT},
{"HasAcceptedTerms", PERSISTENT},
{"IMEI", PERSISTENT},
{"InstallDate", PERSISTENT},
{"IsDriverViewEnabled", CLEAR_ON_ONROAD_TRANSITION},
{"IsEngaged", PERSISTENT},
{"IsLdwEnabled", PERSISTENT},
{"IsMetric", PERSISTENT},
{"IsOffroad", CLEAR_ON_MANAGER_START},
{"IsOnroad", PERSISTENT},
{"IsRhdDetected", PERSISTENT},
{"IsReleaseBranch", CLEAR_ON_MANAGER_START},
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
{"IsTestedBranch", CLEAR_ON_MANAGER_START},
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"LanguageSetting", PERSISTENT},
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
{"LastGPSPosition", PERSISTENT},
{"LastManagerExitReason", CLEAR_ON_MANAGER_START},
{"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"LastPowerDropDetected", CLEAR_ON_MANAGER_START},
{"LastUpdateException", CLEAR_ON_MANAGER_START},
{"LastUpdateTime", PERSISTENT},
{"LiveDelay", PERSISTENT},
{"LiveParameters", PERSISTENT},
{"LiveTorqueParameters", PERSISTENT | DONT_LOG},
{"LongitudinalPersonality", PERSISTENT},
{"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"NavPastDestinations", PERSISTENT},
{"NavSettingLeftSide", PERSISTENT},
{"NavSettingTime24h", PERSISTENT},
{"NetworkMetered", PERSISTENT},
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
{"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
{"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
{"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START},
{"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START},
{"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"Offroad_Recalibration", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"Offroad_StorageMissing", CLEAR_ON_MANAGER_START},
{"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
{"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
{"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
{"OpenpilotEnabledToggle", PERSISTENT},
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"PandaSignatures", CLEAR_ON_MANAGER_START},
{"PrimeType", PERSISTENT},
{"RecordFront", PERSISTENT},
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
{"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"RouteCount", PERSISTENT},
{"SecOCKey", PERSISTENT | DONT_LOG},
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"SshEnabled", PERSISTENT},
{"TermsVersion", PERSISTENT},
{"Timezone", PERSISTENT},
{"TrainingVersion", PERSISTENT},
{"UbloxAvailable", PERSISTENT},
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"UpdateFailedCount", CLEAR_ON_MANAGER_START},
{"UpdaterAvailableBranches", PERSISTENT},
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
{"UpdaterNewDescription", CLEAR_ON_MANAGER_START},
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
{"UpdaterState", CLEAR_ON_MANAGER_START},
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
{"UpdaterLastFetchTime", PERSISTENT},
{"Version", PERSISTENT},
// FrogPilot parameters
{"AccelerationPath", PERSISTENT},
{"AccelerationProfile", PERSISTENT},
{"AdjacentLeadsUI", PERSISTENT},
{"AdjacentPath", PERSISTENT},
{"AdjacentPathMetrics", PERSISTENT},
{"AdvancedCustomUI", PERSISTENT},
{"AdvancedLateralTune", PERSISTENT},
{"AdvancedLongitudinalTune", PERSISTENT},
{"AggressiveFollow", PERSISTENT},
{"AggressiveFollowHigh", PERSISTENT},
{"AggressiveJerkAcceleration", PERSISTENT},
{"AggressiveJerkDanger", PERSISTENT},
{"AggressiveJerkDeceleration", PERSISTENT},
{"AggressiveJerkSpeed", PERSISTENT},
{"AggressiveJerkSpeedDecrease", PERSISTENT},
{"AggressivePersonalityProfile", PERSISTENT},
{"AlertVolumeControl", PERSISTENT},
{"AlwaysOnLateral", PERSISTENT},
{"AlwaysOnLateralLKAS", PERSISTENT},
{"AlwaysOnLateralMain", PERSISTENT},
{"AMapKey1", PERSISTENT | DONT_LOG},
{"AMapKey2", PERSISTENT | DONT_LOG},
{"ApiCache_DriveStats", PERSISTENT},
{"AutomaticallyDownloadModels", PERSISTENT},
{"AutomaticUpdates", PERSISTENT},
{"AvailableModelNames", PERSISTENT},
{"AvailableModelSeries", PERSISTENT},
{"AvailableModels", PERSISTENT},
{"BigMap", PERSISTENT},
{"BlacklistedModels", PERSISTENT},
{"BlindSpotMetrics", PERSISTENT},
{"BlindSpotPath", PERSISTENT},
{"BootLogo", PERSISTENT},
{"BorderMetrics", PERSISTENT},
{"CalibratedLateralAcceleration", PERSISTENT},
{"CalibrationProgress", PERSISTENT},
{"CameraView", PERSISTENT},
{"CancelModelDownload", CLEAR_ON_MANAGER_START},
{"CancelThemeDownload", CLEAR_ON_MANAGER_START},
{"CarMake", PERSISTENT},
{"CarModel", PERSISTENT},
{"CarModelName", PERSISTENT},
{"CECurves", PERSISTENT},
{"CECurvesLead", PERSISTENT},
{"CELead", PERSISTENT},
{"CEModelStopTime", PERSISTENT},
{"CENavigation", PERSISTENT},
{"CENavigationIntersections", PERSISTENT},
{"CENavigationLead", PERSISTENT},
{"CENavigationTurns", PERSISTENT},
{"CESignalSpeed", PERSISTENT},
{"CESignalLaneDetection", PERSISTENT},
{"CESlowerLead", PERSISTENT},
{"CESpeed", PERSISTENT},
{"CESpeedLead", PERSISTENT},
{"CEStatus", CLEAR_ON_OFFROAD_TRANSITION},
{"CEStoppedLead", PERSISTENT},
{"ClusterOffset", PERSISTENT},
{"BootLogoToDownload", CLEAR_ON_MANAGER_START},
{"ColorToDownload", CLEAR_ON_MANAGER_START},
{"Compass", PERSISTENT},
{"ConditionalExperimental", PERSISTENT},
{"CurvatureData", PERSISTENT | DONT_LOG},
{"CurveSpeedController", PERSISTENT},
{"CustomAlerts", PERSISTENT},
{"CustomColors", PERSISTENT},
{"CustomCruise", PERSISTENT},
{"CustomCruiseLong", PERSISTENT},
{"CustomDistanceIcons", PERSISTENT},
{"CustomIcons", PERSISTENT},
{"CustomPersonalities", PERSISTENT},
{"CustomSignals", PERSISTENT},
{"CustomSounds", PERSISTENT},
{"CustomUI", PERSISTENT},
{"DebugMode", CLEAR_ON_OFFROAD_TRANSITION},
{"DecelerationProfile", PERSISTENT},
{"DeveloperMetrics", PERSISTENT},
{"DeveloperSidebar", PERSISTENT},
{"DeveloperSidebarMetric1", PERSISTENT},
{"DeveloperSidebarMetric2", PERSISTENT},
{"DeveloperSidebarMetric3", PERSISTENT},
{"DeveloperSidebarMetric4", PERSISTENT},
{"DeveloperSidebarMetric5", PERSISTENT},
{"DeveloperSidebarMetric6", PERSISTENT},
{"DeveloperSidebarMetric7", PERSISTENT},
{"DeveloperWidgets", PERSISTENT},
{"DeveloperUI", PERSISTENT},
{"DeviceManagement", PERSISTENT},
{"DeviceShutdown", PERSISTENT},
{"DisableOnroadUploads", PERSISTENT},
{"DisableOpenpilotLongitudinal", PERSISTENT},
{"DiscordUsername", PERSISTENT},
{"DistanceButtonControl", PERSISTENT},
{"DistanceIconToDownload", CLEAR_ON_MANAGER_START},
{"DisengageVolume", PERSISTENT},
{"DoToggleReset", PERSISTENT},
{"DoToggleResetStock", PERSISTENT},
{"DownloadableBootLogos", PERSISTENT},
{"DownloadableColors", PERSISTENT},
{"DownloadableDistanceIcons", PERSISTENT},
{"DownloadableIcons", PERSISTENT},
{"DownloadableSignals", PERSISTENT},
{"DownloadableSounds", PERSISTENT},
{"DownloadableWheels", PERSISTENT},
{"DownloadAllModels", CLEAR_ON_MANAGER_START},
{"DriverCamera", PERSISTENT},
{"DynamicPathWidth", PERSISTENT},
{"DynamicPedalsOnUI", PERSISTENT},
{"EngageVolume", PERSISTENT},
{"ExperimentalGMTune", PERSISTENT},
{"EVTuning", PERSISTENT},
{"TruckTuning", PERSISTENT},
{"Fahrenheit", PERSISTENT},
{"FavoriteDestinations", PERSISTENT | DONT_LOG},
{"FlashPanda", CLEAR_ON_MANAGER_START},
{"ForceAutoTune", PERSISTENT},
{"ForceAutoTuneOff", PERSISTENT},
{"ForceFingerprint", PERSISTENT},
{"ForceMPHDashboard", PERSISTENT},
{"ForceOffroad", CLEAR_ON_MANAGER_START},
{"ForceOnroad", CLEAR_ON_MANAGER_START},
{"ForceStops", PERSISTENT},
{"ForceTorqueController", PERSISTENT},
{"FPSCounter", PERSISTENT},
{"FrogPilotCarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"FrogPilotCarParamsPersistent", PERSISTENT},
{"FrogPilotDongleId", PERSISTENT | DONT_LOG},
{"FrogPilotDrives", PERSISTENT},
{"FrogPilotKilometers", PERSISTENT},
{"FrogPilotMinutes", PERSISTENT},
{"FrogPilotStats", PERSISTENT | DONT_LOG},
{"FrogPilotToggles", CLEAR_ON_MANAGER_START},
{"FrogPilotTogglesUpdated", CLEAR_ON_MANAGER_START},
{"FrogPilotTuningLevels", CLEAR_ON_MANAGER_START},
{"FrogsGoMoosTweak", PERSISTENT},
{"FullMap", PERSISTENT},
{"GasRegenCmd", PERSISTENT},
{"GMPedalLongitudinal", PERSISTENT},
{"GoatScream", PERSISTENT},
{"GreenLightAlert", PERSISTENT},
{"HideAlerts", PERSISTENT},
{"HideLeadMarker", PERSISTENT},
{"HideMap", PERSISTENT},
{"HideMapIcon", PERSISTENT},
{"HideMaxSpeed", PERSISTENT},
{"HideSpeed", PERSISTENT},
{"HideSpeedLimit", PERSISTENT},
{"HigherBitrate", PERSISTENT},
{"HolidayThemes", PERSISTENT},
{"HumanAcceleration", PERSISTENT},
{"HumanFollowing", PERSISTENT},
{"IconToDownload", CLEAR_ON_MANAGER_START},
{"IncreasedStoppedDistance", PERSISTENT},
{"IncreaseThermalLimits", PERSISTENT},
{"IssueReported", CLEAR_ON_MANAGER_START},
{"KonikDongleId", PERSISTENT},
{"KonikMinutes", PERSISTENT},
{"LaneChanges", PERSISTENT},
{"LaneChangeTime", PERSISTENT},
{"LaneDetectionWidth", PERSISTENT},
{"LaneLinesWidth", PERSISTENT},
{"LastMapsUpdate", PERSISTENT},
{"LateralTune", PERSISTENT},
{"LeadDepartingAlert", PERSISTENT},
{"LeadDetectionThreshold", PERSISTENT},
{"LeadInfo", PERSISTENT},
{"LKASButtonControl", PERSISTENT},
{"LockDoors", PERSISTENT},
{"LockDoorsTimer", PERSISTENT},
{"LongDistanceButtonControl", PERSISTENT},
{"LongitudinalActuatorDelay", PERSISTENT},
{"LongitudinalActuatorDelayStock", PERSISTENT},
{"LongitudinalTune", PERSISTENT},
{"LongPitch", PERSISTENT},
{"LoudBlindspotAlert", PERSISTENT},
{"LowVoltageShutdown", PERSISTENT},
{"ManualUpdateInitiated", CLEAR_ON_MANAGER_START},
{"MapAcceleration", PERSISTENT},
{"MapboxPublicKey", PERSISTENT | DONT_LOG},
{"MapBoxRequests", PERSISTENT},
{"MapboxSecretKey", PERSISTENT | DONT_LOG},
{"MapDeceleration", PERSISTENT},
{"MapdLogLevel", CLEAR_ON_MANAGER_START},
{"MapGears", PERSISTENT},
{"MapsSelected", PERSISTENT},
{"MapSpeedLimit", CLEAR_ON_MANAGER_START},
{"MapStyle", PERSISTENT},
{"MaxDesiredAcceleration", PERSISTENT},
{"MinimumBackupSize", PERSISTENT},
{"MinimumLaneChangeSpeed", PERSISTENT},
{"Model", PERSISTENT},
{"ModelVersion", PERSISTENT},
{"ModelDownloadProgress", CLEAR_ON_MANAGER_START},
{"ModelDrivesAndScores", PERSISTENT},
{"ModelRandomizer", PERSISTENT},
{"ModelToDownload", CLEAR_ON_MANAGER_START},
{"ModelUI", PERSISTENT},
{"ModelVersions", PERSISTENT},
{"ModelReleasedDates", PERSISTENT},
{"CommunityFavorites", PERSISTENT},
{"UserFavorites", PERSISTENT},
{"SortModelsByDate", PERSISTENT},
{"NavigationUI", PERSISTENT},
{"NextMapSpeedLimit", CLEAR_ON_MANAGER_START},
{"NewLongAPI", PERSISTENT},
{"NNFF", PERSISTENT},
{"NNFFLite", PERSISTENT},
{"NNFFModelName", CLEAR_ON_OFFROAD_TRANSITION},
{"NoLogging", PERSISTENT},
{"NoUploads", PERSISTENT},
{"NudgelessLaneChange", PERSISTENT},
{"NumericalTemp", PERSISTENT},
{"Offset1", PERSISTENT},
{"Offset2", PERSISTENT},
{"Offset3", PERSISTENT},
{"Offset4", PERSISTENT},
{"Offset5", PERSISTENT},
{"Offset6", PERSISTENT},
{"Offset7", PERSISTENT},
{"OneLaneChange", PERSISTENT},
{"OnroadDistanceButton", PERSISTENT},
{"OnroadDistanceButtonPressed", CLEAR_ON_MANAGER_START},
{"openpilotMinutes", PERSISTENT},
{"OSMDownloadBounds", PERSISTENT},
{"OSMDownloadLocations", PERSISTENT},
{"OSMDownloadProgress", CLEAR_ON_MANAGER_START},
{"OverpassRequests", PERSISTENT},
{"PathEdgeWidth", PERSISTENT},
{"PathWidth", PERSISTENT},
{"PauseAOLOnBrake", PERSISTENT},
{"PauseLateralOnSignal", PERSISTENT},
{"PauseLateralSpeed", PERSISTENT},
{"PedalsOnUI", PERSISTENT},
{"PersonalizeOpenpilot", PERSISTENT},
{"PreferredSchedule", PERSISTENT},
{"PreviousSpeedLimit", PERSISTENT},
{"PromptDistractedVolume", PERSISTENT},
{"PromptVolume", PERSISTENT},
{"QOLLateral", PERSISTENT},
{"QOLLongitudinal", PERSISTENT},
{"QOLVisuals", PERSISTENT},
{"RadarTracksUI", PERSISTENT},
{"RainbowPath", PERSISTENT},
{"RandomEvents", PERSISTENT},
{"RandomThemes", PERSISTENT},
{"RefuseVolume", PERSISTENT},
{"RelaxedFollow", PERSISTENT},
{"RelaxedFollowHigh", PERSISTENT},
{"RelaxedJerkAcceleration", PERSISTENT},
{"RelaxedJerkDanger", PERSISTENT},
{"RelaxedJerkDeceleration", PERSISTENT},
{"RelaxedJerkSpeed", PERSISTENT},
{"RelaxedJerkSpeedDecrease", PERSISTENT},
{"RelaxedPersonalityProfile", PERSISTENT},
{"ReverseCruise", PERSISTENT},
{"RoadEdgesWidth", PERSISTENT},
{"RoadName", CLEAR_ON_MANAGER_START},
{"RoadNameUI", PERSISTENT},
{"RedPanda", PERSISTENT},
{"RemoteStartBootsComma", PERSISTENT},
{"RotatingWheel", PERSISTENT},
{"ScreenBrightness", PERSISTENT},
{"ScreenBrightnessOnroad", PERSISTENT},
{"ScreenManagement", PERSISTENT},
{"ScreenRecorder", PERSISTENT},
{"ScreenTimeout", PERSISTENT},
{"ScreenTimeoutOnroad", PERSISTENT},
{"SearchInput", PERSISTENT},
{"SecOCKeys", PERSISTENT | DONT_LOG},
{"SetSpeedLimit", PERSISTENT},
{"SetSpeedOffset", PERSISTENT},
{"ShowCEMStatus", PERSISTENT},
{"ShowCPU", PERSISTENT},
{"ShowCSCStatus", PERSISTENT},
{"ShowGPU", PERSISTENT},
{"ShowIP", PERSISTENT},
{"ShowMemoryUsage", PERSISTENT},
{"ShownToggleDescriptions", PERSISTENT},
{"ShowSLCOffset", PERSISTENT},
{"ShowSpeedLimits", PERSISTENT},
{"ShowSteering", PERSISTENT},
{"ShowStoppingPoint", PERSISTENT},
{"ShowStoppingPointMetrics", PERSISTENT},
{"ShowStorageLeft", PERSISTENT},
{"ShowStorageUsed", PERSISTENT},
{"Sidebar", PERSISTENT},
{"SignalMetrics", PERSISTENT},
{"SignalToDownload", CLEAR_ON_MANAGER_START},
{"SLCConfirmation", PERSISTENT},
{"SLCConfirmationHigher", PERSISTENT},
{"SLCConfirmationLower", PERSISTENT},
{"SLCFallback", PERSISTENT},
{"SLCLookaheadHigher", PERSISTENT},
{"SLCLookaheadLower", PERSISTENT},
{"SLCMapboxFiller", PERSISTENT},
{"SLCOverride", PERSISTENT},
{"SLCPriority1", PERSISTENT},
{"SLCPriority2", PERSISTENT},
{"SLCPriority3", PERSISTENT},
{"SNGHack", PERSISTENT},
{"SoundToDownload", CLEAR_ON_MANAGER_START},
{"SpeedLimitAccepted", CLEAR_ON_MANAGER_START},
{"SpeedLimitChangedAlert", PERSISTENT},
{"SpeedLimitController", PERSISTENT},
{"SpeedLimitFiller", PERSISTENT},
{"SpeedLimits", PERSISTENT | DONT_LOG},
{"SpeedLimitsFiltered", PERSISTENT | DONT_LOG},
{"SpeedLimitSources", PERSISTENT},
{"StandardFollow", PERSISTENT},
{"StandardFollowHigh", PERSISTENT},
{"StandardJerkAcceleration", PERSISTENT},
{"StandardJerkDanger", PERSISTENT},
{"StandardJerkDeceleration", PERSISTENT},
{"StandardJerkSpeed", PERSISTENT},
{"StandardJerkSpeedDecrease", PERSISTENT},
{"StandardPersonalityProfile", PERSISTENT},
{"StandbyMode", PERSISTENT},
{"StartAccel", PERSISTENT},
{"StartAccelStock", PERSISTENT},
{"StartupMessageBottom", PERSISTENT},
{"StartupMessageTop", PERSISTENT},
{"StaticPedalsOnUI", PERSISTENT},
{"SteerDelay", PERSISTENT},
{"SteerDelayStock", PERSISTENT},
{"SteerFriction", PERSISTENT},
{"SteerFrictionStock", PERSISTENT},
{"SteerOffset", PERSISTENT},
{"SteerOffsetStock", PERSISTENT},
{"SteerLatAccel", PERSISTENT},
{"SteerLatAccelStock", PERSISTENT},
{"SteerKP", PERSISTENT},
{"SteerKPStock", PERSISTENT},
{"SteerRatio", PERSISTENT},
{"SteerRatioStock", PERSISTENT},
{"StockDongleId", PERSISTENT},
{"StopAccel", PERSISTENT},
{"StopAccelStock", PERSISTENT},
{"StoppingDecelRate", PERSISTENT},
{"StoppingDecelRateStock", PERSISTENT},
{"StoppedTimer", PERSISTENT},
{"TacoTune", PERSISTENT},
{"TacoTuneHacks", PERSISTENT},
{"TrailerLoad", PERSISTENT},
{"TestAlert", CLEAR_ON_MANAGER_START},
{"TetheringEnabled", PERSISTENT},
{"ThemeDownloadProgress", CLEAR_ON_MANAGER_START},
{"ThemesDownloaded", PERSISTENT},
{"TinygradUpdateAvailable", PERSISTENT},
{"TogglesUpdated", PERSISTENT},
{"ToyotaDoors", PERSISTENT},
{"TrafficFollow", PERSISTENT},
{"TrafficJerkAcceleration", PERSISTENT},
{"TrafficJerkDanger", PERSISTENT},
{"TrafficJerkDeceleration", PERSISTENT},
{"TrafficJerkSpeed", PERSISTENT},
{"TrafficJerkSpeedDecrease", PERSISTENT},
{"TrafficPersonalityProfile", PERSISTENT},
{"TuningLevel", PERSISTENT},
{"TuningLevelConfirmed", PERSISTENT},
{"TurnDesires", PERSISTENT},
{"UnlimitedLength", PERSISTENT},
{"UnlockDoors", PERSISTENT},
{"Updated", PERSISTENT},
{"UpdateSpeedLimits", CLEAR_ON_MANAGER_START},
{"UpdateSpeedLimitsStatus", CLEAR_ON_MANAGER_START},
{"UpdateTinygrad", CLEAR_ON_MANAGER_START},
{"UpdateWheelImage", CLEAR_ON_MANAGER_START},
{"UseActiveTheme", CLEAR_ON_MANAGER_START},
{"UseKonikServer", PERSISTENT},
{"UseSI", PERSISTENT},
{"UseVienna", PERSISTENT},
{"VEgoStarting", PERSISTENT},
{"VEgoStartingStock", PERSISTENT},
{"VEgoStopping", PERSISTENT},
{"VEgoStoppingStock", PERSISTENT},
{"VeryLongDistanceButtonControl", PERSISTENT},
{"VoltSNG", PERSISTENT},
{"WarningImmediateVolume", PERSISTENT},
{"WarningSoftVolume", PERSISTENT},
{"WheelIcon", PERSISTENT},
{"WheelSpeed", PERSISTENT},
{"StopDistance", PERSISTENT},
{"RecoveryPower", PERSISTENT},
{"WheelToDownload", CLEAR_ON_MANAGER_START},
};
} // namespace
Params::Params(const std::string &path) {
params_prefix = "/" + util::getenv("OPENPILOT_PREFIX", "d");
params_path = ensure_params_path(params_prefix, path);
}
Params::~Params() {
if (future.valid()) {
future.wait();
}
assert(queue.empty());
}
std::vector<std::string> Params::allKeys() const {
std::vector<std::string> ret;
for (auto &p : keys) {
ret.push_back(p.first);
}
return ret;
}
bool Params::checkKey(const std::string &key) {
return keys.find(key) != keys.end();
}
ParamKeyType Params::getKeyType(const std::string &key) {
return static_cast<ParamKeyType>(keys[key]);
}
int Params::put(const char* key, const char* value, size_t value_size) {
// Information about safely and atomically writing a file: https://lwn.net/Articles/457667/
// 1) Create temp file
// 2) Write data to temp file
// 3) fsync() the temp file
// 4) rename the temp file to the real name
// 5) fsync() the containing directory
std::string tmp_path = params_path + "/.tmp_value_XXXXXX";
int tmp_fd = mkstemp((char*)tmp_path.c_str());
if (tmp_fd < 0) return -1;
int result = -1;
do {
// Write value to temp.
ssize_t bytes_written = HANDLE_EINTR(write(tmp_fd, value, value_size));
if (bytes_written < 0 || (size_t)bytes_written != value_size) {
result = -20;
break;
}
// fsync to force persist the changes.
if ((result = fsync(tmp_fd)) < 0) break;
FileLock file_lock(params_path + "/.lock");
// Move temp into place.
if ((result = rename(tmp_path.c_str(), getParamPath(key).c_str())) < 0) break;
// fsync parent directory
result = fsync_dir(getParamPath());
} while (false);
close(tmp_fd);
if (result != 0) {
::unlink(tmp_path.c_str());
}
return result;
}
int Params::remove(const std::string &key) {
FileLock file_lock(params_path + "/.lock");
int result = unlink(getParamPath(key).c_str());
if (result != 0) {
return result;
}
return fsync_dir(getParamPath());
}
std::string Params::get(const std::string &key, bool block) {
if (!block) {
return util::read_file(getParamPath(key));
} else {
// blocking read until successful
params_do_exit = 0;
void (*prev_handler_sigint)(int) = std::signal(SIGINT, params_sig_handler);
void (*prev_handler_sigterm)(int) = std::signal(SIGTERM, params_sig_handler);
std::string value;
while (!params_do_exit) {
if (value = util::read_file(getParamPath(key)); !value.empty()) {
break;
}
util::sleep_for(100); // 0.1 s
}
std::signal(SIGINT, prev_handler_sigint);
std::signal(SIGTERM, prev_handler_sigterm);
return value;
}
}
std::map<std::string, std::string> Params::readAll() {
FileLock file_lock(params_path + "/.lock");
return util::read_files_in_dir(getParamPath());
}
void Params::clearAll(ParamKeyType key_type) {
FileLock file_lock(params_path + "/.lock");
// 1) delete params of key_type
// 2) delete files that are not defined in the keys.
if (DIR *d = opendir(getParamPath().c_str())) {
struct dirent *de = NULL;
while ((de = readdir(d))) {
if (de->d_type != DT_DIR) {
auto it = keys.find(de->d_name);
if (it == keys.end() || (it->second & key_type)) {
unlink(getParamPath(de->d_name).c_str());
}
}
}
closedir(d);
}
fsync_dir(getParamPath());
}
void Params::putNonBlocking(const std::string &key, const std::string &val) {
queue.push(std::make_pair(key, val));
// start thread on demand
if (!future.valid() || future.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) {
future = std::async(std::launch::async, &Params::asyncWriteThread, this);
}
}
void Params::asyncWriteThread() {
// TODO: write the latest one if a key has multiple values in the queue.
std::pair<std::string, std::string> p;
while (queue.try_pop(p, 0)) {
// Params::put is Thread-Safe
put(p.first, p.second);
}
}
+90
View File
@@ -0,0 +1,90 @@
#pragma once
#include <future>
#include <map>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "common/queue.h"
enum ParamKeyType {
PERSISTENT = 0x02,
CLEAR_ON_MANAGER_START = 0x04,
CLEAR_ON_ONROAD_TRANSITION = 0x08,
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
DONT_LOG = 0x20,
DEVELOPMENT_ONLY = 0x40,
ALL = 0xFFFFFFFF
};
class Params {
public:
explicit Params(const std::string &path = {});
~Params();
// Not copyable.
Params(const Params&) = delete;
Params& operator=(const Params&) = delete;
std::vector<std::string> allKeys() const;
bool checkKey(const std::string &key);
ParamKeyType getKeyType(const std::string &key);
inline std::string getParamPath(const std::string &key = {}) {
return params_path + params_prefix + (key.empty() ? "" : "/" + key);
}
// Delete a value
int remove(const std::string &key);
void clearAll(ParamKeyType type);
// helpers for reading values
std::string get(const std::string &key, bool block = false);
inline bool getBool(const std::string &key, bool block = false) {
return get(key, block) == "1";
}
inline int getInt(const std::string &key, bool block = false) {
std::string value = get(key, block);
return value.empty() ? 0 : std::stoi(value);
}
inline float getFloat(const std::string &key, bool block = false) {
std::string value = get(key, block);
return value.empty() ? 0.0 : std::stof(value);
}
std::map<std::string, std::string> readAll();
// helpers for writing values
int put(const char *key, const char *val, size_t value_size);
inline int put(const std::string &key, const std::string &val) {
return put(key.c_str(), val.data(), val.size());
}
inline int putBool(const std::string &key, bool val) {
return put(key.c_str(), val ? "1" : "0", 1);
}
inline int putInt(const std::string &key, int val) {
return put(key.c_str(), std::to_string(val).c_str(), std::to_string(val).size());
}
inline int putFloat(const std::string &key, float val) {
return put(key.c_str(), std::to_string(val).c_str(), std::to_string(val).size());
}
void putNonBlocking(const std::string &key, const std::string &val);
inline void putBoolNonBlocking(const std::string &key, bool val) {
putNonBlocking(key, val ? "1" : "0");
}
inline void putIntNonBlocking(const std::string &key, int val) {
putNonBlocking(key, std::to_string(val));
}
inline void putFloatNonBlocking(const std::string &key, float val) {
putNonBlocking(key, std::to_string(val));
}
private:
void asyncWriteThread();
std::string params_path;
std::string params_prefix;
// for nonblocking write
std::future<void> future;
SafeQueue<std::pair<std::string, std::string>> queue;
};
+422 -653
View File
File diff suppressed because it is too large Load Diff
-5
View File
@@ -32,7 +32,6 @@ cdef extern from "common/params.h":
string getParamPath(string) nogil
void clearAll(ParamKeyType)
vector[string] allKeys()
ParamKeyType getKeyType(string) nogil
def ensure_bytes(v):
@@ -157,7 +156,3 @@ cdef class Params:
def all_keys(self):
return self.p.allKeys()
def get_key_type(self, key):
cdef string k = self.check_key(key)
return self.p.getKeyType(k)
Binary file not shown.
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include <cassert>
#include <string>
#include "common/params.h"
#include "common/util.h"
#include "system/hardware/hw.h"
class OpenpilotPrefix {
public:
OpenpilotPrefix(std::string prefix = {}) {
if (prefix.empty()) {
prefix = util::random_string(15);
}
msgq_path = "/dev/shm/" + prefix;
bool ret = util::create_directories(msgq_path, 0777);
assert(ret);
setenv("OPENPILOT_PREFIX", prefix.c_str(), 1);
}
~OpenpilotPrefix() {
auto param_path = Params().getParamPath();
if (util::file_exists(param_path)) {
std::string real_path = util::readlink(param_path);
system(util::string_format("rm %s -rf", real_path.c_str()).c_str());
unlink(param_path.c_str());
}
if (getenv("COMMA_CACHE") == nullptr) {
system(util::string_format("rm %s -rf", Path::download_cache_root().c_str()).c_str());
}
system(util::string_format("rm %s -rf", Path::comma_home().c_str()).c_str());
system(util::string_format("rm %s -rf", msgq_path.c_str()).c_str());
unsetenv("OPENPILOT_PREFIX");
}
private:
std::string msgq_path;
};
+52
View File
@@ -0,0 +1,52 @@
#pragma once
#include <condition_variable>
#include <mutex>
#include <queue>
template <class T>
class SafeQueue {
public:
SafeQueue() = default;
void push(const T& v) {
{
std::unique_lock lk(m);
q.push(v);
}
cv.notify_one();
}
T pop() {
std::unique_lock lk(m);
cv.wait(lk, [this] { return !q.empty(); });
T v = q.front();
q.pop();
return v;
}
bool try_pop(T& v, int timeout_ms = 0) {
std::unique_lock lk(m);
if (!cv.wait_for(lk, std::chrono::milliseconds(timeout_ms), [this] { return !q.empty(); })) {
return false;
}
v = q.front();
q.pop();
return true;
}
bool empty() const {
std::scoped_lock lk(m);
return q.empty();
}
size_t size() const {
std::scoped_lock lk(m);
return q.size();
}
private:
mutable std::mutex m;
std::condition_variable cv;
std::queue<T> q;
};
+40
View File
@@ -0,0 +1,40 @@
#include "common/ratekeeper.h"
#include <algorithm>
#include "common/swaglog.h"
#include "common/timing.h"
#include "common/util.h"
RateKeeper::RateKeeper(const std::string &name, float rate, float print_delay_threshold)
: name(name),
print_delay_threshold(std::max(0.f, print_delay_threshold)) {
interval = 1 / rate;
last_monitor_time = seconds_since_boot();
next_frame_time = last_monitor_time + interval;
}
bool RateKeeper::keepTime() {
bool lagged = monitorTime();
if (remaining_ > 0) {
util::sleep_for(remaining_ * 1000);
}
return lagged;
}
bool RateKeeper::monitorTime() {
++frame_;
last_monitor_time = seconds_since_boot();
remaining_ = next_frame_time - last_monitor_time;
bool lagged = remaining_ < 0;
if (lagged) {
if (print_delay_threshold > 0 && remaining_ < -print_delay_threshold) {
LOGW("%s lagging by %.2f ms", name.c_str(), -remaining_ * 1000);
}
next_frame_time = last_monitor_time + interval;
} else {
next_frame_time += interval;
}
return lagged;
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <cstdint>
#include <string>
class RateKeeper {
public:
RateKeeper(const std::string &name, float rate, float print_delay_threshold = 0);
~RateKeeper() {}
bool keepTime();
bool monitorTime();
inline uint64_t frame() const { return frame_; }
inline double remaining() const { return remaining_; }
private:
double interval;
double next_frame_time;
double last_monitor_time;
double remaining_ = 0;
float print_delay_threshold = 0;
uint64_t frame_ = 0;
std::string name;
};
+12 -1
View File
@@ -6,6 +6,7 @@ from collections import deque
from setproctitle import getproctitle
from openpilot.common.swaglog import cloudlog
from openpilot.system.hardware import PC
@@ -34,7 +35,17 @@ def set_realtime_priority(level: int) -> None:
def set_core_affinity(cores: list[int]) -> None:
if not PC:
os.sched_setaffinity(0, cores)
for attempt in range(3): # Retry up to 3 times
try:
os.sched_setaffinity(0, cores)
return
except OSError as e:
if e.errno == 22: # EINVAL
time.sleep(0.1) # Brief delay before retry
else:
raise # Re-raise other errors
# If all retries fail, log and continue without affinity
cloudlog.error(f"Failed to set core affinity after retries: {cores}")
def config_realtime_process(cores: int | list[int], priority: int) -> None:
+152
View File
@@ -0,0 +1,152 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "common/swaglog.h"
#include <cassert>
#include <limits>
#include <mutex>
#include <string>
#include <zmq.h>
#include <stdarg.h>
#include "third_party/json11/json11.hpp"
#include "common/version.h"
#include "system/hardware/hw.h"
class SwaglogState {
public:
SwaglogState() {
zctx = zmq_ctx_new();
sock = zmq_socket(zctx, ZMQ_PUSH);
// Timeout on shutdown for messages to be received by the logging process
int timeout = 100;
zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout));
zmq_connect(sock, Path::swaglog_ipc().c_str());
print_level = CLOUDLOG_WARNING;
if (const char* print_lvl = getenv("LOGPRINT")) {
if (strcmp(print_lvl, "debug") == 0) {
print_level = CLOUDLOG_DEBUG;
} else if (strcmp(print_lvl, "info") == 0) {
print_level = CLOUDLOG_INFO;
} else if (strcmp(print_lvl, "warning") == 0) {
print_level = CLOUDLOG_WARNING;
}
}
ctx_j = json11::Json::object{};
if (char* dongle_id = getenv("DONGLE_ID")) {
ctx_j["dongle_id"] = dongle_id;
}
if (char* git_origin = getenv("GIT_ORIGIN")) {
ctx_j["origin"] = git_origin;
}
if (char* git_branch = getenv("GIT_BRANCH")) {
ctx_j["branch"] = git_branch;
}
if (char* git_commit = getenv("GIT_COMMIT")) {
ctx_j["commit"] = git_commit;
}
if (char* daemon_name = getenv("MANAGER_DAEMON")) {
ctx_j["daemon"] = daemon_name;
}
ctx_j["version"] = COMMA_VERSION;
ctx_j["dirty"] = !getenv("CLEAN");
ctx_j["device"] = Hardware::get_name();
}
~SwaglogState() {
zmq_close(sock);
zmq_ctx_destroy(zctx);
}
void log(int levelnum, const char* filename, int lineno, const char* func, const char* msg, const std::string& log_s) {
std::lock_guard lk(lock);
if (levelnum >= print_level) {
printf("%s: %s\n", filename, msg);
}
zmq_send(sock, log_s.data(), log_s.length(), ZMQ_NOBLOCK);
}
std::mutex lock;
void* zctx = nullptr;
void* sock = nullptr;
int print_level;
json11::Json::object ctx_j;
};
bool LOG_TIMESTAMPS = getenv("LOG_TIMESTAMPS");
uint32_t NO_FRAME_ID = std::numeric_limits<uint32_t>::max();
static void cloudlog_common(int levelnum, const char* filename, int lineno, const char* func,
char* msg_buf, const json11::Json::object &msg_j={}) {
static SwaglogState s;
json11::Json::object log_j = json11::Json::object {
{"ctx", s.ctx_j},
{"levelnum", levelnum},
{"filename", filename},
{"lineno", lineno},
{"funcname", func},
{"created", seconds_since_epoch()}
};
if (msg_j.empty()) {
log_j["msg"] = msg_buf;
} else {
log_j["msg"] = msg_j;
}
std::string log_s;
log_s += (char)levelnum;
((json11::Json)log_j).dump(log_s);
s.log(levelnum, filename, lineno, func, msg_buf, log_s);
free(msg_buf);
}
void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) {
va_list args;
va_start(args, fmt);
char* msg_buf = nullptr;
int ret = vasprintf(&msg_buf, fmt, args);
va_end(args);
if (ret <= 0 || !msg_buf) return;
cloudlog_common(levelnum, filename, lineno, func, msg_buf);
}
void cloudlog_t_common(int levelnum, const char* filename, int lineno, const char* func,
uint32_t frame_id, const char* fmt, va_list args) {
if (!LOG_TIMESTAMPS) return;
char* msg_buf = nullptr;
int ret = vasprintf(&msg_buf, fmt, args);
if (ret <= 0 || !msg_buf) return;
json11::Json::object tspt_j = json11::Json::object{
{"event", msg_buf},
{"time", std::to_string(nanos_since_boot())}
};
if (frame_id < NO_FRAME_ID) {
tspt_j["frame_id"] = std::to_string(frame_id);
}
tspt_j = json11::Json::object{{"timestamp", tspt_j}};
cloudlog_common(levelnum, filename, lineno, func, msg_buf, tspt_j);
}
void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) {
va_list args;
va_start(args, fmt);
cloudlog_t_common(levelnum, filename, lineno, func, NO_FRAME_ID, fmt, args);
va_end(args);
}
void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func,
uint32_t frame_id, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
cloudlog_t_common(levelnum, filename, lineno, func, frame_id, fmt, args);
va_end(args);
}
+76
View File
@@ -0,0 +1,76 @@
#pragma once
#include "common/timing.h"
#define CLOUDLOG_DEBUG 10
#define CLOUDLOG_INFO 20
#define CLOUDLOG_WARNING 30
#define CLOUDLOG_ERROR 40
#define CLOUDLOG_CRITICAL 50
#ifdef __GNUC__
#define SWAG_LOG_CHECK_FMT(a, b) __attribute__ ((format (printf, a, b)))
#else
#define SWAG_LOG_CHECK_FMT(a, b)
#endif
void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) SWAG_LOG_CHECK_FMT(5, 6);
void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) SWAG_LOG_CHECK_FMT(5, 6);
void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func,
uint32_t frame_id, const char* fmt, ...) SWAG_LOG_CHECK_FMT(6, 7);
#define cloudlog(lvl, fmt, ...) cloudlog_e(lvl, __FILE__, __LINE__, \
__func__, \
fmt, ## __VA_ARGS__)
#define cloudlog_t(lvl, ...) cloudlog_te(lvl, __FILE__, __LINE__, \
__func__, \
__VA_ARGS__)
#define cloudlog_rl(burst, millis, lvl, fmt, ...) \
{ \
static uint64_t __begin = 0; \
static int __printed = 0; \
static int __missed = 0; \
\
int __burst = (burst); \
int __millis = (millis); \
uint64_t __ts = nanos_since_boot(); \
\
if (!__begin) { __begin = __ts; } \
\
if (__begin + __millis*1000000ULL < __ts) { \
if (__missed) { \
cloudlog(CLOUDLOG_WARNING, "cloudlog: %d messages suppressed", __missed); \
} \
__begin = 0; \
__printed = 0; \
__missed = 0; \
} \
\
if (__printed < __burst) { \
cloudlog(lvl, fmt, ## __VA_ARGS__); \
__printed++; \
} else { \
__missed++; \
} \
}
#define LOGT(...) cloudlog_t(CLOUDLOG_DEBUG, __VA_ARGS__)
#define LOGD(fmt, ...) cloudlog(CLOUDLOG_DEBUG, fmt, ## __VA_ARGS__)
#define LOG(fmt, ...) cloudlog(CLOUDLOG_INFO, fmt, ## __VA_ARGS__)
#define LOGW(fmt, ...) cloudlog(CLOUDLOG_WARNING, fmt, ## __VA_ARGS__)
#define LOGE(fmt, ...) cloudlog(CLOUDLOG_ERROR, fmt, ## __VA_ARGS__)
#define LOGD_100(fmt, ...) cloudlog_rl(2, 100, CLOUDLOG_DEBUG, fmt, ## __VA_ARGS__)
#define LOG_100(fmt, ...) cloudlog_rl(2, 100, CLOUDLOG_INFO, fmt, ## __VA_ARGS__)
#define LOGW_100(fmt, ...) cloudlog_rl(2, 100, CLOUDLOG_WARNING, fmt, ## __VA_ARGS__)
#define LOGE_100(fmt, ...) cloudlog_rl(2, 100, CLOUDLOG_ERROR, fmt, ## __VA_ARGS__)
+51
View File
@@ -0,0 +1,51 @@
#pragma once
#include <cstdint>
#include <ctime>
#ifdef __APPLE__
#define CLOCK_BOOTTIME CLOCK_MONOTONIC
#endif
static inline uint64_t nanos_since_boot() {
struct timespec t;
clock_gettime(CLOCK_BOOTTIME, &t);
return t.tv_sec * 1000000000ULL + t.tv_nsec;
}
static inline double millis_since_boot() {
struct timespec t;
clock_gettime(CLOCK_BOOTTIME, &t);
return t.tv_sec * 1000.0 + t.tv_nsec * 1e-6;
}
static inline double seconds_since_boot() {
struct timespec t;
clock_gettime(CLOCK_BOOTTIME, &t);
return (double)t.tv_sec + t.tv_nsec * 1e-9;
}
static inline uint64_t nanos_since_epoch() {
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return t.tv_sec * 1000000000ULL + t.tv_nsec;
}
static inline double seconds_since_epoch() {
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return (double)t.tv_sec + t.tv_nsec * 1e-9;
}
// you probably should use nanos_since_boot instead
static inline uint64_t nanos_monotonic() {
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
return t.tv_sec * 1000000000ULL + t.tv_nsec;
}
static inline uint64_t nanos_monotonic_raw() {
struct timespec t;
clock_gettime(CLOCK_MONOTONIC_RAW, &t);
return t.tv_sec * 1000000000ULL + t.tv_nsec;
}
+100
View File
@@ -0,0 +1,100 @@
#define _USE_MATH_DEFINES
#include "common/transformations/coordinates.hpp"
#include <iostream>
#include <cmath>
#include <eigen3/Eigen/Dense>
double a = 6378137; // lgtm [cpp/short-global-name]
double b = 6356752.3142; // lgtm [cpp/short-global-name]
double esq = 6.69437999014 * 0.001; // lgtm [cpp/short-global-name]
double e1sq = 6.73949674228 * 0.001;
static Geodetic to_degrees(Geodetic geodetic){
geodetic.lat = RAD2DEG(geodetic.lat);
geodetic.lon = RAD2DEG(geodetic.lon);
return geodetic;
}
static Geodetic to_radians(Geodetic geodetic){
geodetic.lat = DEG2RAD(geodetic.lat);
geodetic.lon = DEG2RAD(geodetic.lon);
return geodetic;
}
ECEF geodetic2ecef(Geodetic g){
g = to_radians(g);
double xi = sqrt(1.0 - esq * pow(sin(g.lat), 2));
double x = (a / xi + g.alt) * cos(g.lat) * cos(g.lon);
double y = (a / xi + g.alt) * cos(g.lat) * sin(g.lon);
double z = (a / xi * (1.0 - esq) + g.alt) * sin(g.lat);
return {x, y, z};
}
Geodetic ecef2geodetic(ECEF e){
// Convert from ECEF to geodetic using Ferrari's methods
// https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#Ferrari.27s_solution
double x = e.x;
double y = e.y;
double z = e.z;
double r = sqrt(x * x + y * y);
double Esq = a * a - b * b;
double F = 54 * b * b * z * z;
double G = r * r + (1 - esq) * z * z - esq * Esq;
double C = (esq * esq * F * r * r) / (pow(G, 3));
double S = cbrt(1 + C + sqrt(C * C + 2 * C));
double P = F / (3 * pow((S + 1 / S + 1), 2) * G * G);
double Q = sqrt(1 + 2 * esq * esq * P);
double r_0 = -(P * esq * r) / (1 + Q) + sqrt(0.5 * a * a*(1 + 1.0 / Q) - P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r);
double U = sqrt(pow((r - esq * r_0), 2) + z * z);
double V = sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z);
double Z_0 = b * b * z / (a * V);
double h = U * (1 - b * b / (a * V));
double lat = atan((z + e1sq * Z_0) / r);
double lon = atan2(y, x);
return to_degrees({lat, lon, h});
}
LocalCoord::LocalCoord(Geodetic g, ECEF e){
init_ecef << e.x, e.y, e.z;
g = to_radians(g);
ned2ecef_matrix <<
-sin(g.lat)*cos(g.lon), -sin(g.lon), -cos(g.lat)*cos(g.lon),
-sin(g.lat)*sin(g.lon), cos(g.lon), -cos(g.lat)*sin(g.lon),
cos(g.lat), 0, -sin(g.lat);
ecef2ned_matrix = ned2ecef_matrix.transpose();
}
NED LocalCoord::ecef2ned(ECEF e) {
Eigen::Vector3d ecef;
ecef << e.x, e.y, e.z;
Eigen::Vector3d ned = (ecef2ned_matrix * (ecef - init_ecef));
return {ned[0], ned[1], ned[2]};
}
ECEF LocalCoord::ned2ecef(NED n) {
Eigen::Vector3d ned;
ned << n.n, n.e, n.d;
Eigen::Vector3d ecef = (ned2ecef_matrix * ned) + init_ecef;
return {ecef[0], ecef[1], ecef[2]};
}
NED LocalCoord::geodetic2ned(Geodetic g) {
ECEF e = ::geodetic2ecef(g);
return ecef2ned(e);
}
Geodetic LocalCoord::ned2geodetic(NED n){
ECEF e = ned2ecef(n);
return ::ecef2geodetic(e);
}
+144
View File
@@ -0,0 +1,144 @@
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
#include <eigen3/Eigen/Dense>
#include "common/transformations/orientation.hpp"
#include "common/transformations/coordinates.hpp"
Eigen::Quaterniond ensure_unique(Eigen::Quaterniond quat){
if (quat.w() > 0){
return quat;
} else {
return Eigen::Quaterniond(-quat.w(), -quat.x(), -quat.y(), -quat.z());
}
}
Eigen::Quaterniond euler2quat(Eigen::Vector3d euler){
Eigen::Quaterniond q;
q = Eigen::AngleAxisd(euler(2), Eigen::Vector3d::UnitZ())
* Eigen::AngleAxisd(euler(1), Eigen::Vector3d::UnitY())
* Eigen::AngleAxisd(euler(0), Eigen::Vector3d::UnitX());
return ensure_unique(q);
}
Eigen::Vector3d quat2euler(Eigen::Quaterniond quat){
// TODO: switch to eigen implementation if the range of the Euler angles doesn't matter anymore
// Eigen::Vector3d euler = quat.toRotationMatrix().eulerAngles(2, 1, 0);
// return {euler(2), euler(1), euler(0)};
double gamma = atan2(2 * (quat.w() * quat.x() + quat.y() * quat.z()), 1 - 2 * (quat.x()*quat.x() + quat.y()*quat.y()));
double asin_arg_clipped = std::clamp(2 * (quat.w() * quat.y() - quat.z() * quat.x()), -1.0, 1.0);
double theta = asin(asin_arg_clipped);
double psi = atan2(2 * (quat.w() * quat.z() + quat.x() * quat.y()), 1 - 2 * (quat.y()*quat.y() + quat.z()*quat.z()));
return {gamma, theta, psi};
}
Eigen::Matrix3d quat2rot(Eigen::Quaterniond quat){
return quat.toRotationMatrix();
}
Eigen::Quaterniond rot2quat(const Eigen::Matrix3d &rot){
return ensure_unique(Eigen::Quaterniond(rot));
}
Eigen::Matrix3d euler2rot(Eigen::Vector3d euler){
return quat2rot(euler2quat(euler));
}
Eigen::Vector3d rot2euler(const Eigen::Matrix3d &rot){
return quat2euler(rot2quat(rot));
}
Eigen::Matrix3d rot_matrix(double roll, double pitch, double yaw){
return euler2rot({roll, pitch, yaw});
}
Eigen::Matrix3d rot(Eigen::Vector3d axis, double angle){
Eigen::Quaterniond q;
q = Eigen::AngleAxisd(angle, axis);
return q.toRotationMatrix();
}
Eigen::Vector3d ecef_euler_from_ned(ECEF ecef_init, Eigen::Vector3d ned_pose) {
/*
Using Rotations to Build Aerospace Coordinate Systems
Don Koks
https://apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf
*/
LocalCoord converter = LocalCoord(ecef_init);
Eigen::Vector3d zero = ecef_init.to_vector();
Eigen::Vector3d x0 = converter.ned2ecef({1, 0, 0}).to_vector() - zero;
Eigen::Vector3d y0 = converter.ned2ecef({0, 1, 0}).to_vector() - zero;
Eigen::Vector3d z0 = converter.ned2ecef({0, 0, 1}).to_vector() - zero;
Eigen::Vector3d x1 = rot(z0, ned_pose(2)) * x0;
Eigen::Vector3d y1 = rot(z0, ned_pose(2)) * y0;
Eigen::Vector3d z1 = rot(z0, ned_pose(2)) * z0;
Eigen::Vector3d x2 = rot(y1, ned_pose(1)) * x1;
Eigen::Vector3d y2 = rot(y1, ned_pose(1)) * y1;
Eigen::Vector3d z2 = rot(y1, ned_pose(1)) * z1;
Eigen::Vector3d x3 = rot(x2, ned_pose(0)) * x2;
Eigen::Vector3d y3 = rot(x2, ned_pose(0)) * y2;
x0 = Eigen::Vector3d(1, 0, 0);
y0 = Eigen::Vector3d(0, 1, 0);
z0 = Eigen::Vector3d(0, 0, 1);
double psi = atan2(x3.dot(y0), x3.dot(x0));
double theta = atan2(-x3.dot(z0), sqrt(pow(x3.dot(x0), 2) + pow(x3.dot(y0), 2)));
y2 = rot(z0, psi) * y0;
z2 = rot(y2, theta) * z0;
double phi = atan2(y3.dot(z2), y3.dot(y2));
return {phi, theta, psi};
}
Eigen::Vector3d ned_euler_from_ecef(ECEF ecef_init, Eigen::Vector3d ecef_pose){
/*
Using Rotations to Build Aerospace Coordinate Systems
Don Koks
https://apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf
*/
LocalCoord converter = LocalCoord(ecef_init);
Eigen::Vector3d x0 = Eigen::Vector3d(1, 0, 0);
Eigen::Vector3d y0 = Eigen::Vector3d(0, 1, 0);
Eigen::Vector3d z0 = Eigen::Vector3d(0, 0, 1);
Eigen::Vector3d x1 = rot(z0, ecef_pose(2)) * x0;
Eigen::Vector3d y1 = rot(z0, ecef_pose(2)) * y0;
Eigen::Vector3d z1 = rot(z0, ecef_pose(2)) * z0;
Eigen::Vector3d x2 = rot(y1, ecef_pose(1)) * x1;
Eigen::Vector3d y2 = rot(y1, ecef_pose(1)) * y1;
Eigen::Vector3d z2 = rot(y1, ecef_pose(1)) * z1;
Eigen::Vector3d x3 = rot(x2, ecef_pose(0)) * x2;
Eigen::Vector3d y3 = rot(x2, ecef_pose(0)) * y2;
Eigen::Vector3d zero = ecef_init.to_vector();
x0 = converter.ned2ecef({1, 0, 0}).to_vector() - zero;
y0 = converter.ned2ecef({0, 1, 0}).to_vector() - zero;
z0 = converter.ned2ecef({0, 0, 1}).to_vector() - zero;
double psi = atan2(x3.dot(y0), x3.dot(x0));
double theta = atan2(-x3.dot(z0), sqrt(pow(x3.dot(x0), 2) + pow(x3.dot(y0), 2)));
y2 = rot(z0, psi) * y0;
z2 = rot(y2, theta) * z0;
double phi = atan2(y3.dot(z2), y3.dot(y2));
return {phi, theta, psi};
}
+288
View File
@@ -0,0 +1,288 @@
#include "common/util.h"
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <cassert>
#include <cerrno>
#include <cstring>
#include <dirent.h>
#include <fstream>
#include <iomanip>
#include <random>
#include <sstream>
#ifdef __linux__
#include <sys/prctl.h>
#include <sys/syscall.h>
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <sched.h>
#endif // __linux__
namespace util {
void set_thread_name(const char* name) {
#ifdef __linux__
// pthread_setname_np is dumb (fails instead of truncates)
prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
#endif
}
int set_realtime_priority(int level) {
#ifdef __linux__
long tid = syscall(SYS_gettid);
// should match python using chrt
struct sched_param sa;
memset(&sa, 0, sizeof(sa));
sa.sched_priority = level;
return sched_setscheduler(tid, SCHED_FIFO, &sa);
#else
return -1;
#endif
}
int set_core_affinity(std::vector<int> cores) {
#ifdef __linux__
long tid = syscall(SYS_gettid);
cpu_set_t cpu;
CPU_ZERO(&cpu);
for (const int n : cores) {
CPU_SET(n, &cpu);
}
return sched_setaffinity(tid, sizeof(cpu), &cpu);
#else
return -1;
#endif
}
int set_file_descriptor_limit(uint64_t limit_val) {
struct rlimit limit;
int status;
if ((status = getrlimit(RLIMIT_NOFILE, &limit)) < 0)
return status;
limit.rlim_cur = limit_val;
if ((status = setrlimit(RLIMIT_NOFILE, &limit)) < 0)
return status;
return 0;
}
std::string read_file(const std::string& fn) {
std::ifstream f(fn, std::ios::binary | std::ios::in);
if (f.is_open()) {
f.seekg(0, std::ios::end);
int size = f.tellg();
if (f.good() && size > 0) {
std::string result(size, '\0');
f.seekg(0, std::ios::beg);
f.read(result.data(), size);
// return either good() or has reached end-of-file (e.g. /sys/power/wakeup_count)
if (f.good() || f.eof()) {
result.resize(f.gcount());
return result;
}
}
// fallback for files created on read, e.g. procfs
std::stringstream buffer;
buffer << f.rdbuf();
return buffer.str();
}
return std::string();
}
std::map<std::string, std::string> read_files_in_dir(const std::string &path) {
std::map<std::string, std::string> ret;
DIR *d = opendir(path.c_str());
if (!d) return ret;
struct dirent *de = NULL;
while ((de = readdir(d))) {
if (de->d_type != DT_DIR) {
ret[de->d_name] = util::read_file(path + "/" + de->d_name);
}
}
closedir(d);
return ret;
}
int write_file(const char* path, const void* data, size_t size, int flags, mode_t mode) {
int fd = HANDLE_EINTR(open(path, flags, mode));
if (fd == -1) {
return -1;
}
ssize_t n = HANDLE_EINTR(write(fd, data, size));
close(fd);
return (n >= 0 && (size_t)n == size) ? 0 : -1;
}
FILE* safe_fopen(const char* filename, const char* mode) {
FILE* fp = NULL;
do {
fp = fopen(filename, mode);
} while ((nullptr == fp) && (errno == EINTR));
return fp;
}
size_t safe_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) {
size_t written = 0;
do {
size_t ret = ::fwrite((void*)((char *)ptr + written * size), size, count - written, stream);
if (ret == 0 && errno != EINTR) break;
written += ret;
} while (written != count);
return written;
}
int safe_fflush(FILE *stream) {
int ret = EOF;
do {
ret = fflush(stream);
} while ((EOF == ret) && (errno == EINTR));
return ret;
}
int safe_ioctl(int fd, unsigned long request, void *argp) {
int ret;
do {
ret = ioctl(fd, request, argp);
} while ((ret == -1) && (errno == EINTR));
return ret;
}
std::string readlink(const std::string &path) {
char buff[4096];
ssize_t len = ::readlink(path.c_str(), buff, sizeof(buff)-1);
if (len != -1) {
buff[len] = '\0';
return std::string(buff);
}
return "";
}
bool file_exists(const std::string& fn) {
struct stat st = {};
return stat(fn.c_str(), &st) != -1;
}
static bool createDirectory(std::string dir, mode_t mode) {
auto verify_dir = [](const std::string& dir) -> bool {
struct stat st = {};
return (stat(dir.c_str(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR);
};
// remove trailing /'s
while (dir.size() > 1 && dir.back() == '/') {
dir.pop_back();
}
// try to mkdir this directory
if (mkdir(dir.c_str(), mode) == 0) return true;
if (errno == EEXIST) return verify_dir(dir);
if (errno != ENOENT) return false;
// mkdir failed because the parent dir doesn't exist, so try to create it
size_t slash = dir.rfind('/');
if ((slash == std::string::npos || slash < 1) ||
!createDirectory(dir.substr(0, slash), mode)) {
return false;
}
// try again
if (mkdir(dir.c_str(), mode) == 0) return true;
return errno == EEXIST && verify_dir(dir);
}
bool create_directories(const std::string& dir, mode_t mode) {
if (dir.empty()) return false;
return createDirectory(dir, mode);
}
std::string getenv(const char* key, std::string default_val) {
const char* val = ::getenv(key);
return val ? val : default_val;
}
int getenv(const char* key, int default_val) {
const char* val = ::getenv(key);
return val ? atoi(val) : default_val;
}
float getenv(const char* key, float default_val) {
const char* val = ::getenv(key);
return val ? atof(val) : default_val;
}
std::string hexdump(const uint8_t* in, const size_t size) {
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (size_t i = 0; i < size; i++) {
ss << std::setw(2) << static_cast<unsigned int>(in[i]);
}
return ss.str();
}
int random_int(int min, int max) {
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> dist(min, max);
return dist(rng);
}
std::string random_string(std::string::size_type length) {
const std::string chrs = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::mt19937 rg{std::random_device{}()};
std::uniform_int_distribution<std::string::size_type> pick(0, chrs.length() - 1);
std::string s;
s.reserve(length);
while (length--) {
s += chrs[pick(rg)];
}
return s;
}
bool starts_with(const std::string &s1, const std::string &s2) {
return strncmp(s1.c_str(), s2.c_str(), s2.size()) == 0;
}
bool ends_with(const std::string& s, const std::string& suffix) {
return s.size() >= suffix.size() &&
strcmp(s.c_str() + (s.size() - suffix.size()), suffix.c_str()) == 0;
}
std::string check_output(const std::string& command) {
char buffer[128];
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
if (!pipe) {
return "";
}
while (fgets(buffer, std::size(buffer), pipe.get()) != nullptr) {
result += std::string(buffer);
}
return result;
}
bool system_time_valid() {
// Default to March 30, 2024
tm min_tm = {.tm_year = 2024 - 1900, .tm_mon = 2, .tm_mday = 30};
time_t min_date = mktime(&min_tm);
struct stat st;
if (stat("/lib/systemd/systemd", &st) == 0) {
min_date = std::max(min_date, st.st_mtime + 86400); // Add 1 day (86400 seconds)
}
return time(nullptr) > min_date;
}
} // namespace util
+187
View File
@@ -0,0 +1,187 @@
#pragma once
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <csignal>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
// keep trying if x gets interrupted by a signal
#define HANDLE_EINTR(x) \
({ \
decltype(x) ret_; \
int try_cnt = 0; \
do { \
ret_ = (x); \
} while (ret_ == -1 && errno == EINTR && try_cnt++ < 100); \
ret_; \
})
#ifndef sighandler_t
typedef void (*sighandler_t)(int sig);
#endif
const double MILE_TO_KM = 1.609344;
const double KM_TO_MILE = 1. / MILE_TO_KM;
const double MS_TO_KPH = 3.6;
const double MS_TO_MPH = MS_TO_KPH * KM_TO_MILE;
const double METER_TO_MILE = KM_TO_MILE / 1000.0;
const double METER_TO_FOOT = 3.28084;
const double FOOT_TO_METER = 1. / METER_TO_FOOT;
const double CM_TO_INCH = 1. / 2.54;
const double INCH_TO_CM = 1. / CM_TO_INCH;
namespace util {
void set_thread_name(const char* name);
int set_realtime_priority(int level);
int set_core_affinity(std::vector<int> cores);
int set_file_descriptor_limit(uint64_t limit);
// ***** math helpers *****
// map x from [a1, a2] to [b1, b2]
template <typename T>
T map_val(T x, T a1, T a2, T b1, T b2) {
x = std::clamp(x, a1, a2);
T ra = a2 - a1;
T rb = b2 - b1;
return (x - a1) * rb / ra + b1;
}
// ***** string helpers *****
template <typename... Args>
std::string string_format(const std::string& format, Args... args) {
size_t size = snprintf(nullptr, 0, format.c_str(), args...) + 1;
std::unique_ptr<char[]> buf(new char[size]);
snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1);
}
std::string getenv(const char* key, std::string default_val = "");
int getenv(const char* key, int default_val);
float getenv(const char* key, float default_val);
std::string hexdump(const uint8_t* in, const size_t size);
bool starts_with(const std::string &s1, const std::string &s2);
bool ends_with(const std::string &s, const std::string &suffix);
// ***** random helpers *****
int random_int(int min, int max);
std::string random_string(std::string::size_type length);
// **** file helpers *****
std::string read_file(const std::string& fn);
std::map<std::string, std::string> read_files_in_dir(const std::string& path);
int write_file(const char* path, const void* data, size_t size, int flags = O_WRONLY, mode_t mode = 0664);
FILE* safe_fopen(const char* filename, const char* mode);
size_t safe_fwrite(const void * ptr, size_t size, size_t count, FILE * stream);
int safe_fflush(FILE *stream);
int safe_ioctl(int fd, unsigned long request, void *argp);
std::string readlink(const std::string& path);
bool file_exists(const std::string& fn);
bool create_directories(const std::string &dir, mode_t mode);
std::string check_output(const std::string& command);
bool system_time_valid();
inline void sleep_for(const int milliseconds) {
if (milliseconds > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}
}
} // namespace util
class ExitHandler {
public:
ExitHandler() {
std::signal(SIGINT, (sighandler_t)set_do_exit);
std::signal(SIGTERM, (sighandler_t)set_do_exit);
#ifndef __APPLE__
std::signal(SIGPWR, (sighandler_t)set_do_exit);
#endif
}
inline static std::atomic<bool> power_failure = false;
inline static std::atomic<int> signal = 0;
inline operator bool() { return do_exit; }
inline ExitHandler& operator=(bool v) {
signal = 0;
do_exit = v;
return *this;
}
private:
static void set_do_exit(int sig) {
#ifndef __APPLE__
power_failure = (sig == SIGPWR);
#endif
signal = sig;
do_exit = true;
}
inline static std::atomic<bool> do_exit = false;
};
struct unique_fd {
unique_fd(int fd = -1) : fd_(fd) {}
unique_fd& operator=(unique_fd&& uf) {
fd_ = uf.fd_;
uf.fd_ = -1;
return *this;
}
~unique_fd() {
if (fd_ != -1) close(fd_);
}
operator int() const { return fd_; }
int fd_;
};
class FirstOrderFilter {
public:
FirstOrderFilter(float x0, float ts, float dt, bool initialized = true) {
k_ = (dt / ts) / (1.0 + dt / ts);
x_ = x0;
initialized_ = initialized;
}
inline float update(float x) {
if (initialized_) {
x_ = (1. - k_) * x_ + k_ * x;
} else {
initialized_ = true;
x_ = x;
}
return x_;
}
inline void reset(float x) { x_ = x; }
inline float x(){ return x_; }
private:
float x_, k_;
bool initialized_;
};
template<typename T>
void update_max_atomic(std::atomic<T>& max, T const& value) {
T prev = max;
while (prev < value && !max.compare_exchange_weak(prev, value)) {}
}
typedef struct Rect {
int x;
int y;
int w;
int h;
} Rect;
+11
View File
@@ -0,0 +1,11 @@
#include <string>
#include "common/watchdog.h"
#include "common/util.h"
const std::string watchdog_fn_prefix = "/dev/shm/wd_"; // + <pid>
bool watchdog_kick(uint64_t ts) {
static std::string fn = watchdog_fn_prefix + std::to_string(getpid());
return util::write_file(fn.c_str(), &ts, sizeof(ts), O_WRONLY | O_CREAT) > 0;
}
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include <cstdint>
bool watchdog_kick(uint64_t ts);
+1 -1
View File
@@ -1 +1 @@
/data/themes/theme_packs/frog-animated/distance_icons
/data/openpilot/openpilot/frogpilot/assets/stock_theme/distance_icons
@@ -1 +1 @@
/data/themes/steering_wheels/pedro.gif
/data/themes/steering_wheels/dancing_duck.gif
+31 -14
View File
@@ -7,8 +7,8 @@ from pathlib import Path
from openpilot.frogpilot.common.frogpilot_utilities import delete_file, is_url_pingable
GITHUB_URL = "https://raw.githubusercontent.com/FrogAi/FrogPilot-Resources"
GITLAB_URL = "https://gitlab.com/FrogAi/FrogPilot-Resources/-/raw"
GITHUB_URL = "https://raw.githubusercontent.com/firestar5683/StarPilot-Resources"
GITLAB_URL = "https://gitlab.com/firestar5683/FrogPilot-Resources/-/raw"
def check_github_rate_limit():
try:
@@ -29,13 +29,15 @@ def check_github_rate_limit():
print(f"Error checking GitHub rate limit: {error}")
return False
def download_file(cancel_param, destination, progress_param, url, download_param, params_memory):
def download_file(cancel_param, destination, progress_param, url, download_param, params_memory, allow_unknown_size=False, suppress_errors=False):
try:
destination.parent.mkdir(parents=True, exist_ok=True)
total_size = get_remote_file_size(url)
if total_size == 0:
total_size = get_remote_file_size(url, suppress_errors=suppress_errors or allow_unknown_size)
if total_size == 0 and not allow_unknown_size:
if not url.endswith(".gif"):
if suppress_errors:
return
handle_error(None, "Download invalid...", "Download invalid...", download_param, progress_param, params_memory)
return
@@ -56,24 +58,30 @@ def download_file(cancel_param, destination, progress_param, url, download_param
temp_file.write(chunk)
downloaded_size += len(chunk)
progress = (downloaded_size / total_size) * 100
if progress != 100:
params_memory.put(progress_param, f"{progress:.0f}%")
else:
if total_size > 0:
progress = (downloaded_size / total_size) * 100
if progress != 100:
params_memory.put(progress_param, f"{progress:.0f}%")
else:
params_memory.put(progress_param, "Verifying authenticity...")
elif downloaded_size > 0:
params_memory.put(progress_param, "Verifying authenticity...")
temp_file_path.rename(destination)
except Exception as error:
if suppress_errors:
return
handle_request_error(error, destination, download_param, progress_param, params_memory)
def get_remote_file_size(url):
def get_remote_file_size(url, suppress_errors=False):
try:
response = requests.head(url, headers={"Accept-Encoding": "identity"}, timeout=10)
response.raise_for_status()
return int(response.headers.get("Content-Length", 0))
except Exception as error:
handle_request_error(error, None, None, None, None)
if not suppress_errors:
handle_request_error(error, None, None, None, None)
return 0
def get_repository_url():
@@ -88,7 +96,7 @@ def handle_error(destination, error_message, error, download_param, progress_par
if destination:
delete_file(destination)
if progress_param and "404" not in error_message:
if params_memory and progress_param and "404" not in error_message:
print(f"Error occurred: {error}")
params_memory.put(progress_param, error_message)
params_memory.remove(download_param)
@@ -104,8 +112,17 @@ def handle_request_error(error, destination, download_param, progress_param, par
error_message = error_map.get(type(error), "Unexpected error")
handle_error(destination, f"Failed: {error_message}", error, download_param, progress_param, params_memory)
def verify_download(file_path, url):
remote_file_size = get_remote_file_size(url)
def verify_download(file_path, url, allow_unknown_size=False):
remote_file_size = get_remote_file_size(url, suppress_errors=allow_unknown_size)
if remote_file_size == 0 and allow_unknown_size:
if not file_path.is_file():
print(f"File not found: {file_path}")
return False
if file_path.stat().st_size == 0:
print(f"File is empty: {file_path}")
return False
return True
if remote_file_size == 0:
print(f"Error fetching remote size for {file_path}")
@@ -1,44 +1,44 @@
{
"LaneLines": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 40,
"green": 195,
"blue": 169,
"alpha": 255
},
"LeadMarker": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 40,
"green": 195,
"blue": 169,
"alpha": 255
},
"Path": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 40,
"green": 195,
"blue": 169,
"alpha": 255
},
"PathEdge": {
"red": 18,
"green": 107,
"blue": 54,
"alpha": 242
"red": 238,
"green": 226,
"blue": 95,
"alpha": 255
},
"Sidebar1": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 40,
"green": 195,
"blue": 169,
"alpha": 255
},
"Sidebar2": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 238,
"green": 226,
"blue": 95,
"alpha": 255
},
"Sidebar3": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 238,
"green": 0,
"blue": 0,
"alpha": 255
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 58 KiB

@@ -1,44 +1,44 @@
{
"LaneLines": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 99,
"green": 123,
"blue": 244,
"alpha": 255
},
"LeadMarker": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 99,
"green": 123,
"blue": 244,
"alpha": 255
},
"Path": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 99,
"green": 123,
"blue": 244,
"alpha": 255
},
"PathEdge": {
"red": 18,
"green": 107,
"blue": 54,
"alpha": 242
"red": 255,
"green": 255,
"blue": 255,
"alpha": 255
},
"Sidebar1": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 255,
"green": 0,
"blue": 0,
"alpha": 255
},
"Sidebar2": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 255,
"green": 255,
"blue": 255,
"alpha": 255
},
"Sidebar3": {
"red": 23,
"green": 134,
"blue": 68,
"alpha": 242
"red": 99,
"green": 123,
"blue": 244,
"alpha": 255
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Some files were not shown because too many files have changed in this diff Show More