-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathMakefile
More file actions
475 lines (418 loc) · 22 KB
/
Copy pathMakefile
File metadata and controls
475 lines (418 loc) · 22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
.PHONY: all
all: submodules fprime-venv zephyr generate-if-needed build
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
##@ Dependencies
.PHONY: submodules
submodules: ## Initialize and update git submodules
@git submodule update --init --recursive
@echo "Applying fprime-gds version patch..."
@cd lib/fprime && \
if git apply --check ../../patches/fprime-gds-version.patch 2>/dev/null; then \
git apply ../../patches/fprime-gds-version.patch && \
echo "✓ Applied fprime-gds version patch"; \
elif git apply --reverse --check ../../patches/fprime-gds-version.patch 2>/dev/null; then \
echo "⚠ Patch already applied"; \
else \
echo "❌ Error: Unable to apply patch. Run 'cd lib/fprime && git status' to check."; \
exit 1; \
fi
export VIRTUAL_ENV ?= $(shell pwd)/fprime-venv
.PHONY: fprime-venv
FPRIME_YAMCS_MAIN ?= $(shell pwd)/fprime-venv/lib/python*/site-packages/fprime_yamcs/__main__.py
fprime-venv: uv ## Create a virtual environment
@$(UV) venv fprime-venv --allow-existing
@$(UV) pip install --prerelease=allow --requirement requirements.txt --overrides yamcs/pyyaml-override.txt
@echo "Applying fprime-yamcs noapp/path patch..."
@TARGET=$$(ls $(FPRIME_YAMCS_MAIN) 2>/dev/null | head -1); \
if [ -z "$$TARGET" ]; then echo "⚠ fprime-yamcs not found, skipping patch"; exit 0; fi; \
PATCH_DIR=$$(dirname $$TARGET); \
if grep -q 'venv_bin = str(Path(sys.executable).parent)' $$TARGET; then \
echo "⚠ fprime-yamcs patch already applied"; \
elif patch --dry-run -p2 -d $$PATCH_DIR < patches/fprime-yamcs-noapp-path.patch > /dev/null 2>&1; then \
patch -p2 -d $$PATCH_DIR < patches/fprime-yamcs-noapp-path.patch && echo "✓ Applied fprime-yamcs patch"; \
else \
echo "❌ Error: Unable to apply fprime-yamcs patch. Run 'ls $$TARGET' to check."; exit 1; \
fi
@echo "Applying fprime-yamcs-events CPU fix..."
@EVENTS_PROC=$$(ls $(shell pwd)/fprime-venv/lib/python*/site-packages/fprime_yamcs/events/processor.py 2>/dev/null | head -1); \
if [ -z "$$EVENTS_PROC" ]; then echo "⚠ events processor not found, skipping"; exit 0; fi; \
$(VIRTUAL_ENV)/bin/python tools/apply-events-cpu-fix.py "$$EVENTS_PROC"
@echo "Applying fprime-yamcs instance config fix..."
@INST_CFG=$$(ls $(shell pwd)/fprime-venv/lib/python*/site-packages/fprime_yamcs/yamcs/src/main/yamcs/etc/yamcs.fprime-project.yaml 2>/dev/null | head -1); \
if [ -z "$$INST_CFG" ]; then echo "⚠ instance config not found, skipping"; exit 0; fi; \
$(VIRTUAL_ENV)/bin/python tools/apply-yamcs-instance-config-fix.py "$$INST_CFG"
.PHONY: zephyr-setup
zephyr-setup: fprime-venv ## Set up Zephyr environment
@test -d lib/zephyr-workspace/modules/hal/rpi_pico || test -d ../lib/zephyr-workspace/modules/hal/rpi_pico || { \
echo "Setting up Zephyr environment..."; \
$(UVX) west update && \
$(UVX) west zephyr-export && \
$(UV) run west packages pip --install && \
$(UV) run west sdk install --toolchains arm-zephyr-eabi && \
$(UV) pip install --prerelease=allow -r lib/zephyr-workspace/bootloader/mcuboot/zephyr/requirements.txt; \
}
##@ Development
.PHONY: pre-commit-install
pre-commit-install: uv ## Install pre-commit hooks
@$(UVX) pre-commit install > /dev/null
.PHONY: fmt
fmt: pre-commit-install ## Lint and format files
@$(UVX) pre-commit run --all-files
.PHONY: data-budget
data-budget: fprime-venv ## Analyze telemetry data budget (use VERBOSE=1 for detailed output)
@$(UV_RUN) python3 tools/data_budget.py $(if $(VERBOSE),--verbose,)
.PHONY: data-diagram
data-diagram: fprime-venv ## Generate Mermaid packet wire diagrams as Markdown (use OUTPUT=file.md to save to a file)
@$(UV_RUN) python3 tools/data_budget.py --diagram $(if $(OUTPUT),--output $(OUTPUT),)
##@ Documentation
.PHONY: docs-sync
docs-sync: ## Sync SDD files from components to docs-site
@echo "Syncing SDD files to docs-site/components..."
@mkdir -p docs-site/components/img
@# Copy ADCS
@cp PROVESFlightControllerReference/Components/ADCS/docs/sdd.md docs-site/components/ADCS.md
@# Copy Communication Components
@cp PROVESFlightControllerReference/Components/AmateurRadio/docs/sdd.md docs-site/components/AmateurRadio.md
@cp PROVESFlightControllerReference/Components/SBand/docs/sdd.md docs-site/components/SBand.md
@cp PROVESFlightControllerReference/ComCcsdsUart/docs/sdd.md docs-site/components/ComCcsdsUart.md
@cp PROVESFlightControllerReference/ComCcsdsSband/docs/sdd.md docs-site/components/ComCcsdsSband.md
@cp PROVESFlightControllerReference/ComCcsdsLora/docs/sdd.md docs-site/components/ComCcsdsLora.md
@cp PROVESFlightControllerReference/Components/PayloadCom/docs/sdd.md docs-site/components/PayloadCom.md
@cp PROVESFlightControllerReference/Components/ComDelay/docs/sdd.md docs-site/components/ComDelay.md
@# Copy Core Components
@cp PROVESFlightControllerReference/Components/ModeManager/docs/sdd.md docs-site/components/ModeManager.md
@cp PROVESFlightControllerReference/Components/StartupManager/docs/sdd.md docs-site/components/StartupManager.md
@cp PROVESFlightControllerReference/Components/ResetManager/docs/sdd.md docs-site/components/ResetManager.md
@cp PROVESFlightControllerReference/Components/Watchdog/docs/sdd.md docs-site/components/Watchdog.md
@cp PROVESFlightControllerReference/Components/BootloaderTrigger/docs/sdd.md docs-site/components/BootloaderTrigger.md
@cp PROVESFlightControllerReference/Components/DetumbleManager/docs/sdd.md docs-site/components/DetumbleManager.md
@# Copy Hardware Components
@cp PROVESFlightControllerReference/Components/AntennaDeployer/docs/sdd.md docs-site/components/AntennaDeployer.md
@cp PROVESFlightControllerReference/Components/Burnwire/docs/sdd.md docs-site/components/Burnwire.md
@cp PROVESFlightControllerReference/Components/CameraHandler/docs/sdd.md docs-site/components/CameraHandler.md
@cp PROVESFlightControllerReference/Components/LoadSwitch/docs/sdd.md docs-site/components/LoadSwitch.md
@# Copy Sensor Components
@cp PROVESFlightControllerReference/Components/ImuManager/docs/sdd.md docs-site/components/ImuManager.md
@cp PROVESFlightControllerReference/Components/PowerMonitor/docs/sdd.md docs-site/components/PowerMonitor.md
@cp PROVESFlightControllerReference/Components/ThermalManager/docs/sdd.md docs-site/components/ThermalManager.md
@# Copy Driver Components
@cp PROVESFlightControllerReference/Components/Drv/Drv2605Manager/docs/sdd.md docs-site/components/Drv2605Manager.md
@cp PROVESFlightControllerReference/Components/Drv/Ina219Manager/docs/sdd.md docs-site/components/Ina219Manager.md
@cp PROVESFlightControllerReference/Components/Drv/RtcManager/docs/sdd.md docs-site/components/RtcManager.md
@cp PROVESFlightControllerReference/Components/Drv/Tmp112Manager/docs/sdd.md docs-site/components/Tmp112Manager.md
@cp PROVESFlightControllerReference/Components/Drv/Veml6031Manager/docs/sdd.md docs-site/components/Veml6031Manager.md
@# Copy Storage Components
@cp PROVESFlightControllerReference/Components/FlashWorker/docs/sdd.md docs-site/components/FlashWorker.md
@cp PROVESFlightControllerReference/Components/FsFormat/docs/sdd.md docs-site/components/FsFormat.md
@cp PROVESFlightControllerReference/Components/FsSpace/docs/sdd.md docs-site/components/FsSpace.md
@cp PROVESFlightControllerReference/Components/NullPrmDb/docs/sdd.md docs-site/components/NullPrmDb.md
@# Copy Security Components
@cp PROVESFlightControllerReference/Components/Authenticate/docs/sdd.md docs-site/components/Authenticate.md
@cp PROVESFlightControllerReference/Components/AuthenticationRouter/docs/sdd.md docs-site/components/AuthenticationRouter.md
@# Copy images
@find PROVESFlightControllerReference -path "*/docs/img/*" -type f -exec cp {} docs-site/components/img/ \; 2>/dev/null || true
@echo "✓ Synced 32 component SDDs and images"
.PHONY: docs-serve
docs-serve: uv ## Serve MkDocs documentation site locally
@echo "Starting MkDocs server at http://127.0.0.1:8000"
@$(UVX) --from mkdocs-material mkdocs serve
.PHONY: docs-build
docs-build: uv ## Build MkDocs documentation site
@$(UVX) --from mkdocs-material mkdocs build
.PHONY: generate
generate: submodules fprime-venv zephyr generate-auth-key keys/proves.pem ## Generate FPrime-Zephyr Proves Core Reference
@$(UV_RUN) fprime-util generate --force
.PHONY: generate-if-needed
BUILD_DIR ?= $(shell pwd)/build-fprime-automatic-zephyr
generate-if-needed:
@test -d $(BUILD_DIR) || $(MAKE) generate
.PHONY: build
BUILD_YAMCS_MDB ?= 1
build: submodules zephyr fprime-venv generate-if-needed ## Build FPrime-Zephyr Proves Core Reference
@$(UV_RUN) fprime-util build
./tools/bin/make-loadable-image ./build-artifacts/zephyr.signed.bin bootable.uf2
mv ./build-artifacts/zephyr.signed.hex bootable.signed.hex
@if [ "$(BUILD_YAMCS_MDB)" = "1" ]; then $(MAKE) yamcs-mdb; else echo "Skipping yamcs-mdb (BUILD_YAMCS_MDB=$(BUILD_YAMCS_MDB))"; fi
##@ Authentication Keys
AUTH_DEFAULT_KEY_HEADER ?= PROVESFlightControllerReference/Components/Authenticate/AuthDefaultKey.h
AUTH_KEY_TEMPLATE ?= scripts/generate_auth_default_key.h
.PHONY: generate-auth-key
generate-auth-key: ## Generate AuthDefaultKey.h with a random HMAC key
@if [ -f "$(AUTH_DEFAULT_KEY_HEADER)" ]; then \
echo "$(AUTH_DEFAULT_KEY_HEADER) already exists. Skipping generation."; \
else \
echo "Generating $(AUTH_DEFAULT_KEY_HEADER) with random key..."; \
$(UV_RUN) python3 scripts/generate_auth_key_header.py --output $(AUTH_DEFAULT_KEY_HEADER) --template $(AUTH_KEY_TEMPLATE); \
fi
@echo "Generated $(AUTH_DEFAULT_KEY_HEADER)"
keys/proves.pem:
@mkdir -p keys
@cp lib/zephyr-workspace/bootloader/mcuboot/root-rsa-2048.pem keys/proves.pem
SYSBUILD_PATH ?= $(shell pwd)/lib/zephyr-workspace/zephyr/samples/sysbuild/with_mcuboot
.PHONY: build-mcuboot
build-mcuboot: submodules zephyr fprime-venv
@cp $(shell pwd)/bootloader/sysbuild.conf $(SYSBUILD_PATH)/sysbuild.conf
$(UV_RUN) $(shell pwd)/tools/bin/build-with-proves $(SYSBUILD_PATH) --sysbuild
mv $(shell pwd)/build/with_mcuboot/zephyr/zephyr.uf2 $(shell pwd)/mcuboot.uf2
mv $(shell pwd)/build/mcuboot/zephyr/zephyr.elf $(shell pwd)/mcuboot.elf
##@ Debugging / OpenOCD
OPENOCD_DIR ?= $(shell pwd)/tools/openocd
OPENOCD_REPO ?= https://github.com/raspberrypi/openocd.git
OPENOCD_REF ?= acff23f
OPENOCD_BIN ?= $(OPENOCD_DIR)/src/openocd
OPENOCD_JOBS ?= 4
OPENOCD_FLASH_SPEED ?= 5000
OPENOCD_COMMON_FLAGS ?= -s $(OPENOCD_DIR)/tcl -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed $(OPENOCD_FLASH_SPEED)"
$(OPENOCD_DIR)/.built:
@if [ ! -d "$(OPENOCD_DIR)" ]; then \
git clone "$(OPENOCD_REPO)" "$(OPENOCD_DIR)"; \
fi
@cd "$(OPENOCD_DIR)" && \
git checkout "$(OPENOCD_REF)" || { echo "Failed to checkout $(OPENOCD_REF)"; exit 1; } && \
./bootstrap && \
./configure --disable-werror --enable-cmsis-dap --enable-cmsis-dap-v2 && \
$(MAKE) -j$(OPENOCD_JOBS)
@touch "$(OPENOCD_DIR)/.built"
.PHONY: debug
debug: $(OPENOCD_DIR)/.built ## Run OpenOCD against the debug probe and stream board debug output
@"$(OPENOCD_BIN)" $(OPENOCD_COMMON_FLAGS)
.PHONY: debug-install
debug-install: $(OPENOCD_DIR)/.built ## Flash a file via SWD with OpenOCD. Usage: make debug-install <filename>
@TARGET_FILE="$(firstword $(filter-out $@,$(MAKECMDGOALS)))"; \
if [ -z "$$TARGET_FILE" ]; then \
echo "Usage: make debug-install <filename>"; \
exit 1; \
fi; \
if [ ! -f "$$TARGET_FILE" ]; then \
echo "File not found: $$TARGET_FILE"; \
exit 1; \
fi; \
"$(OPENOCD_BIN)" $(OPENOCD_COMMON_FLAGS) -c "program $$TARGET_FILE verify reset exit"
test-unit: ## Run unit tests
cmake -S PROVESFlightControllerReference/test/unit-tests -B build-gtest -DBUILD_TESTING=ON
cmake --build build-gtest
ctest --test-dir build-gtest
FILTER ?= not sync_sequence_number and not format_filesystem
.PHONY: test-integration
test-integration: uv ## Run integration tests (set TEST=<name|file.py> or pass test targets)
@DEPLOY="build-artifacts/zephyr/fprime-zephyr-deployment"; \
TARGETS=""; \
if [ -n "$(TEST)" ]; then \
case "$(TEST)" in \
*.py) TARGETS="PROVESFlightControllerReference/test/int/$(TEST)" ;; \
*) TARGETS="PROVESFlightControllerReference/test/int/$(TEST).py" ;; \
esac; \
[ -e "$$TARGETS" ] || { echo "Specified test file $$TARGETS not found"; exit 1; }; \
elif [ -n "$(filter-out $@,$(MAKECMDGOALS))" ]; then \
for test in $(filter-out $@,$(MAKECMDGOALS)); do \
case "$$test" in \
*.py) TARGETS="$$TARGETS PROVESFlightControllerReference/test/int/$$test" ;; \
*) TARGETS="$$TARGETS PROVESFlightControllerReference/test/int/$${test}_test.py" ;; \
esac; \
done; \
else \
TARGETS="PROVESFlightControllerReference/test/int"; \
fi; \
echo "Running integration tests: $$TARGETS"; \
$(UV_RUN) pytest $$TARGETS --deployment $$DEPLOY -m "$(FILTER)" $(PYTEST_ARGS)
# Allow test names to be passed as targets without Make trying to execute them
%:
@:
.PHONY: test-interactive
test-interactive: fprime-venv ## Run interactive test selection (set ARGS for CLI mode, e.g., ARGS="--all --cycles 10")
@$(UV_RUN) python PROVESFlightControllerReference/test/run_interactive_tests.py $(ARGS)
.PHONY: clean
clean: ## Remove all gitignored files
git clean -dfX
##@ YAMCS
.PHONY: yamcs-dict
yamcs-dict: fprime-venv ## Generate XTCE dictionary for YAMCS (requires build-artifacts; run 'make build' first)
@mkdir -p yamcs/yamcs-data/mdb
@DICT=$$(find build-artifacts -name "*TopologyDictionary.json" | head -1); \
if [ -z "$$DICT" ]; then echo "Error: run 'make build' first"; exit 1; fi; \
echo "Generating XTCE from $$DICT"; \
$(UV_RUN) fprime-to-xtce "$$DICT" -o yamcs/yamcs-data/mdb/fprime.xtce.xml
@echo "XTCE dictionary at yamcs/yamcs-data/mdb/fprime.xtce.xml"
.PHONY: yamcs-mdb
yamcs-mdb: yamcs-dict ## Build the YAMCS Mission Database (alias for yamcs-dict, runs after build)
.PHONY: yamcs-build-check
yamcs-build-check: ## Validate YAMCS server boots via docker compose with the current MDB
@set -e; \
if [ ! -f yamcs/yamcs-data/mdb/fprime.xtce.xml ]; then \
echo "Error: yamcs/yamcs-data/mdb/fprime.xtce.xml missing — run 'make yamcs-mdb' first"; \
exit 1; \
fi; \
command -v jq >/dev/null 2>&1 || { echo "ERROR: jq is required for yamcs-build-check"; exit 1; }; \
trap 'status=$$?; \
if [ $$status -ne 0 ]; then docker compose -f yamcs/docker-compose.yml logs || true; fi; \
docker compose -f yamcs/docker-compose.yml down || true' EXIT INT TERM; \
echo "Pre-pulling YAMCS images (excluded from readiness budget)..."; \
docker compose -f yamcs/docker-compose.yml pull; \
echo "Starting YAMCS server (docker compose)..."; \
docker compose -f yamcs/docker-compose.yml up -d; \
echo "Waiting for YAMCS HTTP API on :8090 (up to 180s)..."; \
i=0; until curl -fsS http://localhost:8090/api/instances >/dev/null 2>&1; do \
i=$$((i+1)); \
if [ $$i -ge 180 ]; then \
echo "ERROR: YAMCS did not respond on :8090 within 180s"; \
exit 1; \
fi; \
sleep 1; \
done; \
echo "Checking that instance fprime-project is RUNNING..."; \
state=$$(curl -fsS http://localhost:8090/api/instances/fprime-project | jq -r '.state'); \
if [ "$$state" != "RUNNING" ]; then \
echo "ERROR: instance fprime-project did not reach RUNNING (state=$$state)"; \
curl -sS http://localhost:8090/api/instances/fprime-project || true; \
exit 1; \
fi; \
echo "YAMCS build check passed."
.PHONY: test-yamcs
test-yamcs: fprime-venv ## Run YAMCS round-trip tests (assumes 'make yamcs UART_DEVICE=...' is running)
$(UV_RUN) pytest PROVESFlightControllerReference/test/yamcs \
--deployment build-artifacts/zephyr/fprime-zephyr-deployment
.PHONY: yamcs-stop
yamcs-stop: ## Stop all YAMCS-related processes (YAMCS server, events bridge, adapter)
@echo "Stopping YAMCS processes..."
@find_repo_pids() { \
marker="$$1"; \
ps -eo pid=,args= | awk -v repo="$(CURDIR)" -v marker="$$marker" -v self="$$$$" 'index($$0, repo) && index($$0, marker) && $$1+0 != self+0 { print $$1 }'; \
}; \
stop_repo_processes() { \
marker="$$1"; \
label="$$2"; \
pids="$$(find_repo_pids "$$marker" | tr '\n' ' ' | sed 's/[[:space:]]*$$//')"; \
if [ -n "$$pids" ]; then \
kill $$pids 2>/dev/null || true; \
echo " stopped $$label"; \
fi; \
}; \
kill_udp_port() { \
port="$$1"; label="$$2"; \
pids="$$(lsof -tiUDP:$$port 2>/dev/null | tr '\n' ' ' | sed 's/[[:space:]]*$$//')"; \
if [ -n "$$pids" ]; then \
kill $$pids 2>/dev/null || true; \
echo " stopped $$label (port $$port)"; \
fi; \
}; \
kill_udp_port 50001 'serial adapter'; \
kill_udp_port 50000 'TM UDP sender'; \
stop_repo_processes 'fprime-yamcs-events' 'fprime-yamcs-events'; \
stop_repo_processes 'fprime_yamcs' 'fprime-yamcs wrapper'; \
stop_repo_processes 'mvn' 'Maven yamcs runner'; \
stop_repo_processes 'org.yamcs.YamcsServer' 'YAMCS server'; \
i=0; while lsof -iTCP:8090 -sTCP:LISTEN >/dev/null 2>&1; do \
sleep 0.5; i=$$((i+1)); if [ $$i -ge 10 ]; then \
echo " Warning: YAMCS server still running after 5s, forcing..."; \
pids="$$(find_repo_pids 'org.yamcs.YamcsServer' | tr '\n' ' ' | sed 's/[[:space:]]*$$//')"; \
[ -n "$$pids" ] && kill -9 $$pids 2>/dev/null || true; \
break; \
fi; \
done
@echo "Done."
# Spacecraft ID(s) passed to the adapter. May be a comma-separated list
# (e.g. SPACECRAFT_ID=68,67) — the adapter accepts TM from all listed SCIDs
# and uses the first for TC framing. Must include the SCID baked into the
# FSW build (ComCfg.fpp) and registered in the YAMCS instance config.
# Defaults to the production value (68 / 0x0044). CI sets this to 67 /
# 0x0043 via `make-ci-spacecraft-id` to avoid collisions with dev machines.
SPACECRAFT_ID ?= 68
.PHONY: yamcs
yamcs: fprime-venv yamcs-dict ## Run YAMCS with serial adapter (Use Case 1: UART_DEVICE=/dev/ttyXXX)
@if [ -z "$(UART_DEVICE)" ]; then echo "Error: set UART_DEVICE=/dev/ttyXXX"; exit 1; fi
@$(MAKE) yamcs-stop
@echo "Starting YAMCS (requires Java 11+)..."
@mkdir -p $(shell pwd)/yamcs/yamcs-runtime
FPRIME_GDS_CONFIG_PATH=$(shell pwd)/yamcs/fprime-gds.yml \
$(UV_RUN) fprime-yamcs \
-d $(shell pwd)/build-artifacts/zephyr/fprime-zephyr-deployment \
--no-app \
--communication-selection none \
--yamcs-config-dir $(shell pwd)/yamcs/yamcs-data \
--yamcs-data-dir $(shell pwd)/yamcs/yamcs-runtime &
@echo "Waiting for YAMCS HTTP API on :8090 (up to 180s)..."
@i=0; until curl -fsS http://localhost:8090/api/instances >/dev/null 2>&1; do \
i=$$((i+1)); \
if [ $$i -ge 180 ]; then echo "ERROR: YAMCS did not open :8090 within 180s"; exit 1; fi; \
sleep 1; \
done; \
echo "YAMCS up after $${i}s"
@echo "Starting fprime-yamcs-events bridge..."
$(UV_RUN) fprime-yamcs-events --dictionary $(shell pwd)/build-artifacts/zephyr/fprime-zephyr-deployment/dict/ReferenceDeploymentTopologyDictionary.json &
@echo "Starting serial adapter on $(UART_DEVICE) (spacecraft-id=$(SPACECRAFT_ID))..."
$(VIRTUAL_ENV)/bin/python tools/yamcs/proves_adapter.py \
--mode serial \
--uart-device $(UART_DEVICE) \
--uart-baud 115200 \
--spacecraft-id $(SPACECRAFT_ID)
.PHONY: yamcs-server
yamcs-server: yamcs-dict ## Start YAMCS server via Docker (Use Case 2: remote deployment)
docker compose -f yamcs/docker-compose.yml up
.PHONY: yamcs-adapter-tcp
yamcs-adapter-tcp: fprime-venv ## Start TCP adapter for bent-pipe (GS_HOST=, GS_PORT=, YAMCS_HOST=)
$(VIRTUAL_ENV)/bin/python tools/yamcs/proves_adapter.py \
--mode tcp \
--tcp-host $(GS_HOST) \
--tcp-port $(GS_PORT) \
--yamcs-host $(YAMCS_HOST)
##@ Operations
GDS_COMMAND ?= $(UV_RUN) fprime-gds
ARTIFACT_DIR ?= $(shell pwd)/build-artifacts
.PHONY: sequence
sequence: fprime-venv ## Compile a sequence file (usage: make sequence SEQ=startup)
@if [ -z "$(SEQ)" ]; then \
echo "Error: SEQ variable not set. Usage: make sequence SEQ=startup"; \
exit 1; \
fi
@echo "Compiling sequence: $(SEQ).seq"
@$(UV_RUN) fprime-seqgen sequences/$(SEQ).seq -d $(ARTIFACT_DIR)/zephyr/fprime-zephyr-deployment
.PHONY: gds
gds: ## Run FPrime GDS
@echo "Running FPrime GDS..."
@if [ -n "$(UART_DEVICE)" ]; then \
echo "Using UART_DEVICE=$(UART_DEVICE)"; \
$(GDS_COMMAND) --uart-device $(UART_DEVICE); \
fi
$(GDS_COMMAND)
.PHONY: delete-shadow-gds
delete-shadow-gds:
@echo "Deleting shadow GDS..."
@$(UV_RUN) pkill -9 -f fprime_gds
@$(UV_RUN) pkill -9 -f fprime-gds
.PHONY: gds-integration
gds-integration: framer-plugin
@$(GDS_COMMAND) --gui=none --uart-device=$(if $(UART_DEVICE),$(UART_DEVICE),/dev/ttyBOARD)
.PHONY: DoL_test
DoL_test:
@echo "make sure passthrough GDS is running"
@$(UV_RUN) pytest test/test_day_in_the_life.py --deployment build-artifacts/zephyr/fprime-zephyr-deployment
.PHONY: framer-plugin
framer-plugin: fprime-venv ## Build framer plugin
@echo "Framer plugin built and installed in virtual environment."
@ cd Framing && $(UV_RUN) pip install -e .
.PHONY: copy-secrets
copy-secrets:
@if [ -z "$(SECRETS_DIR)" ]; then \
echo "Error: Must pass valid secrets dir. Usage: make copy-secrets SECRETS_DIR=dir"; \
exit 1; \
fi
@mkdir -p ./keys/
@cp $(SECRETS_DIR)/proves.pem ./keys/
@cp $(SECRETS_DIR)/proves.pub.pem ./keys/
@cp $(SECRETS_DIR)/AuthDefaultKey.h ./PROVESFlightControllerReference/Components/Authenticate/
@echo "Copied secret files 🤫"
.PHONY: make-ci-spacecraft-id
make-ci-spacecraft-id: ## Generate a unique spacecraft ID for CI builds (also rewrites YAMCS instance config to match)
@echo "Generating unique spacecraft ID for CI build..."
sed -i.bak 's/SpacecraftId = 0x0044/SpacecraftId = 0x0043/' PROVESFlightControllerReference/project/config/ComCfg.fpp && \
rm PROVESFlightControllerReference/project/config/ComCfg.fpp.bak
@grep -q 'SpacecraftId = 0x0043' PROVESFlightControllerReference/project/config/ComCfg.fpp || (echo "Failed to set CI spacecraft ID in ComCfg.fpp" && exit 1)
@echo "Patching YAMCS instance config spacecraftId 68 -> 67..."
sed -i.bak 's/spacecraftId: 68/spacecraftId: 67/g' yamcs/yamcs-data/etc/yamcs.fprime-project.yaml && \
rm yamcs/yamcs-data/etc/yamcs.fprime-project.yaml.bak
@! grep -q 'spacecraftId: 68' yamcs/yamcs-data/etc/yamcs.fprime-project.yaml || (echo "Failed to patch all spacecraftId entries in yamcs.fprime-project.yaml" && exit 1)
include makelib/build-tools.mk
include makelib/ci.mk
include makelib/zephyr.mk