Skip to content

Commit 6b350fa

Browse files
committed
Merge branch 'main' of https://github.com/C5Lab/projectZero
2 parents 91e8a5d + 05a3cbb commit 6b350fa

15 files changed

Lines changed: 469 additions & 118 deletions

.github/workflows/esp32c5-build-master.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ on:
99
push:
1010
branches: [main]
1111
paths:
12-
- 'ESP32C5/main/main.c'
12+
- 'ESP32C5/**'
1313
- 'FLIPPER/**'
14+
- '.github/scripts/**'
15+
- '.github/workflows/esp32c5-build-master.yml'
1416
release:
1517
types: [published, edited]
1618

@@ -393,7 +395,7 @@ jobs:
393395
BUILD_TAG: ${{ steps.meta.outputs.tag }}
394396
run: |
395397
set -euo pipefail
396-
python -c "import os, json; from pathlib import Path; version=os.getenv('FW_VERSION') or os.getenv('BUILD_TAG'); build=os.getenv('BUILD_TAG','manual'); manifest={'name':'projectZero ESP32-C5','version':version,'build':build,'chipFamily':'ESP32-C5','parts':[{'path':'firmware/bootloader.bin','offset':8192},{'path':'firmware/partition-table.bin','offset':32768},{'path':'firmware/projectZero.bin','offset':131072}]}; Path('docs/manifest.json').write_text(json.dumps(manifest, indent=2))"
398+
python -c "import os, json; from pathlib import Path; version=os.getenv('FW_VERSION') or os.getenv('BUILD_TAG'); build=os.getenv('BUILD_TAG','manual'); manifest={'name':'projectZero ESP32-C5','version':version,'build':build,'chipFamily':'ESP32-C5','parts':[{'path':'firmware/bootloader.bin','offset':8192},{'path':'firmware/partition-table.bin','offset':32768},{'path':'firmware/projectZero.bin','offset':131072},{'path':'firmware/projectZero.bin','offset':4259840}]}; Path('docs/manifest.json').write_text(json.dumps(manifest, indent=2))"
397399
- name: Upload Pages artifact
398400
uses: actions/upload-pages-artifact@v4
399401
with:

.github/workflows/pages-webflasher.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ jobs:
8888
TAG: ${{ steps.meta.outputs.tag }}
8989
run: |
9090
set -euo pipefail
91-
python -c "import os, json; from pathlib import Path; tag=os.getenv('TAG','manual'); manifest={'name':'projectZero ESP32-C5','version':tag,'build':tag,'chipFamily':'ESP32-C5','parts':[{'path':'firmware/bootloader.bin','offset':8192},{'path':'firmware/partition-table.bin','offset':32768},{'path':'firmware/projectZero.bin','offset':131072}]}; Path('docs/manifest.json').write_text(json.dumps(manifest, indent=2) + '\\n')"
91+
python -c "import os, json; from pathlib import Path; tag=os.getenv('TAG','manual'); manifest={'name':'projectZero ESP32-C5','version':tag,'build':tag,'chipFamily':'ESP32-C5','parts':[{'path':'firmware/bootloader.bin','offset':8192},{'path':'firmware/partition-table.bin','offset':32768},{'path':'firmware/projectZero.bin','offset':131072},{'path':'firmware/projectZero.bin','offset':4259840}]}; Path('docs/manifest.json').write_text(json.dumps(manifest, indent=2) + '\\n')"
9292
9393
- name: Upload Pages artifact
9494
uses: actions/upload-pages-artifact@v3

ESP32C5/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Important notes:
2222
- The bootloader and partition table must be flashed once via UART after enabling OTA/rollback. OTA only updates the app image.
2323
- Rollback happens if the new image crashes before it is marked valid.
2424
- Auto-OTA on IP is disabled; use the CLI commands below.
25+
- On ESP32-C5 N8R8 (8 MB flash), each OTA slot is `0x3F0000` bytes (~3.94 MiB). Two full `4 MiB` slots do not fit because boot metadata and data partitions occupy the space before `0x20000`.
26+
- A UART/web flash that writes only `ota_0` leaves `ota_1` empty until the first OTA update. The bundled `binaries-esp32c5/flash_board.py` now seeds `ota_1` by default by also writing the app at `0x410000`.
2527

