# Custom Makefile for AVR-C MCU projects
# 2025/01/28 Tomas Kolousek - updated with windows 11 compatible mode call (mandatory colon)
# 2024/11/23 Tomas Kolousek - silent mode DTR reset, board presets using Makefile.boards
# 2022/09/04 Tomas Kolousek - updated size target by syntax supported by v8.3.0+ toolchain
# 2021/02/01 Tomas Kolousek - automatic project name guessing from actual folder in case of empty TARGET macro
# 2020/02/02 Tomas Kolousek - cts and rts short toggle in program target using mode command (win32 specific)
# 2018/03/09 Tomas Kolousek - added target listing, gnu99 standard for asm() and bootloader support
# 2017/07/24 Tomas Kolousek - cleanup, minimal semiuniversal Win/Lin portable version

# Target CPU and programmer parameters. These has priority over board preset configs if set
MCU        := <setme>
F_CPU      := <setme>
PROGRAMMER := <setme>
UPLOADPORT := <setme>

# Alternative predefined configuration based on board name. Update Makefile.boards for your specific use
# BOARD      := micronucleus
-include Makefile.boards

STD 	     := gnu99
FORMAT     := ihex
DEBUG	     := dwarf

# Target binary name. Leave undefined to automatically use actual folder name
# TARGET 	:=

# optional separated content directories must end with forward (!) slash
SRCDIR 	:= ./
OBJDIR 	:= obj/
BINDIR 	:= bin/

# space separated additional include and library directories
LIBDIRS := libs/
INCDIRS := $(LIBDIRS) $(SRCDIRS)

# C and assembler sources which are subject of current project build. Doesn't need change for normal use
SRC 	:= $(wildcard $(SRCDIR)*.c) $(wildcard $(LIBDIRS)*.c)
ASRC 	:= $(wildcard $(SRCDIR)*.s)

#---------------- Programming Options (avrdude) ----------------
AVRDUDE_PROGRAMMER	 ?= $(PROGRAMMER)
AVRDUDE_PORT 		     ?= $(UPLOADPORT)
AVRDUDE_FLAGS 		   ?= -b115200 -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -V
AVRDUDE_WRITE_FLASH  ?= -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep

#---------------- Compiler options ----------------
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
CDEFS 	+= -DF_CPU=$(F_CPU)UL $(if $(BOARD), -DBOARD=$(BOARD))
CFLAGS  += $(if $(DEBUG), -g$(DEBUG))
CFLAGS 	+= $(CDEFS) -mmcu=$(MCU) $(STD:%=-std=%) -Os
CFLAGS 	+= -Wall -Wsign-compare -fno-exceptions 
# Listings for readable .lss files including C source fragments
CFLAGS  += -Wa,-adhlns=$(TARGET).lst
CFLAGS 	+= -I. $(INCDIRS:%=-I%)
CFLAGS  += $(GENDEPFLAGS)

ASFLAGS += -mmcu=$(MCU) -I.

OBJ = $(SRC:$(SRCDIR)%.c=$(OBJDIR)%.o) $(ASRC:$(ASRCDIR)%.c=$(OBJDIR)%.o) 
TARGET ?= $(lastword $(subst /, ,$(subst $(subst , ,),_,$(CURDIR))))
TARGET := $(BINDIR)$(TARGET)
ELFSIZE = $(SIZE) --format=berkeley $(TARGET).elf
#---------------- Library Options ----------------
PRINTF_LIB_STANDARD :=
PRINTF_LIB_MIN 		:= -Wl,-u,vfprintf -lprintf_min
PRINTF_LIB_FLOAT 	:= -Wl,-u,vfprintf -lprintf_flt -lm
PRINTF_LIB := $(PRINTF_LIB_STANDARD)

SCANF_LIB_STANDARD 	:= 
SCANF_LIB_MIN 		:= -Wl,-u,vfscanf -lscanf_min
SCANF_LIB_FLOAT 	:= -Wl,-u,vfscanf -lscanf_flt -lm
SCANF_LIB := $(SCANF_LIB_STANDARD)

