# #############################################################################
#                         STM32 FIRMWARE MAKEFILE
# #############################################################################
# Add this path to your PATH
# D:\mingw64\bin;D:\mingw64\opt\bin
# D:\armgcc\bin;D:\openocd\bin
# C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin
# C:\Program Files\7-Zip
# #############################################################################

# Make flags
MAKEFLAGS += -j8

# PROJECT
# -------
TITLE = MINITREE
EXEC = MiniTree
COPYRIGHT = Copyright (c) 1998 2026 Romain LABBE
BASE_ADDR = 0x08000000
DEBUG = 0
HAL_VERSION=1.4.1
CUBEMX_DIR = STM32Cube_FW_C0_V$(HAL_VERSION)
CUBEMX_DPFX = STM32C0xx
CUBEMX_FPFX = stm32c0xx
# STM32C011J4M6
MCU = STM32C011xx
LD_SCRIPT = STM32C011XX_FLASH.ld
STARTUP_FILE = startup_stm32c011xx.s

# DIRECTORIES
# -----------
# Base directory
BASE_DIR = .
# Build directory
BUILD_DIR = build
# Backup directory
BKP_DIR = ..\bkp

# MCU/FPU
# -------
# Mcpu [cortex-m0plus|cortex-m3|cortex-m4|cortex-m7]
MFLAGS = -mcpu=cortex-m0plus
# Thumb instruction
MFLAGS += -mthumb

# C-FLAGS
# -------
CFLAGS = $(MFLAGS)
# Optimization [-O0|-O1|-O2|-O3|-Ofast|-Os|-Oz|-Og]
CFLAGS += -Os
# Warning
CFLAGS += -Wall
CFLAGS += -Wno-unused-variable
# Linker stripper
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
# Dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"

# LD-FLAGS
# --------
LDFLAGS = $(MFLAGS)
# Linker script
LDFLAGS += -T ld\$(LD_SCRIPT)
# Map file
LDFLAGS += -Wl,-Map=$(BUILD_DIR)\$(EXEC).map,--cref
# Linker stripper
LDFLAGS += -Wl,--gc-sections
# Memory usage
LDFLAGS += -Wl,--print-memory-usage
# GCC 12 issue #1029
LDFLAGS += -Wl,--no-warn-rwx-segments

# DEFINES
# -------
# core
DEFINES = $(MCU)
DEFINES += USE_HAL_DRIVER
DEFINES += CPU=$(MCU)
DEFINES += HAL_VERSION=$(HAL_VERSION)
#DEFINES += USE_FULL_ASSERT


# #############################################################################
#                                 SOURCE
# #############################################################################

# Source version information
VER_FILE = inc/version.h
VER_MAJ_TAG = VERSION_MAJOR
VER_MIN_TAG = VERSION_MINOR


# Includes directories (Relative to BASE_DIR)
INC_DIRS = \
	inc \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Inc \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Inc/Legacy \
	libs/$(CUBEMX_DIR)/Drivers/CMSIS/Device/ST/$(CUBEMX_DPFX)/Include \
	libs/$(CUBEMX_DIR)/Drivers/CMSIS/Include \

# Sources files
SRC_FILES = \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_cortex.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_rcc.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_rcc_ex.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_flash.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_flash_ex.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_gpio.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_pwr.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_pwr_ex.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_tim.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_tim_ex.c \
	libs/$(CUBEMX_DIR)/Drivers/$(CUBEMX_DPFX)_HAL_Driver/Src/$(CUBEMX_FPFX)_hal_exti.c \
	src/$(STARTUP_FILE) \
	src/system_$(CUBEMX_FPFX).c \
	src/platform.c \
	src/system.c \
	src/main.c \
	src/led.c \
	src/sw.c \
	src/seq.c \

# #############################################################################
#                                 TOOLCHAIN
# #############################################################################

