#   Zerocat PS/2 Keyboard --- Get rid of keyloggers,
#                             avoid USB firmware attacks!
#
#   Copyright (C) 2015 Tomás Zerolo <tomas@tuxteam.de> @n
#   Copyright (C) 2015, 2016, 2017, 2018, 2023 Kai Mertens <kmx@posteo.net>
#
#   The Zerocat PS/2 Keyboard 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.
#
#   The Zerocat PS/2 Keyboard 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 this program.  If not, see <http://www.gnu.org/licenses/>.
#
#   This file is part of the Zerocat PS/2 Keyboard.


#   # Usage
#
#   To build the firmware, type:
#
#           make



# Shell
SHELL                         := /bin/sh


# White Space
EMPTY                         :=
SPACE                         := $(EMPTY) $(EMPTY)
COMMA                         := ,
M5                            := mmmmm


# Suffixes
.SUFFIXES :
.SUFFIXES : .c .h .elf


# Root Paths
ROOT                          := ../../
ROOT_DOC                      := ../../doc/


# Standard Utilities
WHEREIS                       := $(shell command -v whereis;)
WHEREIS_FLAGS                 := -b
$(if $(strip $(WHEREIS)),,    $(error Cannot find whereis utility))

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

RM                            := $(shell command -v rm;)
RM_FLAGS                      := -f
$(if $(strip $(RM)),,         $(error Cannot find rm 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                     := -r
$(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 $(WHEREIS) $(WHEREIS_FLAGS) echo | $(CUT) $(CUT_FLAGS) -f2;)
ECHO_FLAGS                    := -e
$(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))


# Extra Utilities
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))


# Settings
PROJECT_TITLE                 := Zerocat PS/2 Keyboard
PROJECT_BRIEF                 := Get rid of spyware.
MAKEFILE_TITLE                := Build the firmware.
PROJECT_NUMBER                := $(strip\
	$(shell\
		$(SET) $(SET_FLAGS)\
		&& $(GIT) $(GIT_FLAGS)\
			describe\
				--always\
				--match v*\
		| $(SED) $(SED_FLAGS)\
			-e 's/(.*)(-g)([0-9a-f]*)/\1-\3/;'\
				-;\
	)\
)
PARALLAX_REMOTE               := https://github.com/
PARALLAX_REPO                 := parallaxinc/Simple-Libraries
PARALLAX_REPO_VERSION         := c4f9a3e273002ec5e6f8b1d1ab95c14cb1823e82


# Files


# Tinned Cans
define HEADER
$(strip\
	$(ECHO) $(ECHO_FLAGS)\
		"\n$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)"\
		"\n$(M5) $(PROJECT_TITLE)"\
		"\n$(M5) – $(PROJECT_BRIEF)"\
		"\n$(M5) $(MAKEFILE_TITLE)"\
		"\n$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)"\
)
endef
define HEADLINE
$(strip\
	$(ECHO) $(ECHO_FLAGS)\
		"$(M5) Process target “$@” $(M5)$(M5)"\
)
endef
define DONE
$(strip\
	$(ECHO) $(ECHO_FLAGS)\
		"... successfully processed: “$@”"\
		"\n"\
)
endef


# Built-in Special Targets
#~ .SECONDARY :                  # Uncomment for debugging
.PHONY :\
	all\
	\
	hello\
	help\
	\
	print-search-dirs\
	setup-lib-parallaxinc\
	main\
	\
	remove-lib-parallaxinc\
	clean


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


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

#   display help information
help : hello
	@$(HEADLINE)\
	&& $(ECHO) $(ECHO_FLAGS)\
		"\nList of Targets"\
		"\n==============="\
		"\n"\
		"\nDefault"\
		"\n-------"\
		"\n"\
		"\nall\r\t\t\t\tsame as main"\
		"\n"\
		"\nHelp"\
		"\n----"\
		"\n"\
		"\nhello\r\t\t\t\tgreeter, provided with all, clean and help"\
		"\nhelp\r\t\t\t\tdisplay this help information"\
		"\n"\
		"\nActions"\
		"\n-------"\
		"\n"\
		"\nprint-search-dirs\r\t\t\t\tprint Propeller-Elf-GCC search directories"\
		"\nsetup-lib-parallaxinc\r\t\t\t\tdownload Parallax Library Repo and Checkout"\
		"\nmain\r\t\t\t\tbuild the firmware"\
		"\n"\
		"\nClean"\
		"\n-----"\
		"\n"\
		"\nremove-lib-parallaxinc\r\t\t\t\tremove Parallax Library Repo"\
		"\nclean\r\t\t\t\tclean all"\
		"\n"\
	&& $(DONE);

#   target “main”
#     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.
main : main.lmm.elf main.cmm.elf
	@$(HEADLINE)\
	&& $(DONE);

# setup parallax repo
$(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 main.elf file
main.%.elf : main.c main.h setup-lib-parallaxinc
	@$(HEADLINE)\
	&& $(PROPELFGCC) $(PROPELFGCC_FLAGS)\
		$<\
		$(PROPELFGCC_LIBS)\
			-o $@\
	&& $(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);

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

#   clean main
clean : hello
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS)\
		main.lmm.elf\
		main.cmm.elf\
	&& $(DONE);
