# Portal panel firmware — build and USB deploy # # make # build only # make deploy # build + flash over USB (picotool) # # Options (also via repo-root .env — see .env.example): # make deploy PANEL_ID=0 # make deploy NETWORK=dhcp # make deploy IP=10.1.1.10 GATEWAY=10.1.1.1 # make deploy WS2812_PIN=26 WS2812_PIN1=27 # # Environment: # PICO_SDK_PATH default: ~/pico-sdk (fallback ~/pico/pico-sdk) MAKEFILE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -include $(MAKEFILE_DIR)../.env -include $(MAKEFILE_DIR).env ifeq ($(origin PICO_SDK_PATH), undefined) ifneq ($(wildcard $(HOME)/pico-sdk/pico_sdk_init.cmake),) PICO_SDK_PATH := $(HOME)/pico-sdk else PICO_SDK_PATH := $(HOME)/pico/pico-sdk endif endif BUILD_DIR := build UF2 := $(BUILD_DIR)/panel.uf2 CMAKE_STAMP := $(BUILD_DIR)/.cmake_stamp JOBS ?= $(shell nproc 2>/dev/null || echo 4) SERIAL_PORT ?= $(shell ls /dev/ttyACM* 2>/dev/null | head -1) ifeq ($(SERIAL_PORT),) SERIAL_PORT := /dev/ttyACM0 endif SERIAL_BAUD ?= 115200 NETWORK ?= static comma := , dot_to_csv = $(subst .,$(comma),$(1)) CMAKE_ARGS := ifdef PANEL_ID CMAKE_ARGS += -DPANEL_ID_BUILD=$(PANEL_ID) endif ifdef WS2812_PIN CMAKE_ARGS += -DWS2812_PIN_BUILD=$(WS2812_PIN) endif ifdef WS2812_PIN1 CMAKE_ARGS += -DWS2812_PIN1_BUILD=$(WS2812_PIN1) endif ifdef IP CMAKE_ARGS += -DSTATIC_IP_BUILD=$(call dot_to_csv,$(IP)) endif ifdef NETMASK CMAKE_ARGS += -DSTATIC_SN_BUILD=$(call dot_to_csv,$(NETMASK)) endif ifdef GATEWAY CMAKE_ARGS += -DSTATIC_GW_BUILD=$(call dot_to_csv,$(GATEWAY)) endif ifdef DNS CMAKE_ARGS += -DSTATIC_DNS_BUILD=$(call dot_to_csv,$(DNS)) endif ifeq ($(NETWORK),dhcp) CMAKE_ARGS += -DPORTAL_USE_DHCP=ON else ifeq ($(NO_DHCP),0) CMAKE_ARGS += -DPORTAL_USE_DHCP=ON else CMAKE_ARGS += -DPORTAL_USE_DHCP=OFF endif CMAKE_STAMP_BODY := $(strip $(CMAKE_ARGS)) .PHONY: all build configure reconfigure deploy flash upload reset monitor clean help all: build help: @echo "Targets:" @echo " make build Build panel.uf2" @echo " make deploy Build and flash over USB" @echo " make reset USB reboot Pico" @echo " make monitor USB serial console" @echo " make clean Remove build directory" build: configure @echo "==> Building panel firmware" # Host GCC 15 needs cstdint for pico-sdk pioasm CXXFLAGS='-include cstdint' PICO_SDK_PATH="$(PICO_SDK_PATH)" cmake --build $(BUILD_DIR) -j$(JOBS) @test -f "$(UF2)" || (echo "Error: build did not produce panel.uf2" && exit 1) @echo "==> Build OK: $(UF2)" configure: @test -d "$(PICO_SDK_PATH)" || (echo "Error: pico-sdk not found at $(PICO_SDK_PATH)" && exit 1) @command -v cmake >/dev/null || (echo "Error: cmake is required" && exit 1) @mkdir -p $(BUILD_DIR) @STAMP='$(CMAKE_STAMP_BODY)'; \ if [ ! -f "$(BUILD_DIR)/CMakeCache.txt" ] || [ ! -f "$(CMAKE_STAMP)" ] || [ "$$(cat $(CMAKE_STAMP))" != "$$STAMP" ]; then \ echo "==> Configuring cmake in $(BUILD_DIR) $(CMAKE_ARGS)"; \ CXXFLAGS='-include cstdint' PICO_SDK_PATH="$(PICO_SDK_PATH)" cmake -S . -B $(BUILD_DIR) $(CMAKE_ARGS); \ echo "$$STAMP" > "$(CMAKE_STAMP)"; \ fi reconfigure: @mkdir -p $(BUILD_DIR) CXXFLAGS='-include cstdint' PICO_SDK_PATH="$(PICO_SDK_PATH)" cmake -S . -B $(BUILD_DIR) $(CMAKE_ARGS) @echo '$(CMAKE_STAMP_BODY)' > $(CMAKE_STAMP) deploy: build @command -v picotool >/dev/null || { echo "Error: picotool not found"; exit 1; } @echo "==> Uploading $(UF2) over USB" @picotool load -x -f "$(UF2)" flash: deploy upload: deploy reset: @command -v picotool >/dev/null || { echo "Error: picotool not found"; exit 1; } @picotool reboot -f @i=0; last=; \ while [ $$i -lt 50 ]; do \ cur=$$(ls /dev/ttyACM* 2>/dev/null | head -1); \ if [ -n "$$cur" ] && [ "$$cur" = "$$last" ]; then \ sleep 0.5; \ if [ -e "$$cur" ]; then echo "==> Ready ($$cur)"; exit 0; fi; \ fi; \ last=$$cur; \ i=$$((i + 1)); sleep 0.2; \ done; \ echo "==> Warning: serial not ready yet"; exit 0 monitor: @command -v picocom >/dev/null || { echo "Error: picocom not found"; exit 1; } @SERIAL=; i=0; \ while [ $$i -lt 40 ]; do \ for d in $(SERIAL_PORT) $$(ls /dev/ttyACM* 2>/dev/null); do \ [ -n "$$d" ] && [ -e "$$d" ] || continue; \ SERIAL=$$d; break; \ done; \ [ -n "$$SERIAL" ] && [ -e "$$SERIAL" ] && break; \ i=$$((i + 1)); sleep 0.25; \ done; \ if [ -z "$$SERIAL" ] || [ ! -e "$$SERIAL" ]; then echo "Error: no serial port"; exit 1; fi; \ echo "==> monitor $$SERIAL"; \ exec picocom --baud $(SERIAL_BAUD) --flow n --echo --noreset "$$SERIAL" clean: rm -rf $(BUILD_DIR)