# Toolchain binaries
CC = arm-none-eabi-gcc
AS = arm-none-eabi-gcc
OC = arm-none-eabi-objcopy
AR = arm-none-eabi-ar
SZ = arm-none-eabi-size
DMP = arm-none-eabi-objdump
STLINK = ST-LINK_CLI.exe
STPROG = STM32_Programmer_CLI.exe
OPENOCD = openocd.exe

# Common
NCSCRIPT = ncscript.txt
NC = nc

# Toolchain utilitites
FIXPATH = $(subst /,\,$(1))
MKDIR_CMD = if not exist "$(call FIXPATH,$(1))" mkdir "$(call FIXPATH,$(1))"
RM = del /S /Q
RMDIR = rmdir /S /Q
CP = copy /Y
CAT = type
ZIP = 7z a -tzip -r
GET_DEFINE_VAL = $(shell for /f "tokens=3" %%i in ('findstr /C:"#define $(2)" $(call FIXPATH,$(1))') do echo %%i)
FSZ = for %%I in ($(call FIXPATH,$(1))) do @echo %%~nxI : %%~zI bytes

# #############################################################################
#                               INITIALISATION
# #############################################################################

# New line
NL = & echo.

# Space definition
VSPACE =
SPACE = $(VSPACE) $(VSPACE)

# Get version
VER_MAJ_VAL = $(call GET_DEFINE_VAL,$(VER_FILE),$(VER_MAJ_TAG))
VER_MIN_VAL = $(call GET_DEFINE_VAL,$(VER_FILE),$(VER_MIN_TAG))
VERSION = $(VER_MAJ_VAL).$(VER_MIN_VAL)

# Output filename
OUTPUT = $(EXEC)-$(VERSION)

# Create INCLUDES
INCLUDES = $(addprefix $(BASE_DIR)/,$(INC_DIRS))

# Create source objects
OBJS =

# C files
C_FILES=$(filter %.c,$(SRC_FILES))
OBJS = $(addprefix $(BUILD_DIR)/, $(C_FILES:.c=.o))

# ASM files
AS_FILES=$(filter %.s,$(SRC_FILES))
OBJS += $(addprefix $(BUILD_DIR)/, $(AS_FILES:.s=.o))

# Update DEFINES
ifeq ($(DEBUG),1)
DEFINES += DEBUG
endif

# Update CFLAGS
CFLAGS += $(foreach item,$(DEFINES),-D$(item))
CFLAGS += $(foreach item,$(INCLUDES),-I$(item))
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif


# #############################################################################
#                                  TARGETS
# #############################################################################

# Phony
.PHONY: all clean mrproper stlink-flash stprog-flash stprog-blank stprog-ob openocd-flash openocd-server backup version info infosrc infoobj infopath infoinc infodef

# ----------------------------------------------------------------------------
#                               TARGET : ALL
# ----------------------------------------------------------------------------

# default action: build all
all: banner $(BUILD_DIR)/$(OUTPUT).elf $(BUILD_DIR)/$(OUTPUT).hex $(BUILD_DIR)/$(OUTPUT).bin
	@echo * Make '$@' ($(MCU)) done !

$(BUILD_DIR)/%.o: %.c Makefile
	@echo * Building C file '$@' ...
	@$(call MKDIR_CMD,$(dir $@))
	$(CC) -c $(CFLAGS) $< -o $@
	@echo.

$(BUILD_DIR)/%.o: %.s Makefile
	@echo * Building ASM file '$@' ...
	@$(call MKDIR_CMD,$(dir $@))
	$(AS) -c $(CFLAGS) $< -o $@
	@echo.

$(BUILD_DIR)/$(OUTPUT).elf: $(OBJS) Makefile
	@echo * Linking '$@'...
	$(CC) $(OBJS) $(LDFLAGS) -o $@
	@$(CP) $(subst  /,\,$@) $(subst /,\,$(BUILD_DIR)/$(EXEC).elf)
	@$(call FSZ,$@)
	@$(SZ) $@
	@echo.

