# -----------------------------------------------------------------------------------------
#
#   jamrules.avr.inc
#
#   Bob Cook Development, Robotics Library
#   http://www.bobcookdev.com/rl/
#    
#   Implements the base jamrules for AVR (8-bit) projects.
#
#   Copyright (C) 2009 Bob Cook
#
#       This program 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 2 of the License, or (at your
#       option) any later version.
#     
#       This program 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, write to the Free Software Foundation, Inc., 
#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# -----------------------------------------------------------------------------------------


if $(TRACE) { echo "trace /jamrules.avr.inc" ; }


# -----------------------------------------------------------------------------------------

rule avr_executable_with_eeprom # name device : src | lib | pkg ... ;
{
    if ! $(1[1]) { exit "*** avr_executable: must have a exe name" ; }

    # build the executuable first
    
    avr_executable $(1) : $(2) ;
    
    # override some built-in variables.
    
    local sv_SUFEXE        = $(SUFEXE) ;
    local sv_LOCATE_TARGET = $(LOCATE_TARGET) ;
    
    SUFEXE        = .elf ;
    LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) bin ] ;
    
    # now derive the eeprom hex image from the executable
    
    local exename eepromhex ;
    
    exename   = [ FAppendSuffix $(1)        : $(SUFEXE)   ] ;
    eepromhex = [ FAppendSuffix $(1)_eeprom : .hex ] ;

    Depends exe          : $(eepromhex) ;
    Depends $(eepromhex) : $(exename) ;

    MakeLocate $(eepromhex) : $(LOCATE_TARGET) ;
    
    Clean clean : $(eepromhex) ;
    
    avr_eepromhex_from_executable $(eepromhex) : $(exename) ;
    
    # restore the modified variables.
    
    SUFEXE        = $(sv_SUFEXE) ;
    LOCATE_TARGET = $(sv_LOCATE_TARGET) ;
}

    
# -----------------------------------------------------------------------------------------

rule avr_executable # name device : src | lib | pkg ... ;
{
    if ! $(1[1]) { exit "*** avr_executable: must have a exe name" ; }
    if ! $(1[2]) { exit "*** avr_executable: must have a device" ; }
    if   $(1[3]) { exit "*** avr_executable: must not have extra names" ; }
    if ! $(2[1]) { exit "*** avr_executable: must have at least one source file" ; }
    
    # override some built-in variables.
    
    local sv_SUFOBJ        = $(SUFOBJ) ;
    local sv_SUFLIB        = $(SUFLIB) ;
    local sv_SUFEXE        = $(SUFEXE) ;
    local sv_SUFMAP        = $(SUFMAP) ;
    local sv_SOURCE_GRIST  = $(SOURCE_GRIST) ;
    local sv_LOCATE_TARGET = $(LOCATE_TARGET) ;
    
    SUFOBJ = .o ;
    SUFLIB = .a ;
    SUFEXE = .elf ;
    SUFMAP = .map ;

    # look for headers in the current dir as well as the top dir
        
    AVR_INCDIR  = [ FSubDirPath TOP ] ;
    AVR_INCDIR += $(SUBDIR) ;
    
    # validate the device string; we only support specific ones.
    
    switch $(1[2]:L)
    {
        case atmega8   : AVR_DEVICE = atmega8 ;
        case atmega88  : AVR_DEVICE = atmega88 ;
        case atmega16  : AVR_DEVICE = atmega16 ;
        case atmega168 : AVR_DEVICE = atmega168 ;
        case atmega128 : AVR_DEVICE = atmega128 ;
        case *         : exit "*** avr_executable: unsupported device $(1[2])" ;
    }
    
    # sort the input files
    
    local f, sources, libs, packages ;
    
    sources  = ;
    libs     = ;
    packages = ;

    for f in $(2)
    {
        switch $(f:S)
        {
            case .c   : sources  += $(f) ;
            case .cpp : sources  += $(f) ;
            case .S   : sources  += $(f) ;
            case .lib : libs     += $(f) ;
            case .pkg : packages += $(f) ;
            case *    : exit "*** avr_executable: unrecognized suffix $(f:S)" ;
        }
    }
    
    # set up the required libraries from lib

    local l ;
        
    for l in $(libs) 
    {
        switch $(l:L)
        {
            case printf_min.lib   : AVR_WHICH_PRINTF = MINIMAL ;
            case printf_float.lib : AVR_WHICH_PRINTF = FLOATING_PT ;
            case scanf_min.lib    : AVR_WHICH_SCANF  = MINIMAL ;
            case scanf_float.lib  : AVR_WHICH_SCANF  = FLOATING_PT ;
            case *                : exit "*** avr_executable: unrecognized lib $(l:L)" ;
        }
    }
    
    # build the object files from local sources
    
    local grist_obj = ;
    
    LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) gen ] ;
    SEARCH_SOURCE = $(SUBDIR) ;
    SOURCE_GRIST  = $(sv_SOURCE_GRIST) ;
    avr_objects $(sources) ;
    
    grist_obj += [ FGristFiles $(sources:BS=$(SUFOBJ)) ] ;
    
    # build the object files from pkg sources
    
    for p in $(packages)
    {
        PKG_SOURCES = ;
        IncludePackage $(p) ;
        
        LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) gen $(p) ] ;
        SEARCH_SOURCE = [ PackageDirFromNameVar $(p) ] ;
        SOURCE_GRIST  = $(sv_SOURCE_GRIST)!$(p) ;
        avr_objects $(PKG_SOURCES) ;
        
        grist_obj += [ FGristFiles $(PKG_SOURCES:BS=$(SUFOBJ)) ] ;
    }
    
    # build the executable target
    
    LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) bin ] ;
    avr_executable_from_objects $(1[1]) : $(grist_obj) ;

    # restore the modified variables.
    
    SUFOBJ        = $(sv_SUFOBJ) ;
    SUFLIB        = $(sv_SUFLIB) ;
    SUFEXE        = $(sv_SUFEXE) ;
    SUFMAP        = $(sv_SUFMAP) ;
    SOURCE_GRIST  = $(sv_SOURCE_GRIST) ;
    LOCATE_TARGET = $(sv_LOCATE_TARGET) ;
}


