Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 68 additions & 0 deletions BUILD_AGNOS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# AGNOS 18.4+ fork installer template

The Qt-based `installer_source_agnos.cc` in this repo is **legacy**. The active template is built from **raylib** `selfdrive/ui/installer/installer.cc` in your openpilot fork with `INSTALLER_USE_PLACEHOLDERS=1`.

## 1. Build template on C3 (AGNOS 18.4+)

```bash
cd /data/openpilot
git pull
scons extras -j$(nproc) selfdrive/ui/installer/installers/installer_fork_template
```

Output:

```text
selfdrive/ui/installer/installers/installer_fork_template
```

## 2. Copy template into this PHP project

From your PC (replace IP):

```bash
scp [email protected]:/data/openpilot/selfdrive/ui/installer/installers/installer_fork_template \
E:/openpilot-installer-generator/fork/installer_openpilot_agnos
```

Or on-device:

```bash
cp /data/openpilot/selfdrive/ui/installer/installers/installer_fork_template \
/path/to/openpilot-installer-generator/fork/installer_openpilot_agnos
```

**Important:** Replace the old Qt template binary. The previous `installer_openpilot_agnos` will not run on AGNOS 18.4.

## 3. Deploy PHP

Host `fork/` on any PHP-capable web server. Example URL during C3 setup:

```text
https://your-host/fork/mouxangithub/master-c3
```

Aliases (see `fork/index.php`):

| Short | Installs |
|-------|----------|
| `mouxan/master-c3` | `github.com/mouxangithub/openpilot` @ `master-c3` |
| `mouxangithub` | default branch `master-c3` |

Device User-Agent must include `AGNOSSetup` (factory setup does this automatically).

## 4. Placeholder slots (must match `installer_config.php`)

| Slot | Length | PHP replaces |
|------|--------|--------------|
| `27182818284590452353602874713526624977572470936999595` | 53 | `{username}/openpilot.git` (NUL padded) |
| `161803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748475408807538689175212663386222353693179318006076672635443338908659593958290563832266131992829026788067520876689250171169620703222104321626954862629631361` | 255 | branch (NUL padded, empty = default branch) |
| `314159265358979323846264338327950288419` | 39 | loading message (space padded) |

Full git URL in binary: `https://github.com/` + username slot.

## 5. Rebuild template when

- AGNOS major version changes
- `installer.cc` or linked libraries change
- `installer_config.php` slot strings change
42 changes: 19 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,34 @@
# openpilot-installer-generator
A PHP webpage that uses string replacements to generate a binary on the fly that you can enter at setup in NEOS.

## What is this?
Previously to install a custom fork from scratch, you would enter `https://openpilot.comma.ai` in the Custom Software prompt on your device, then `ssh` in later and clone the actual fork you want. Now you can enter a URL during set up to install any openpilot fork available on GitHub without first cloning stock.
PHP site that patches a **prebuilt AGNOS installer ELF** with your fork username, branch, and loading message.

## Usage
The syntax is pretty simple, with up to 3 arguments you can pass the generator site: `https://smiskol.com/fork/[username]/{branch}/{loading_msg}`
## AGNOS 18.4+ (comma four)

The old Qt template in this repo **does not work** on AGNOS 18.4+. Use the raylib template built from openpilot:

Where `username` is the required username of the fork, `branch` is the branch to clone, and `loading_msg` is the text it displays when cloning the repo (`Installing {loading_msg}`). `branch` and `loading_msg` are optional.
1. Build `installer_fork_template` in your openpilot fork (`scons extras`)
2. Copy it to `fork/installer_openpilot_agnos`
3. Deploy `fork/` to PHP hosting

