#   Zerocat Chipflasher --- Flash free firmware, kick the Management Engine.
#
#   Copyright (C) 2015, 2016  kai <kmx@posteo.net>
#   Copyright (C) 2015, 2016  tomás zerolo <tomás@tuxteam.de>
#   Copyright (C) 2016, 2017, 2018, 2020, 2021, 2022, 2023, 2024  Kai Mertens <kmx@posteo.net>
#
#   This file is part of Zerocat Chipflasher.
#
#   Zerocat Chipflasher is free software: you can redistribute it and/or
#   modify it under the terms of the GNU General Public License as
#   published by the Free Software Foundation, either version 3 of the
#   License, or (at your option) any later version.
#
#   Zerocat Chipflasher is distributed in the hope that it will be
#   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
#   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#   General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with Zerocat Chipflasher.
#   If not, see <http://www.gnu.org/licenses/>.


#   Documentation
#   =============
#
#
#   Diagnostic Pragmas
#   ------------------
#
#
#   NOTE Propeller code allows some non ANSI standard format specifiers,
#   i.e. "%b" for binary representation of an integer.
#   That will produce warnings according to -Wformat and -Wformat-extra-args.
#
#   You can temporarily disable these warnings in your source code:
#
#       [...]
#       #pragma GCC diagnostic push
#       #pragma GCC diagnostic ignored "-Wall"
#       #pragma GCC diagnostic ignored "-Wformat-extra-args"
#       //your code goes here, i.e.:
#       //printi("binary number: %08b", x);
#       #pragma GCC diagnostic pop
#       [...]
#
#   Please compare to:
#   https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas)
#
#
#   Usage
#   -----
#
#
#       $ make help
#
#
#   FIXME
#   -----
#
#
#   A patern rule would be nice. But where to stick the -lm -lfdserial and so on?
#   NOTE lib order matters (-lfoo -lbar). And $^ must go before libs.


#   Workaround for GNU Make < 4.3
#   =============================
#
#   Finalize commands within a $(shell) function with semicolon, e.g.:
#
#           $(shell echo;)


# Shell
SHELL                         := /bin/sh


# White Space
EMPTY                         :=
SPACE                         := $(EMPTY) $(EMPTY)
COMMA                         := ,
M5                            := uuuuu
TAB1                          := $(SPACE)$(SPACE)$(SPACE)$(SPACE)
TOKEN_DISABLE                 := $(EMPTY)"\/\/\# \t "$(EMPTY)
TOKEN_ENABLE                  := $(EMPTY)"\# \t "$(EMPTY)


# Root Paths
ROOT                          := ../../
ROOT_DOC                      := ../../doc/
ROOT_FW1_SRC                  := ../../firmware1/src/


# Utilities
CD                            := $(shell command -v cd;)
CD_FLAGS                      :=
$(if $(strip $(CD)),,         $(error Cannot find cd utility))

CP                            := $(shell command -v cp;)
CP_FLAGS                      :=
$(if $(strip $(CP)),,         $(error Cannot find cp utility))

RM                            := $(shell command -v rm;)
RM_FLAGS                      := -f
$(if $(strip $(RM)),,         $(error Cannot find rm utility))

MV                            := $(shell command -v mv;)
MV_FLAGS                      :=
$(if $(strip $(MV)),,         $(error Cannot find mv utility))

CAT                           := $(shell command -v cat;)
CAT_FLAGS                     :=
$(if $(strip $(CAT)),,        $(error Cannot find cat utility))

CUT                           := $(shell command -v cut;)
CUT_FLAGS                     := -d' '
$(if $(strip $(CUT)),,        $(error Cannot find cut utility))

GIT                           := $(shell command -v git;)
GIT_FLAGS                     :=
$(if $(strip $(GIT)),,        $(error Cannot find git utility))

SED                           := $(shell command -v sed;)
SED_FLAGS                     := -E
$(if $(strip $(SED)),,        $(error Cannot find sed utility))

SET                           := $(shell command -v set;)
SET_FLAGS                     := -f
$(if $(strip $(SET)),,        $(error Cannot find set utility))

ECHO                          := $(shell command -v echo;)
ECHO_FLAGS                    :=
$(if $(strip $(ECHO)),,       $(error Cannot find echo utility))

