PROJECT_NAME 	= $(PWD:B) ;
PROJECT_DIR 	= . ;
PROJECT_LIBS    = EEPROM SPI RF24 ; 

OUT_DIR = ojam ;
F_CPU 		= 16000000 ;
MCU             = atmega328p ;
PORTS           = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ;

UPLOAD_RATE 	= 57600 ;
AVRDUDE_PROTOCOL = stk500v1 ;
COM 		= 33 ;

# Host-specific overrides for locations 
if $(OS) = MACOSX 
{
ARDUINO_VERSION	= 22 ;
OLD_DIR 	= /opt/arduino-0021 ;
AVR_TOOLS_PATH 	= $(OLD_DIR)/hardware/tools/avr/bin ;
AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ;
ARDUINO_DIR 	= /opt/Arduino ;
ARDUINO_AVR 	= /usr/lib/avr/include ;
}

# Where is everything?
ARDUINO_VERSION	?= 22 ;
AVR_TOOLS_PATH 	?= /usr/bin ;
ARDUINO_DIR 	?= /opt/arduino-00$(ARDUINO_VERSION) ;
ARDUINO_AVR 	?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ;
AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ;
ARDUINO_CORE 	= $(ARDUINO_DIR)/hardware/arduino/cores/arduino ;
ARDUINO_LIB 	= $(ARDUINO_DIR)/libraries ;
SKETCH_LIB      = $(HOME)/Source/Arduino/libraries ;
AVR_CC  	= $(AVR_TOOLS_PATH)/avr-gcc ;
AVR_CXX  	= $(AVR_TOOLS_PATH)/avr-g++ ;
AVR_LD  	= $(AVR_TOOLS_PATH)/avr-gcc ;
AVR_OBJCOPY 	= $(AVR_TOOLS_PATH)/avr-objcopy ;
AVRDUDE 	= $(AVR_TOOLS_PATH)/avrdude ;

DEFINES  	= F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ;
CTUNING  	= -ffunction-sections -fdata-sections ;
CXXTUNING  	= -fno-exceptions -fno-strict-aliasing ; 
CFLAGS  	= -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ;
CXXFLAGS  	= $(CFLAGS) $(CXXTUNING) ;
LDFLAGS  	= -Os -lm -Wl,--gc-sections -mmcu=atmega328p ;

# Search everywhere for headers
HDRS  	 	= $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ;

# Grab everything from the core directory
CORE_MODULES  	= [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ;

# Grab everything from libraries.  To avoid this "grab everything" behaviour, you
# can specify specific modules to pick up in PROJECT_MODULES
LIB_MODULES  	= [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ;

# In addition to explicitly-specified program modules, pick up anything from the current
# dir.
PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ;

# Shortcut for the out files
OUT             = $(OUT_DIR)/$(PROJECT_NAME) ;

# AvrDude setup
AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ;

rule GitVersion
{
  Always $(<) ;
  Depends all : $(<) ;
}

actions GitVersion
{
  echo "const char program_version[] = \"\\" > $(<)
  git log -1 --pretty=format:%h >> $(<)
  echo "\";" >> $(<)
}

GitVersion version.h ;

rule AvrCc
{
  Depends $(<) : $(>) ;
  Depends $(<) : $(<:D) ;
  Clean clean : $(<) ;

  CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
  CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
}

actions AvrCc
{
  $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) 
}

rule AvrC++
{
  Depends $(<) : $(>) ;
  Depends $(<) : $(<:D) ;
  Clean clean : $(<) ;

  CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
  CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
}

actions AvrC++
{
  $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) 
}

rule Pde
{
  Depends $(<) : $(>) ;
  Depends $(<) : $(<:D) ;
  Clean clean : $(<) ;

}

actions Pde
{
  echo "#include <WProgram.h>" > $(<) 
  echo "#line 1 \"$(>)\"" >> $(<)
  cat $(>) >> $(<) 
}

rule AvrPde
{
  local _CPP = $(OUT_DIR)/$(_I:B).cpp ;
  Pde $(_CPP) : $(>) ;
  AvrC++ $(<) : $(_CPP) ;
}

rule AvrObject
{
  switch $(>:S)
  {
    case .c :   AvrCc $(<) : $(>) ;
    case .cpp : AvrC++ $(<) : $(>) ;
    case .pde : AvrPde $(<) : $(>) ;
  }
}

rule AvrObjects
{
  for _I in $(<) 
  {
    AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ;
  }
}

rule AvrMainFromObjects
{
  Depends $(<) : $(>) ;
  Depends $(<) : $(<:D) ;
  MkDir $(<:D) ;
  Depends all : $(<) ;
  Clean clean : $(<) ;
}

actions AvrMainFromObjects
{
  $(AVR_LD) $(LDFLAGS) -o $(<) $(>) 
}

rule AvrMain
{
  AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ;
  AvrObjects $(>) ;
}

rule AvrHex
{
  Depends $(<) : $(>) ;
  Depends $(<) : $(<:D) ;
  Depends hex : $(<) ;
  Clean clean : $(<) ;
}

actions AvrHex
{
  $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<)
}

rule AvrUpload
{
  Depends $(1) : $(2) ;
  Depends $(2) : $(3) ;
  NotFile $(1) ;
  Always $(1) ;
  Always $(2) ;
  AvrUploadAction $(2) : $(3) ;
}

actions AvrUploadAction
{
  $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i
}

AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ;
AvrHex $(OUT).hex : $(OUT).elf ;

AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ;
AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ;
AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ;