- If `branch` is left blank (https://smiskol.com/fork/commaai), git will clone the default branch on GitHub.
- If `loading_msg` is left blank, then the installer will display `Installing {username}` unless the fork has a custom loading message (check the index.php for aliases).
- While `username` is required if you visit the website on your desktop, if you `wget` the site or enter just `/fork` during set up, it will install the release2 branch of stock openpilot.
**Full steps:** [BUILD_AGNOS.md](BUILD_AGNOS.md)

**Example:** https://smiskol.com/fork/sshane installs the Stock Additions fork.
Example setup URL:

The main `index.php` file looks at your user-agent to decide which installer to serve. If `NEOSSetup` is present in your user-agent, then the Android-based installer is served. If `AGNOSSetup` is present, then it serves the Ubuntu-based installer for the comma three.
```text
https://your-host/fork/mouxangithub/master-c3
```

## Aliases
Defined in the [index.php](fork/index.php) file, aliases allow for more quickly installing a fork with a long username.
## Legacy (NEOS / old AGNOS)

- To install [dragonpilot](https://github.com/dragonpilot-community/dragonpilot), you can simply use the following URL which uses the `devel-i18n` branch by default: https://smiskol.com/fork/dp
- To install [Stock Additions](https://github.com/sshane/openpilot), my fork, enter the URL: https://smiskol.com/fork/shane
- To install [stock openpilot](https://github.com/commaai/openpilot), enter the URL: https://smiskol.com/fork/commaai or just https://smiskol.com/fork
- [NEOS installer source](/source/installer_source_neos.c)
- [Legacy Qt AGNOS source](/source/installer_source_agnos.cc) (reference only)

If you are a fork developer, have a repository that is not named `openpilot`, and want to allow users to install with this tool, you can take advantage of GitHub's internal compatibility aliasing and just temporaily rename your fork to `openpilot` and rename it back. You can see an example of this in action with "https://github.com/dragonpilot-community/openpilot" redirecting to "https://github.com/dragonpilot-community/dragonpilot".
## Usage

## Misc
### Custom loading message without branch
If you want to specify a custom loading message but use the default branch (not passing in a branch), you can pass an underscore for the branch. For example: https://smiskol.com/fork/shane/_/some%20additions%20or%20something
`https://your-host/fork/[username]/{branch}/{loading_msg}`

### Source code to build the custom installer
- [Source code for NEOS installer](/source/installer_source_neos.c)
- [Source code for AGNOS installer](/source/installer_source_agnos.cc)
During comma four factory setup, enter the URL under **Custom Software**. The device sends `User-Agent: AGNOSSetup-<version>` and receives a patched ELF.

---

[Idea](https://discord.com/channels/469524606043160576/524594418628558878/827726757201051658) by [nelsonjchen](https://github.com/nelsonjchen) on the [comma.ai community Discord](https://discord.comma.ai/)!
73 changes: 48 additions & 25 deletions fork/build_agnos.php
Original file line number Diff line number Diff line change
@@ -1,44 +1,67 @@
<?php
# Constants
define("E", "27182818284590452353602874713526624977572470936999595"); # placeholder for username, includes "openpilot" repo name
define("PI", "314159265358979323846264338327950288419"); # placeholder for loading msg
define("GOLDEN", "161803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748475408807538689175212663386222353693179318006076672635443338908659593958290563832266131992829026788067520876689250171169620703222104321626954862629631361"); # placeholder for branch
require_once __DIR__ . "/installer_config.php";

# Replaces placeholder with input + any needed NULs, plus does length checking
function fill_in_arg($placeholder, $replace_with, $binary, $padding, $arg_type) {
$placeholder_len = mb_strlen($placeholder);
if ($placeholder_len - strlen($replace_with) < 0) { echo "Error: Invalid " . $arg_type . " length!"; exit; }
$placeholder_len = strlen($placeholder);
if ($placeholder_len < strlen($replace_with)) {
echo "Error: Invalid " . $arg_type . " length!";
exit;
}

$replace_with .= str_repeat($padding, $placeholder_len - strlen($replace_with));
return str_replace($placeholder, $replace_with, $binary);
}

$template_path = __DIR__ . "/" . INSTALLER_TEMPLATE_BINARY;
if (!file_exists($template_path)) {
echo "Error: missing template binary " . INSTALLER_TEMPLATE_BINARY . ". Build selfdrive/ui/installer/installers/installer_fork_template on AGNOS 18.4+ and copy it here.";
exit;
}

# Load installer binary
$installer_binary = file_get_contents(getcwd() . "/installer_openpilot_agnos"); # load the unmodified installer

$username = $_GET["username"];
$branch = $_GET["branch"];
$loading_msg = $_GET["loading_msg"];
$installer_binary = file_get_contents($template_path);

if ($username == "") exit; # discount assertions
if ($loading_msg == "") exit;
$username = $_GET["username"] ?? "";
$branch = $_GET["branch"] ?? "";
$loading_msg = $_GET["loading_msg"] ?? "";

if ($username == "") {
echo "Error: username required";
exit;
}
if ($loading_msg == "") {
$loading_msg = $username;
}

# Handle username replacement:
$installer_binary = fill_in_arg(E, $username . "/openpilot.git", $installer_binary, "\0", "username");
$username = substr($username, 0, 39);
$branch = substr($branch, 0, 255);
$loading_msg = substr($loading_msg, 0, 39);

# Handle branch replacement (3 occurrences):
$installer_binary = fill_in_arg(GOLDEN, $branch, $installer_binary, "\0", "branch");
$installer_binary = fill_in_arg(
INSTALLER_USERNAME_SLOT,
$username . "/openpilot.git",
$installer_binary,
"\0",
"username"
);

# Handle loading message replacement:
$installer_binary = fill_in_arg(PI, $loading_msg, $installer_binary, " ", "loading message"); // QT actually displays null characters
$installer_binary = fill_in_arg(
INSTALLER_BRANCH_SLOT,
$branch,
$installer_binary,
"\0",
"branch"
);

$installer_binary = fill_in_arg(
INSTALLER_LOADING_MSG_SLOT,
$loading_msg,
$installer_binary,
" ",
"loading message"
);

# Now download
header("Content-Type: application/octet-stream");
header("Content-Length: " . strlen($installer_binary)); # we want actual bytes
header("Content-Length: " . strlen($installer_binary));
header("Content-Disposition: attachment; filename=installer_openpilot");
echo $installer_binary; # downloads without saving to a file
echo $installer_binary;
exit;
?>
4 changes: 2 additions & 2 deletions fork/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
define("IS_NEOS", str_contains(USER_AGENT, "NEOSSetup"));
define("IS_AGNOS", str_contains(USER_AGENT, "AGNOSSetup"));
define("IS_WGET", str_contains(USER_AGENT, "Wget"));
# Use release2 if NEOS, else release3 (careful! wget assumes comma three)
# Use release2 if NEOS, else release3 (careful! wget assumes comma four)
define("DEFAULT_STOCK_BRANCH", IS_NEOS ? "release2" : "release3");

define("WEBSITE_URL", "https://smiskol.com");
Expand Down Expand Up @@ -106,7 +106,7 @@ public function __construct($name, $default_branch, $aliases, $repo, $loading_ms
echo '<h3 style="position: absolute; bottom: 0; left: 0; width: 100%; text-align: center;"><a href="https://github.com/sshane/openpilot-installer-generator" style="color: 30323D;">💾 Installer Generator GitHub Repo</a></h3>';

if ($username == "") {
echo '<h3 style="color: #30323D;">🎉 now supports comma three! 🎉<h3>';
echo '<h3 style="color: #30323D;">🎉 now supports comma four! 🎉<h3>';
echo "</br><h2>Enter this URL on your device during setup with the format:</h2>";
echo "<h2><a href='" . BASE_DIR . "/sshane/SA-master'><span>" . WEBSITE_URL . BASE_DIR . "/username/branch</span></a></h2>";
echo "</br><h3>Or complete the request on your desktop to download a custom installer.</h3>";
Expand Down
12 changes: 12 additions & 0 deletions fork/installer_config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
// Must stay in sync with selfdrive/ui/installer/installer.cc (INSTALLER_USE_PLACEHOLDERS).

define("INSTALLER_USERNAME_SLOT", "27182818284590452353602874713526624977572470936999595");
define("INSTALLER_BRANCH_SLOT", "161803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748475408807538689175212663386222353693179318006076672635443338908659593958290563832266131992829026788067520876689250171169620703222104321626954862629631361");
define("INSTALLER_LOADING_MSG_SLOT", "314159265358979323846264338327950288419");

define("INSTALLER_USERNAME_SLOT_LEN", 53); // 39-char GitHub user + "/openpilot.git"
define("INSTALLER_BRANCH_SLOT_LEN", 255);
define("INSTALLER_LOADING_MSG_SLOT_LEN", 39);

define("INSTALLER_TEMPLATE_BINARY", "installer_openpilot_agnos");
Binary file modified fork/installer_openpilot_agnos
Binary file not shown.
13 changes: 13 additions & 0 deletions scripts/copy_template_from_device.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Copy raylib installer_fork_template from a comma four device into this repo.
set -euo pipefail

DEVICE="${1:[email protected]}"
REMOTE="${2:-/data/openpilot/selfdrive/ui/installer/installers/installer_fork_template}"
DEST="$(cd "$(dirname "$0")/.." && pwd)/fork/installer_openpilot_agnos"

echo "Copying ${DEVICE}:${REMOTE} -> ${DEST}"
scp "${DEVICE}:${REMOTE}" "${DEST}"
chmod +x "${DEST}"
file "${DEST}"
echo "Done. Deploy fork/ to your PHP host and use https://your-host/fork/mouxangithub/master-c3"
Loading