READ                          := $(shell command -v read;)
READ_FLAGS                    :=
$(if $(strip $(READ)),,       $(error Cannot find read utility))

#   Note ‘mkdir -p’ might not be supported.
MKDIR                         := $(shell command -v mkdir;)
MKDIR_FLAGS                   :=
$(if $(strip $(MKDIR)),,      $(error Cannot find mkdir utility))

MKTEMP                        := $(shell command -v mktemp;)
MKTEMP_FLAGS                  :=
$(if $(strip $(MKTEMP)),,     $(error Cannot find mktemp utility))

PROPELFGCC                    := $(shell command -v propeller-elf-gcc;)
PROPELFGCC_SYSROOT            = $(strip\
	--sysroot=$(PARALLAX_REPO)/\
)
PROPELFGCC_INCLUDES           := $(strip\
	-I .\
	-I =Learn/Simple\ Libraries/TextDevices/libsimpletext\
	-I =Learn/Simple\ Libraries/Utility/libsimpletools\
	-I =Learn/Simple\ Libraries/Protocol/libsimplei2c\
)
PROPELFGCC_LIBDIRS_lmm        := $(strip\
	-L .\
	-L =Learn/Simple\ Libraries/TextDevices/libsimpletext/lmm\
	-L =Learn/Simple\ Libraries/Utility/libsimpletools/lmm\
	-L =Learn/Simple\ Libraries/Protocol/libsimplei2c/lmm\
)
PROPELFGCC_LIBDIRS_cmm        := $(strip\
	-L .\
	-L =Learn/Simple\ Libraries/TextDevices/libsimpletext/cmm\
	-L =Learn/Simple\ Libraries/Utility/libsimpletools/cmm\
	-L =Learn/Simple\ Libraries/Protocol/libsimplei2c/cmm\
)
PROPELFGCC_LIBS               := $(strip\
	-lsimpletext\
	-lsimpletools\
	-lsimplei2c\
)
PROPELFGCC_FLAGS              = $(strip\
	$(PROPELFGCC_SYSROOT)\
	$(PROPELFGCC_INCLUDES)\
	$(PROPELFGCC_LIBDIRS_$*)\
	-Os -Wall -Wmissing-prototypes -m32bit-doubles -fno-exceptions -std=c99 -m$*\
)
$(if $(strip $(PROPELFGCC)),, $(error Cannot find propeller-elf-gcc utility))


# Project Settings
include $(ROOT_DOC)project-numbers.mk


# Settings
MAKEFILE_TITLE                := Build ‘kick’, the first firmware
PROJECT_TITLE                 := Zerocat Chipflasher
PROJECT_BRIEF                 := Flash free firmware, kick the Management Engine.
PARALLAX_REMOTE               := https://github.com/
PARALLAX_REPO                 := parallaxinc/Simple-Libraries
PARALLAX_REPO_VERSION         := c4f9a3e273002ec5e6f8b1d1ab95c14cb1823e82