# -----------------------------------------------------------------------------------------

rule avr_executable_from_objects # name : gristed_obj ;
{
    local exename linkmap listing texthex eepromhex ;
    
    exename   = [ FAppendSuffix $(1) : $(SUFEXE) ] ;
    linkmap   = [ FAppendSuffix $(1) : $(SUFMAP) ] ;
    listing   = [ FAppendSuffix $(1) : .listing  ] ;
    texthex   = [ FAppendSuffix $(1) : .hex      ] ;

    if $(exename) != $(1)
    {
        Depends $(1) : $(exename) ;
        NotFile $(1) ;
    }

    Depends exe        : $(exename) $(listing) $(texthex) ;
    Depends $(exename) : $(2) ;
    Depends $(linkmap) : $(exename) ;
    Depends $(listing) : $(exename) ;
    Depends $(texthex) : $(exename) ;

    MakeLocate $(exename) : $(LOCATE_TARGET) ;
    MakeLocate $(linkmap) : $(LOCATE_TARGET) ;
    MakeLocate $(listing) : $(LOCATE_TARGET) ;
    MakeLocate $(texthex) : $(LOCATE_TARGET) ;
    
    Clean clean : $(exename) $(linkmap) $(listing) $(texthex) ;

    AVR_LINKMAP on $(exename) = [ FDirName $(LOCATE_TARGET) $(linkmap) ] ;
    avr_link $(exename) : $(2) ;
    
    SEARCH     on $(exename) = $(LOCATE_TARGET) ;
    AVR_DEVICE on $(exename) = $(AVR_DEVICE) ;
    AVR_OPTIM  on $(exename) = -Os ;

    if $(AVR_WHICH_PRINTF) = MINIMAL
    {
        AVR_EXTRA_LIBS on $(exename) += -Wl,-u,vfprintf -lprintf_min ;
    }
    else if $(AVR_WHICH_PRINTF) = FLOATING_PT
    {
        AVR_EXTRA_LIBS on $(exename) += -Wl,-u,vfprintf -lprintf_flt ;
        AVR_EXTRA_LIBS on $(exename) += -lm ;
    }

    if $(AVR_WHICH_SCANF) = MINIMAL
    {
        AVR_EXTRA_LIBS on $(exename) += -Wl,-u,vfscanf -lscanf_min ;
    }
    else if $(AVR_WHICH_SCANF) = FLOATING_PT
    {
        AVR_EXTRA_LIBS on $(exename) += -Wl,-u,vfscanf -lscanf_flt ;
        AVR_EXTRA_LIBS on $(exename) += -lm ;
    }
    
    avr_list_from_executable    $(listing) : $(exename) ;
    avr_texthex_from_executable $(texthex) : $(exename) ;
}


# -----------------------------------------------------------------------------------------

rule avr_objects # src ;
{
    local s ;
    
    for s in $(1)
    {
        local o = [ FGristFiles $(s:BS=$(SUFOBJ)) ] ;
        avr_object $(o) : $(s) ;
        Depends obj : $(o) ;
    }
}


# -----------------------------------------------------------------------------------------

rule avr_object # obj : src ;
{
    Clean clean : $(1) ;

    MakeLocate $(1) : $(LOCATE_TARGET) ;
    SEARCH on $(2) = $(SEARCH_SOURCE) ;

    HDRS on $(1) = $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ;
    AVR_INCDIR on $(1) = $(SEARCH_SOURCE) $(AVR_INCDIR) ;

    local WINAVR_INCDIR ;
    WINAVR_INCDIR  = c:\\WinAVR-20070525\\avr\\include ;
    WINAVR_INCDIR += c:\\WinAVR-20070525\\lib\\gcc\\avr\\3.4.6\\include ;

    HDRRULE on $(2) = HdrRule ;
    HDRSCAN on $(2) = $(HDRPATTERN) ;
    HDRSEARCH on $(2) = $(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(AVR_INCDIR) $(WINAVR_INCDIR) ;

    HDRGRIST on $(2) = $(HDRGRIST) ;

    DEFINES on $(1) += $(DEFINES) ;
    
    AVR_DEVICE on $(1) = $(AVR_DEVICE) ;

    switch $(2:S)
    {
        case .c   : avr_cc  $(1) : $(2) ;
        case .cpp : avr_c++ $(1) : $(2) ;
        case .S   : avr_as  $(1) : $(2) ;
        case *    : exit "*** avr_object: unrecognized suffix $(2:S)" ;
    }
    
    Depends $(1) : $(2) ;
}


# -----------------------------------------------------------------------------------------