2628
### OTA Commands
2729
- `wifi_connect <SSID> <Password> [ota] [<IP> <Netmask> <GW> [DNS1] [DNS2]]`: Connect to Wi-Fi as STA. Add `ota` to trigger OTA right after DHCP, or pass static IP settings (optionally with DNS).
13.2 KB
Binary file not shown.
0 Bytes
Binary file not shown.

ESP32C5/binaries-esp32c5/flash_board.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,18 @@ def ensure_packages():
2626
# Colors
2727
RED = "\033[91m"; GREEN = "\033[92m"; YELLOW = "\033[93m"; CYAN = "\033[96m"; RESET = "\033[0m"
2828

29-
VERSION = "v02"
29+
VERSION = "v04"
3030
DEFAULT_BAUD = 460800 # Original default; can be overridden via CLI
3131
REQUIRED_FILES = ["bootloader.bin", "partition-table.bin", "projectZero.bin"]
3232

33-
# >>> DO NOT CHANGE: keep your original offsets <<<
33+
# Keep these offsets in sync with partitions.csv.
3434
OFFSETS = {
3535
"bootloader.bin": "0x2000", # as requested
3636
"partition-table.bin": "0x8000",
3737
# partitions.csv defines ota_0 at 0x20000, so app must be flashed there
3838
"projectZero.bin": "0x20000",
39+
# Optional: seed ota_1 so both OTA slots are bootable after a UART flash
40+
"projectZero_ota1.bin": "0x410000",
3941
}
4042

4143
def check_files():
@@ -76,7 +78,7 @@ def erase_all(port, baud=DEFAULT_BAUD):
7678
print(f"{RED}Erase failed with code {res.returncode}.{RESET}")
7779
sys.exit(res.returncode)
7880

79-
def do_flash(port, baud=DEFAULT_BAUD, flash_mode="dio", flash_freq="80m"):
81+
def do_flash(port, baud=DEFAULT_BAUD, flash_mode="dio", flash_freq="80m", seed_ota1=True):
8082
cmd = [
8183
sys.executable, "-m", "esptool",
8284
"-p", port,
@@ -92,6 +94,8 @@ def do_flash(port, baud=DEFAULT_BAUD, flash_mode="dio", flash_freq="80m"):
9294
OFFSETS["partition-table.bin"], "partition-table.bin",
9395
OFFSETS["projectZero.bin"], "projectZero.bin",
9496
]
97+
if seed_ota1:
98+
cmd.extend([OFFSETS["projectZero_ota1.bin"], "projectZero.bin"])
9599
print(f"{CYAN}Flashing command:{RESET} {' '.join(cmd)}")
96100
res = subprocess.run(cmd)
97101
if res.returncode != 0:
@@ -154,6 +158,8 @@ def main():
154158
help=f"Optional baud rate (default: {DEFAULT_BAUD})")
155159
parser.add_argument("--monitor", action="store_true", help="Open serial monitor after flashing")
156160
parser.add_argument("--erase", action="store_true", help="Full erase before flashing (fixes stale NVS/partitions)")
161+
parser.add_argument("--no-seed-ota1", action="store_true",
162+
help="Do not flash projectZero.bin into ota_1 at 0x410000")
157163
parser.add_argument("--flash-mode", default="dio", choices=["dio", "qio", "dout", "qout"],
158164
help="Flash mode (default: dio)")
159165
parser.add_argument("--flash-freq", default="80m", choices=["80m", "60m", "40m", "26m", "20m"],
@@ -173,11 +179,15 @@ def main():
173179

174180
print(f"{GREEN}Detected serial port: {port}{RESET}")
175181
print(f"{YELLOW}Tip: release the BOOT button before programming finishes.{RESET}")
182+
seed_ota1 = not args.no_seed_ota1
183+
if seed_ota1:
184+
print(f"{YELLOW}Seeding both OTA slots: ota_0 @ {OFFSETS['projectZero.bin']} and ota_1 @ {OFFSETS['projectZero_ota1.bin']}{RESET}")
176185

177186
if args.erase:
178187
erase_all(port, args.baud)
179188

180-
do_flash(port, baud=args.baud, flash_mode=args.flash_mode, flash_freq=args.flash_freq)
189+
do_flash(port, baud=args.baud, flash_mode=args.flash_mode, flash_freq=args.flash_freq,
190+
seed_ota1=seed_ota1)
181191

182192
reset_to_app(port)
183193

0 Bytes
Binary file not shown.
4.09 KB
Binary file not shown.

0 commit comments

Comments
 (0)