# Files
LIBPROP                       := $(wildcard libprop/*)
LIBCOMMON                     := $(wildcard libcommon/*)
LIBSPI                        := $(wildcard libSPI/*)
LIBKICK                       := $(wildcard libkick/*)
H_PINS                        := $(ROOT_FW1_SRC)libkick/proppins.h


.PHONY :\
	all\
	\
	hello\
	help\
	print-search-dirs\
	\
	setup-lib-parallaxinc\
	config-BOARD_V2\
	config-BOARD_V1\
	\
	kick\
	\
	remove-libcommon/common.h\
	remove-lib-parallaxinc\
	clean-config\
	clean


# Tinned Cans: HEADER, HEADLINE, DONE
include $(ROOT_DOC)tinned-headers.mk


# Targets
#   all: same as kick
all : hello kick
	@$(HEADLINE)\
	&& $(DONE);

#   Say hello.
#     provided with all, clean and help
hello :
	@$(HEADER)\
	&& $(DONE);

#   display help information
help : $(ROOT_FW1_SRC)help.txt hello
	@$(HEADLINE)\
	&& $(CAT) $(CAT_FLAGS)\
		$<\
	&& $(DONE);

#   print search directories
print-search-dirs :
	@$(HEADLINE)\
	&& $(PROPELFGCC)\
		-print-search-dirs\
	&& $(DONE);

#   set up parallaxinc repo clone
setup-lib-parallaxinc : $(PARALLAX_REPO)
	@$(HEADLINE)\
	&& $(DONE);

config-BOARD_V2 : $(H_PINS)
	@$(HEADLINE)\
	&& $(SED) $(SED_FLAGS)\
		--in-place\
		-e "s/^("$(TOKEN_ENABLE)")(.*define.*_CFG_BOARD_V1)/"$(TOKEN_DISABLE)"\2/;"\
		-e "s/^("$(TOKEN_DISABLE)")(.*define.*_CFG_BOARD_V2)/"$(TOKEN_ENABLE)"\2/;"\
			$<\
	&& $(DONE);

config-BOARD_V1 : $(H_PINS)
	@$(HEADLINE)\
	&& $(SED) $(SED_FLAGS)\
		--in-place\
		-e "s/^("$(TOKEN_ENABLE)")(.*define.*_CFG_BOARD_V2)/"$(TOKEN_DISABLE)"\2/;"\
		-e "s/^("$(TOKEN_DISABLE)")(.*define.*_CFG_BOARD_V1)/"$(TOKEN_ENABLE)"\2/;"\
			$<\
	&& $(DONE);

#   target ‘kick’
#     Memory model
#     lmm: stores the program image and variable data in Main RAM, fastest execution
#     cmm: the program image is compiled into a size-optimized form
#     xmmc: stores program images in external flash memory, an SD card, or EEPROM.
kick : kick.lmm.elf kick.cmm.elf
	@$(HEADLINE)\
	&& $(DONE);

$(PARALLAX_REPO) :
	@$(HEADLINE)\
	&& $(READ) $(READ_FLAGS)\
		-p 'Ready to start download from ‘$(PARALLAX_REMOTE)’? [yes|no]: '\
			reply\
	&& if [ "$$reply" = 'yes' ]\
		; then\
			$(MKDIR) $(MKDIR_FLAGS)\
				$(dir $@)\
			&& $(CD) $(CD_FLAGS)\
				$(dir $@)\
			&& $(GIT) $(GIT_FLAGS)\
				clone $(PARALLAX_REMOTE)$@.git\
			&& if [ $$? -eq 0 ]\
				; then\
					$(CD) $(CD_FLAGS)\
						$(@F)/\
					&& $(GIT) $(GIT_FLAGS)\
						checkout $(PARALLAX_REPO_VERSION)\
					&& $(CD) $(CD_FLAGS)\
						-\
				; else\
					exit 1\
				; fi\
		; else\
			$(ECHO) $(ECHO_FLAGS) "Download cancelled by user."\
			&& exit 1\
		; fi\
	&& $(DONE);

#   build kick.elf file
kick.%.elf : kick.c libcommon/common.h $(LIBPROP) $(LIBCOMMON) $(LIBSPI) $(LIBKICK) setup-lib-parallaxinc
	@$(HEADLINE)\
	&& $(PROPELFGCC) $(PROPELFGCC_FLAGS)\
		$<\
		$(PROPELFGCC_LIBS)\
			-o $@\
	&& $(DONE);

# modified header file with version tag
libcommon/common.h : libcommon/common.tmpl.h
	@$(HEADLINE)\
	&& $(CD) $(CD_FLAGS)\
		$(<D)\
	&& $(SED) $(SED_FLAGS)\
		-e 's/<VERSION>/$(PROJECT_NUMBER)/g;'\
			$(<F)\
				> $(@F)\
	&& $(CD) $(CD_FLAGS) -\
	&& $(DONE);

#   remove libcommon/common.h
remove-libcommon/common.h :
	@$(HEADLINE)\
	&& $(CD) $(CD_FLAGS)\
		$(subst remove-,,$(@D))\
	&& $(RM) $(RM_FLAGS)\
		$(@F)\
	&& $(CD) $(CD_FLAGS) -\
	&& $(DONE);

#   clean (remove) parallaxinc folder
remove-lib-parallaxinc :
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS) -r\
		$(dir $(PARALLAX_REPO))\
	&& $(DONE);

#   clean kick configuration
clean-config : config-BOARD_V2
	@$(HEADLINE)\
	&& $(DONE);

#   clean kick
clean : hello clean-config remove-libcommon/common.h
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS)\
		kick.lmm.elf\
		kick.cmm.elf\
	&& $(DONE);