$(BUILD_DIR)/$(OUTPUT).hex: $(BUILD_DIR)/$(OUTPUT).elf
	@echo * Extracting hexa '$@' ...
	$(OC) -O ihex $< $@
	@$(call FSZ,$@)
	@echo.

$(BUILD_DIR)/$(OUTPUT).bin: $(BUILD_DIR)/$(OUTPUT).elf
	@echo * Extracting binary '$@' ...
	$(OC) -O binary -S $< $@
	@$(CP) $(subst  /,\,$@) $(subst /,\,$(BUILD_DIR)/$(EXEC).bin)
	@$(call FSZ,$@)
	@echo.


# ----------------------------------------------------------------------------
#                               TARGET : CLEAN
# ----------------------------------------------------------------------------

clean: banner $(BUILD_DIR)
	@echo * Cleaning  '$(BUILD_DIR)' directory...
	-$(RM) $(call FIXPATH,$(BUILD_DIR)/*.o)
	-$(RM) $(call FIXPATH,$(BUILD_DIR)/*.d)
	@echo Clean done !

# ----------------------------------------------------------------------------
#                              TARGET : MRPROPER
# ----------------------------------------------------------------------------

mrproper: banner $(BUILD_DIR)
	@echo * Propering  '$(BUILD_DIR)' directory...
	-$(RMDIR) $(call FIXPATH,$(BUILD_DIR))
	@echo MrProper done !

# ----------------------------------------------------------------------------
#                              TARGET : STLINK-FLASH
# ----------------------------------------------------------------------------

stlink-flash: banner
	@echo * Flashing  '$(OUTPUT).bin'...
	$(STLINK) -c SWD UR -P $(BUILD_DIR)/$(OUTPUT).bin $(BASE_ADDR) -V "while_programming" -Rst -Run -NoPrompt
	@echo Flashed !

# ----------------------------------------------------------------------------
#                              TARGET : STPROG-FLASH
# ----------------------------------------------------------------------------

# NRST is a GPIO on this board: no hardware reset, hot plug on a running MCU
# (failsafe mode: button held 3 s at power-up, star on) and software reset.
stprog-flash: banner
	@echo * Flashing  '$(OUTPUT).bin'...
	$(STPROG) -c port=swd reset=SWrst mode=HOTPLUG -w $(BUILD_DIR)/$(OUTPUT).bin $(BASE_ADDR) -v -rst
	@echo Flashed !

# ----------------------------------------------------------------------------
#                              TARGET : STPROG-BLANK
# ----------------------------------------------------------------------------
# Blank board (NRST still in reset mode): connect under reset, flash, then set
# NRST_MODE=2. Also recovers a board flashed without the option byte.

stprog-blank: banner
	@echo * Flashing blank board '$(OUTPUT).bin' + option bytes...
	$(STPROG) -c port=swd reset=HWrst mode=UR -w $(BUILD_DIR)/$(OUTPUT).bin $(BASE_ADDR) -v -ob NRST_MODE=2
	@echo Blank board done !

# ----------------------------------------------------------------------------
#                              TARGET : STCLONE-FLASH
# ----------------------------------------------------------------------------
# ST-Link V2 clone (metal dongle): its RST pin does not drive NRST in SWD, so
# no connect under reset. Hot plug + software reset at low SWD clock, flash,
# then NRST_MODE=2. Blank board: power it and go. Flashed board: failsafe mode
# (star on).

stclone-flash: banner
	@echo * Flashing  '$(OUTPUT).bin' + option bytes (ST-Link clone, hot plug)...
	$(STPROG) -c port=swd reset=SWrst mode=HOTPLUG freq=480 -w $(BUILD_DIR)/$(OUTPUT).bin $(BASE_ADDR) -v -ob NRST_MODE=2 -rst
	@echo Flashed !

# ----------------------------------------------------------------------------
#                              TARGET : STCLONE-BLANK
# ----------------------------------------------------------------------------
# ST-Link V2 clone, recovery without failsafe: one attempt to catch the SWD
# grace window (BUILD_SWD_GRACE_MS after the MCU starts, or while it is held
# in reset by the button after Shutdown), halt the core at once, then flash
# and set NRST_MODE=2. Retried in a loop by stclone-blank.bat.

stclone-blank:
	$(STPROG) -c port=swd reset=SWrst mode=HOTPLUG freq=4000 -halt -w $(BUILD_DIR)/$(OUTPUT).bin $(BASE_ADDR) -v -ob NRST_MODE=2 -rst

# ----------------------------------------------------------------------------
#                              TARGET : STPROG-OB
# ----------------------------------------------------------------------------
# NRST pin as GPIO (button on PA0/NRST), the firmware can also do it itself
# when BUILD_OB_NRST_GPIO is enabled in inc/build.h.

stprog-ob: banner
	@echo * Setting option bytes NRST_MODE=2 (GPIO)...
	$(STPROG) -c port=swd reset=SWrst mode=HOTPLUG -ob NRST_MODE=2
	@echo Option bytes done !

# ----------------------------------------------------------------------------
#                              TARGET : OPENOCD-FLASH
# ----------------------------------------------------------------------------

openocd-flash: banner
	@echo * Flashing  '$(OUTPUT).bin'...
	@echo reset halt > $(NCSCRIPT)
	@echo flash write_image erase $(subst \,/,$(shell echo %CD%))/$(BUILD_DIR)/$(OUTPUT).bin $(BASE_ADDR) >> $(NCSCRIPT)
	@echo reset init >> $(NCSCRIPT)
	@echo reset >> $(NCSCRIPT)
	@echo resume >> $(NCSCRIPT)
	@echo exit >> $(NCSCRIPT)
	$(CAT) $(NCSCRIPT) | $(NC) 127.0.0.1 4444
	@$(RM) $(NCSCRIPT)


# ----------------------------------------------------------------------------
#                              TARGET : OPENOCD-SERVER
# ----------------------------------------------------------------------------

openocd-server: banner
	@echo * Starting OpenOCD...
	$(OPENOCD) -f interface\stlink.cfg -f target\stm32c0x.cfg -c "reset_config srst_only"


# ----------------------------------------------------------------------------
#                              TARGET : BACKUP
# ----------------------------------------------------------------------------

backup: banner
	@$(call MKDIR_CMD,$(BKP_DIR))
	$(ZIP) "$(call FIXPATH,$(BKP_DIR)/$(EXEC)-$(VERSION).zip)" . -xr!build -xr!libs
	@echo * Backup '$(BKP_DIR)\$(EXEC)-$(VERSION).zip' ready !


# ----------------------------------------------------------------------------
#                              TARGET : VERSION
# ----------------------------------------------------------------------------

version:
	@echo $(VERSION)

# ----------------------------------------------------------------------------
#                              TARGET : INFO
# ----------------------------------------------------------------------------

info: infosrc infoobj infoinc infodef

infosrc: banner
	@echo SOURCES ($(words $(SRC_FILES)) items)
	@echo.
	@echo $(subst $(SPACE),$(NL),$(SRC_FILES))
	@echo.

infoobj: banner
	@echo OBJECTS ($(words $(OBJS)) items)
	@echo.
	@echo $(subst $(SPACE),$(NL),$(OBJS))
	@echo.

infoinc: banner
	@echo INCLUDES ($(words $(INCLUDES)) items)
	@echo.
	@echo $(subst $(SPACE),$(NL),$(INCLUDES))
	@echo.

infodef: banner
	@echo DEFINES ($(words $(DEFINES)) items)
	@echo.
	@echo $(subst $(SPACE),$(NL),$(DEFINES))
	@echo.

# ----------------------------------------------------------------------------
#                              UTILITIES
# ----------------------------------------------------------------------------

banner:
	@echo $(TITLE) V$(VERSION) - $(COPYRIGHT)
	@echo.


# Include dependencies (objects live in sub directories of BUILD_DIR)
-include $(OBJS:.o=.d)