#---------------- Linker Options ----------------
LDFLAGS = 
LDFLAGS += -Wl,-Map=$(TARGET).map,--cref
#LDFLAGS += -wl,--section-start=.text=$(MT_BOOTLOADER_ADDRESS)
LDFLAGS += -Wl,--section-start=.text_bootlib=0x3FFA
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(LIBDIRS:%=-L%)
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB)
#LDFLAGS += -T linker_script.x

#---------------- Programs and commands ---------------
CC 		:= avr-gcc
OBJCOPY := avr-objcopy
OBJDUMP := avr-objdump
SIZE 	:= avr-size
AR 		:= avr-ar rcs
NM 		:= avr-nm
LD      := avr-ld
AVRDUDE ?= avrdude

#---------------- Linux / Windows portability ---------------
space := $(subst , ,)
ifeq ($(OS),Windows_NT)
	RM 		:= del /Q /S
	RMDIR 	:= rmdir /Q /S
	SHELL 	:= cmd.exe
	NULL    := NUL
	GREP	:= find.exe
	fixpath = $(subst /,\,$1)
else
	RM 		:= rm -f
	RMDIR 	:= rm -rf
	NULL    := /dev/null
	GREP	:= grep
	fixpath	= $1
endif

#----------- Main targets --------
.NOTPARALLEL:
.PHONY: clean

all: build size
build: $(TARGET).hex $(TARGET).eep $(TARGET).lss

program: build
	@-mode $(AVRDUDE_PORT): rts=on dtr=on >$(NULL) || :
	@$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)

size: $(TARGET).elf
	@echo Size info for $(<F):
#$(ELFSIZE)|$(GREP) "Program"
#$(ELFSIZE)|$(GREP) "Data"
	@$(ELFSIZE)

clean:
	@-$(RM) *.hex *.eep *.map *.lst *.lss *.elf *.o 2> $(NULL) || exit 0
	@-$(if $(wildcard $(OBJDIR)), $(RMDIR) $(call fixpath,$(OBJDIR)) 2> $(NULL))
	@-$(if $(wildcard $(BINDIR)), $(RMDIR) $(call fixpath,$(BINDIR)) 2> $(NULL))
	@-$(if $(wildcard .dep), $(RMDIR) .dep 2>$(NULL))

help:
	@echo Available targets:
	@echo   build   - build $(TARGET).hex and $(TARGET).eep from sources
	@echo   size    - display information about size of compiled binary
	@echo   program - upload to MCU using $(AVRDUDE_PROGRAMMER) programmer $(if $(AVRDUDE_PORT),on port $(AVRDUDE_PORT))
	@echo Current config:
	@echo   Processor $(MCU) at $(F_CPU)Hz, sources in $(realpath $(SRCDIR))

#--- Supporting targets for generating main binaries from sources and intermediate files ---
.PRECIOUS: $(OBJ) $(TARGET).elf $(TARGET).map $(TARGET).lst
%.hex: %.elf
	@$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock $< $@

%.eep: %.elf
	@-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
	--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0

%.elf: $(OBJ) 
	@echo Linking $@ ...
	@$(CC) $(CFLAGS) $^ --output $@ $(LDFLAGS)

$(BINDIR)%.lss: $(BINDIR)%.elf
	@$(OBJDUMP) -h -S $< > $@

$(OBJDIR)%.o : $(SRCDIR)%.c
	@echo Compiling $< ..
	@$(CC) -c $(CFLAGS) $< -o $@ 

%.S : $(SRCDIR)%.c   # this allows explicit call of make in form make main.S to see assembled source in OBJDIR
	@$(CC) -S $(CFLAGS) $< -o $(OBJDIR)$@ 

#----------- Common initialization -----------
$(if $(OBJDIR),$(shell mkdir $(call fixpath,$(OBJDIR)) 2>$(NULL) ))
$(if $(BINDIR),$(shell mkdir $(call fixpath,$(BINDIR)) 2>$(NULL) ))
-include $(shell mkdir .dep 2>$(NULL)) $(wildcard .dep/*)
# use propper windows encodding in terminal (instead of default CP852)
$(if (ifeq $(OS),Windows_NT),$(shell chcp 1250))
