Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
2444970
restore c3
thftgr Jun 26, 2026
d3d4470
Update `get_expected_signature` to use `panda` instance for MCU type …
thftgr Jun 26, 2026
93ea7e8
Add USB support to `pandad` with fallback to SPI communication
thftgr Jun 26, 2026
27a8188
Expand modem support for EC20 and simplify ICCID checks
thftgr Jun 26, 2026
66df50d
Add SIM state tracking and optimize ICCID polling frequency
thftgr Jun 26, 2026
f6e86ea
add carrot-agnos
thftgr Jun 26, 2026
e0d3e22
Reorder `start_carrot_recovery` for proper initialization sequence
thftgr Jun 26, 2026
b6fc94a
Install `jeepney` dependency if missing during initialization
thftgr Jun 26, 2026
3a38470
Update Agnos URLs and add `agnos-tici.json`
thftgr Jun 27, 2026
b039097
Adjust Agnos manifest selection based on model type
thftgr Jun 27, 2026
39ad5f6
Move `jeepney` installation to AGNOS update block
thftgr Jun 27, 2026
6483898
Adjust internet wait logic in AGNOS version check
thftgr Jun 27, 2026
db90d81
Add debug logs for AGNOS updater variables to improve visibility
thftgr Jun 27, 2026
1ca5a93
Add debug logs for device model and manifest path in AGNOS updater
thftgr Jun 27, 2026
42ce0d0
Add debug log for AGNOS updater completion
thftgr Jun 27, 2026
3e26691
Reorder `start_carrot_recovery` call for improved initialization logic
thftgr Jun 27, 2026
7e9513f
fix screen action (#417)
jominki354 Jun 29, 2026
b6c1f1a
Merge remote-tracking branch 'origin/carrot-wip' into tcw3-x
thftgr Jun 29, 2026
28468bb
Use IFE path for AR0231 cameras to avoid CAM-ICP/BPS recovery
thftgr Jun 30, 2026
d7a9fbb
"Remove redundant AR0231 IFE path handling and placeholder entries in…
thftgr Jun 30, 2026
2cfa49c
"Add logic for BPS blob index mapping and warnings for mismatched sen…
thftgr Jun 30, 2026
b57b10d
"Fix `get_bps_blob_index` call by using `sensor.get()` for proper poi…
thftgr Jun 30, 2026
9967148
"Add warning and enforce IFE path for AR0231 to prevent CAM-ICP/BPS r…
thftgr Jun 30, 2026
cd1c82e
Add helper function for BPS blob index selection and update related l…
thftgr Jun 30, 2026
caaef67
Improve first frame sync logic for Spectra camera and add detailed de…
thftgr Jun 30, 2026
889fe3a
Revert ""Add warning and enforce IFE path for AR0231 to prevent CAM-I…
thftgr Jun 30, 2026
343b6d2
Revert ""Fix `get_bps_blob_index` call by using `sensor.get()` for pr…
thftgr Jun 30, 2026
3aaa4b5
Revert ""Add logic for BPS blob index mapping and warnings for mismat…
thftgr Jun 30, 2026
42c3611
Revert ""Remove redundant AR0231 IFE path handling and placeholder en…
thftgr Jun 30, 2026
3150317
Revert "Use IFE path for AR0231 cameras to avoid CAM-ICP/BPS recovery"
thftgr Jun 30, 2026
0151ddb
Merge branch 'thftgr/carrot-wip-c3' into carrot-wip-c3
thftgr Jun 30, 2026
ae03c4d
add yt
jominki354 Jul 1, 2026
bfab1ff
f
jominki354 Jul 1, 2026
81a8ff3
f
jominki354 Jul 1, 2026
7ff3320
f
jominki354 Jul 1, 2026
30535b3
f
jominki354 Jul 1, 2026
8351a36
f
jominki354 Jul 1, 2026
d7c6dbf
f
jominki354 Jul 1, 2026
59a8030
f
jominki354 Jul 1, 2026
0c8c000
f
jominki354 Jul 1, 2026
ab8ac47
f
jominki354 Jul 1, 2026
c5b5cf8
f
jominki354 Jul 1, 2026
075d4c0
f
jominki354 Jul 1, 2026
a7a3c15
f
jominki354 Jul 1, 2026
7c28bce
f
jominki354 Jul 1, 2026
d992678
f
jominki354 Jul 1, 2026
4b24f5d
f
jominki354 Jul 1, 2026
e48573c
f
jominki354 Jul 1, 2026
5c7b5c6
f
jominki354 Jul 1, 2026
ae8757b
f
jominki354 Jul 1, 2026
2a927ac
f
jominki354 Jul 1, 2026
02f5b21
f
jominki354 Jul 1, 2026
7892f21
f
jominki354 Jul 1, 2026
259c34d
f
jominki354 Jul 1, 2026
ea93601
f
jominki354 Jul 1, 2026
de87f08
f
jominki354 Jul 1, 2026
a6b67d9
f
jominki354 Jul 1, 2026
ce55f56
f
jominki354 Jul 1, 2026
97fbfde
f
jominki354 Jul 1, 2026
1189e74
f
jominki354 Jul 1, 2026
5d545b6
f
jominki354 Jul 1, 2026
d2acc1e
f
jominki354 Jul 1, 2026
38fa919
f
jominki354 Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cereal/log.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,8 @@ struct Event {
livestreamRoadEncodeData @120 :EncodeData;
livestreamWideRoadEncodeData @121 :EncodeData;
livestreamDriverEncodeData @122 :EncodeData;
youtubeRoadEncodeData @152 :EncodeData;
youtubeRoadEncodeIdx @153 :EncodeIndex;

# *********** Custom: reserved for forks ***********

Expand Down
1 change: 1 addition & 0 deletions cereal/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def __init__(self, should_log: bool, frequency: float, decimation: Optional[int]
"livestreamWideRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
"livestreamRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
"livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM),
"youtubeRoadEncodeData": (False, 20., None, QueueSize.BIG),
"customReservedRawData0": (True, 0.),
"customReservedRawData1": (True, 0.),
"customReservedRawData2": (True, 0.),
Expand Down
3 changes: 3 additions & 0 deletions common/params_keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ClusterHudRadarDisplay", {PERSISTENT, INT, "0"}},
{"ClusterHudRadarSourceColor", {PERSISTENT, INT, "0"}},
{"RecordRoadCam", {PERSISTENT, INT, "0"}},
{"CarrotYouTubeLive", {PERSISTENT, INT, "0"}},
{"CarrotYouTubeQuality", {PERSISTENT, INT, "0"}},
{"CarrotYouTubeTimestamp", {PERSISTENT, INT, "0"}},
{"HDPuse", {PERSISTENT, INT, "0"}},

{"AutoCruiseControl", {PERSISTENT, INT, "0"}},
Expand Down
36 changes: 34 additions & 2 deletions launch_chffrplus.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,44 @@ function agnos_init {

# Check if AGNOS update is required
if [ $(< /VERSION) != "$AGNOS_VERSION" ]; then
echo "Waiting for internet..."

timeout=0
while [ $timeout -lt 120 ]; do
if getent hosts pypi.org >/dev/null 2>&1; then
break
fi
echo "Waiting for internet... (${timeout})"
sleep 5
timeout=$((timeout+5))

done

if python3 -c "import jeepney" > /dev/null 2>&1; then
echo "jeepney already installed."
else
echo "jeepney installing to pydeps."
python3 -m pip install --target "$PYDEPS" --upgrade jeepney
fi

AGNOS_PY="$DIR/system/hardware/tici/agnos.py"
MANIFEST="$DIR/system/hardware/tici/agnos.json"
MODEL="$(tr -d '\000\r\n' 2>/dev/null < /sys/firmware/devicetree/base/model | tr '[:upper:]' '[:lower:]')"
MODEL="${MODEL#comma }"
if [ "$MODEL" = "c3" ] || [ "$MODEL" = "tici" ]; then
MANIFEST="$DIR/system/hardware/tici/agnos-tici.json"
fi
if $AGNOS_PY --verify $MANIFEST; then
sudo reboot
fi
$DIR/system/hardware/tici/updater $AGNOS_PY $MANIFEST
echo "AGNOS_PY=${AGNOS_PY}"
echo "MANIFEST=${MANIFEST}"
echo "MODEL=${MODEL}"
if ! python3 $DIR/system/ui/updater.py $AGNOS_PY $MANIFEST; then
echo "python updater failed, falling back to bundled updater"
$DIR/system/hardware/tici/updater $AGNOS_PY $MANIFEST
fi
echo "end updater $AGNOS_PY $MANIFEST"
fi
}

Expand Down Expand Up @@ -124,14 +156,14 @@ function launch {
PYDEPS="$DIR/pydeps"
mkdir -p "$PYDEPS"
export PYTHONPATH="$PYDEPS:$PWD${PYTHONPATH:+:$PYTHONPATH}"

start_carrot_recovery

# hardware specific init
if [ -f /AGNOS ]; then
agnos_init
fi


FORCE_REBUILD=0
invalidate_modeld_build_if_needed
invalidate_native_build_if_needed
Expand Down
2 changes: 2 additions & 0 deletions selfdrive/carrot/server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
CARROT_WEB_SETTINGS_PATH = os.path.join(CARROT_STATE_DIR, "web_settings.json")
CARROT_SETTING_FAVORITES_PATH = os.path.join(CARROT_STATE_DIR, "setting_favorites.json")
CARROT_SETTING_PROFILES_PATH = os.path.join(CARROT_STATE_DIR, "setting_profiles.json")
CARROT_YOUTUBE_LIVE_STATE_PATH = os.path.join(CARROT_STATE_DIR, "youtube_live.json")
CARROT_YOUTUBE_LIVE_SECRET_PATH = os.path.join(CARROT_STATE_DIR, "youtube_live_secret.json")

# Dashcam
DASHCAM_ROOT = "/data/media/0/realdata"
Expand Down
2 changes: 2 additions & 0 deletions selfdrive/carrot/server/features/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
vision_test,
web_settings,
ws,
youtube_live,
)


Expand All @@ -39,5 +40,6 @@ def register_all(app: web.Application) -> None:
dashcam.register(app)
screenrecord.register(app)
tools.register(app)
youtube_live.register(app)
vision_test.register(app)
vision_diag.register(app)
86 changes: 86 additions & 0 deletions selfdrive/carrot/server/features/youtube_live.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from __future__ import annotations

import asyncio

from aiohttp import web

from ..services.youtube_live import YouTubeLiveService


YOUTUBE_LIVE_APP_KEY = "youtube_live_service"


def _service(request: web.Request) -> YouTubeLiveService:
service = request.app.get(YOUTUBE_LIVE_APP_KEY)
if not isinstance(service, YouTubeLiveService):
raise web.HTTPServiceUnavailable(text="youtube live service unavailable")
return service


async def youtube_live_context(app: web.Application):
service = YouTubeLiveService()
app[YOUTUBE_LIVE_APP_KEY] = service
await service.start()
try:
yield
finally:
await service.stop()
app.pop(YOUTUBE_LIVE_APP_KEY, None)


async def api_status(request: web.Request) -> web.Response:
return web.json_response({"ok": True, **_service(request).status()})


async def api_set_stream_key(request: web.Request) -> web.Response:
try:
body = await request.json()
except Exception:
return web.json_response({"ok": False, "error": "invalid json"}, status=400)
key = body.get("stream_key", body.get("key", ""))
try:
status = _service(request).set_stream_key(str(key or ""))
except ValueError as exc:
return web.json_response({"ok": False, "error": str(exc)}, status=400)
return web.json_response({"ok": True, **status})


async def api_get_stream_key(request: web.Request) -> web.Response:
stream_key = _service(request).get_stream_key()
return web.json_response({"ok": True, "configured": bool(stream_key), "stream_key": stream_key})


async def api_clear_stream_key(request: web.Request) -> web.Response:
return web.json_response({"ok": True, **_service(request).clear_stream_key()})


async def api_test(request: web.Request) -> web.Response:
result = await asyncio.to_thread(_service(request).test_config)
return web.json_response(result, status=200 if result.get("ok") else 409)


async def api_validate_stream_key(request: web.Request) -> web.Response:
body = {}
if request.can_read_body:
try:
body = await request.json()
except Exception:
return web.json_response({"ok": False, "error": "invalid json"}, status=400)
key = body.get("stream_key", body.get("key")) if isinstance(body, dict) else None
result = await asyncio.to_thread(_service(request).validate_stream_key, key)
return web.json_response(result, status=200 if result.get("ok") else 409)


async def api_diagnostics(request: web.Request) -> web.Response:
return web.json_response({"ok": True, "diagnostics": _service(request).diagnostics()})


def register(app: web.Application) -> None:
app.cleanup_ctx.append(youtube_live_context)
app.router.add_get("/api/youtube_live/status", api_status)
app.router.add_get("/api/youtube_live/diagnostics", api_diagnostics)
app.router.add_get("/api/youtube_live/stream_key", api_get_stream_key)
app.router.add_post("/api/youtube_live/stream_key", api_set_stream_key)
app.router.add_post("/api/youtube_live/stream_key/validate", api_validate_stream_key)
app.router.add_delete("/api/youtube_live/stream_key", api_clear_stream_key)
app.router.add_post("/api/youtube_live/test", api_test)
Loading
Loading