#   Copyright (c) 2007...2009 Axel Wachtler
#   All rights reserved.
#
#   Redistribution and use in source and binary forms, with or without
#   modification, are permitted provided that the following conditions
#   are met:
#
#   * Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   * Neither the name of the authors nor the names of its contributors
#     may be used to endorse or promote products derived from this software
#     without specific prior written permission.
#
#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
#   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
#   POSSIBILITY OF SUCH DAMAGE.

# $Id: SConstruct,v 1.43 2009/06/30 19:42:02 awachtler Exp $

#=== modules ==================================================================
import os, time, sys
sys.path.append("./Tools")
import ds2reg

#=== setup build environment ==================================================
if os.name == 'posix':
    dbgfmt = "stabs"
else:
    dbgfmt = "dwarf-2"

com = Environment (
    tools = ['mingw'],
    CC="avr-gcc",
    DBGFMT=dbgfmt,
    CCFLAGS="-g$DBGFMT -mmcu=$CPU -Wall -Wundef -fshort-enums",
#    ENV = {'PATH' : os.environ['PATH']},
    ENV = os.environ,
    ofname = time.strftime("foo-%Y%m%d"),
    )

RUN_SLOW = ARGUMENTS.get('slow',0)
if not RUN_SLOW:
	com.Decider('MD5-timestamp')
	print "Running with optimization --max-drift=1,--implicit-deps-unchanged, MD5-timestamp and selective rules"

class Board:
    ##
    # @param cpu        name of the cpu as ggc-mmcu string
    # @param blstart    bootloader start address
    # @ccopts           further cc
    def __init__(self,cpu,blstart,**ccopts):
        self.cpu = cpu
        self.blstart = blstart
        self.ccopts = {}
        for k in ccopts.keys():
            self.ccopts[k] = ccopts[k]
            setattr(self, k, self.ccopts[k])

    def get_ccopts(self):
        return " ".join(map(lambda k,v: "-D%s=%s" % (k,v),
                    self.ccopts.keys(),
                    self.ccopts.values()))

# Template processor for transceiver header files
def create_radio_headerfiles(target, source, env):
    ds2reg.generate_header(str(source[0]),str(target[0]))

# Template processor for AVRStudio files
def configure_apsfile(target, source, env):
    try:
        xslt_lxml(target, source, env)
    except:
        xslt_cmdline(target, source, env)
    
def xslt_lxml(target, source, env):
    from lxml import etree    
    f = open(env.subst("$APSTEMPLATE"),"r")
    xmldoc = etree.parse(f)
    f.close()
    f = open(env.subst("$XSLTFILE"),"r")
    xsldoc = etree.parse(f)
    f.close()
    xparms = {}
    for k in env['STRINGPARAM'].keys():
        t = "\'%s\'" % str(env['STRINGPARAM'][k])
        xparms[k] = t
    x = apply(xmldoc.xslt, (xsldoc,), xparms )
    f = open(str(target[0]),"w")
    f.write(str(x))
    f.close()
    
def xslt_cmdline(target, source, env):
    strparm = []
    for k in env['STRINGPARAM'].keys():
        strparm.append("-stringparam %s \"%s\"" % (k,env['STRINGPARAM'][k]))

    env['PARMS'] = " ".join(strparm)
    cmd = env.subst("xsltproc $PARMS $XSLTFILE $APSTEMPLATE > %s" % target[0])
    os.system(cmd)



# Template Processor for Doxygen Config File
def configure_textfile(target, source, env):
    fin = open(str(source[0]),"r")
    fout = open(str(target[0]),"w")
    parms = env['STRINGPARAM']
    for l in fin.xreadlines():
        l = l.rstrip()
        lo = l % parms
        fout.write(lo+"\n")
    fout.close()
    fin.close()

# Template Processor for Doxygen Config File
def configure_doxyfile(target, source, env):
    fin = open(str(source[0]),"r")
    fout = open(str(target[0]),"w")
    for l in fin.xreadlines():
        l = l.rstrip()
        if "WARN_FORMAT" not in l:
            l = env.subst(l)
        fout.write(l+"\n")
    fout.close()
    fin.close()

com["TARFLAGS"] = '-c -z'
com["TARSUFFIX"] = '.tgz'
com['dir_top'] = com.Dir(".")
com['dir_src_doc'] = com.Dir("./Doc")
com['dir_src_img'] = com.Dir("./Doc/Images")
com['dir_install'] = com.Dir("install")
com['dir_install_doc'] = com.Dir("$dir_install/doc")
com['dir_install_xmpl'] = com.Dir("$dir_install/xmpl")
com['PROGSUFFIX']='.elf'
com["dir_build"] = com.Dir("build")
com.SConsignFile(".scons-signatures")


com['boardopts'] = {
                     # cpu ,  bootoffset in byte, compileflags
    # radio extender with STK501 or single RCB
    "rdk230":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "rdk230b":  Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "rdk231":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "rdk212":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),

    # STK541 with RCB
    "psk230":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "psk230b":  Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "psk231":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "psk212":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),

    # Sensor Terminal Board with RCB
    "stb230":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "stb230b":  Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "stb231":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "stb212":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),

    # RCB breakout board
    "rbb230":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "rbb230b":  Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "rbb231":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "rbb212":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),

    # ATZGB Link Modul
    "zgbl230":  Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "zgbl231":  Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "zgbl212":  Board("atmega1281",0x1e000, F_CPU="8000000UL"),

    # ATZGB EVM-H
    "zgbh230":  Board("atmega1281",0x1e000, F_CPU="7372800UL"),
    "zgbh231":  Board("atmega1281",0x1e000, F_CPU="7372800UL"),
    "zgbh212":  Board("atmega1281",0x1e000, F_CPU="7372800UL"),

    # Raven USB Stick
    "rzusb":    Board("at90usb1287",0x1e000, F_CPU="8000000UL"),
#   "ravrf":    Board("atmega1284p",0x1e000, F_CPU="8000000UL"),


    # meshbean 2.4GHz
    "wdba1281": Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    # meshbean 900Mhz
    "mnb900":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),

    # Incircuit
    "ict230":   Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "ics230_11": Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    "icm230_11": Board("atmega1281",0x1e000, F_CPU="8000000UL"),
    # Various DIY boards
    "tiny230":  Board("attiny84",0, F_CPU="8000000UL"),

    "stkm16":   Board("atmega16",0x3800, F_CPU="8000000UL"),
    "stkm8" :   Board("atmega8",0, F_CPU="8000000UL"),
    "stkt26":   Board("attiny26",0, F_CPU="8000000UL"),
    "lgee231":	Board("atmega88",0, F_CPU="8000000UL"),
    }

com["boards"] = com['boardopts'].keys()
com['BUILDERS']['RadioHeaderWriter'] = Builder(action = create_radio_headerfiles)
com['BUILDERS']['DoxyfileTransformer'] =  Builder(action = configure_doxyfile)
com['BUILDERS']['ApsTransformer'] =  Builder(action = configure_apsfile)
com['BUILDERS']['TextTransformer'] =  Builder(action = configure_textfile)

avr = com.Clone()

#=== targets ==========================================================

#=== Ugly Optimization ================================================
# Prefiltering of the build rules on for "explicitely wanted" targets, 
#
# This reduces the build time, since the dependency tree 
# gets much smaller.
#
# For testing, the  command "scons -n  --debug=time stb230"
# detects that nothing is todo.
#
# Unfiltered (old) version:
#   Total build time: 22.301233 seconds
#   Total SConscript file execution time: 18.462105 seconds
# Prefiltered version:
#   Total build time: 5.319315 seconds
#   Total SConscript file execution time: 1.648799 seconds
#========================================================================
current_boards = []
for board in com["boards"]:
    for ct in COMMAND_LINE_TARGETS:
        if board in ct:
            current_boards.append(board)
            
            
if len(current_boards) == 0 or RUN_SLOW:
    current_boards = com["boards"]

for board in current_boards:
    avr.SConscript('Src/Lib/SConscript',
                    build_dir = '${dir_build}/%s/lib' % board,
                    exports="avr board",
                    duplicate = 0
                    )
    
    avr.SConscript('Src/App/SConscript',
                    build_dir = '${dir_build}/%s/app' % board,
                    exports="avr board",
                    duplicate = 0
                    )

    avr.SConscript('Src/Xmpl/SConscript',
                    build_dir = '${dir_build}/%s/xmpl' % board,
                    exports="avr board",
                    duplicate = 0
                    )

#
# Install Example sources
#
xmplsources = []
for xmpl in com.Glob('Src/Xmpl/xmpl*.[hc]'):
    x = avr.Install('$dir_install_xmpl',xmpl)
    xmplsources.append(x)

#
# Documentation targets
#
doc = com.Clone()

doc['dox_version'] = ARGUMENTS.get("version","[%s]" % time.asctime())

doc.SConscript("Doc/SConscript", build_dir='build/doc',
               exports="doc", duplicate=0)

doc.SConscript("Doc/Usr/SConscript", build_dir='build/udoc',
               exports="doc", duplicate=0)

doc.SConscript("Doc/App/SConscript", build_dir='build/adoc',
               exports="doc", duplicate=0)

doc.SConscript("Doc/Dev/SConscript", build_dir='build/ddoc',
               exports="doc", duplicate=0)

doc.SConscript("Doc/Contrib/SConscript", build_dir='build/cdoc',
               exports="doc", duplicate=0)

#=== install ==========================================================
i1 = avr.Install('${dir_install}/inc',
        ["Src/Lib/Inc/board.h",
         "Src/Lib/Inc/transceiver.h",
         "Src/Lib/Inc/const.h",
         "Src/Lib/Inc/radio.h",
         "Src/Lib/Inc/ioutil.h",
         "Src/Lib/Ioutil/uart.h",
         "Src/Lib/Inc/timer.h",
         "Src/Lib/Inc/hif.h",
         "Src/Lib/Inc/acc_mma7455.h"])

boardincludes = Glob("Src/Lib/Inc/boards/*.h")
i2 = avr.Install('${dir_install}/inc/boards/', boardincludes)
i3a = com.RadioHeaderWriter('${dir_install}/inc/at86rf230a.h','Templates/at86rf230a.txt')
i3b = com.RadioHeaderWriter('${dir_install}/inc/at86rf230b.h','Templates/at86rf230b.txt')
i3c = com.RadioHeaderWriter('${dir_install}/inc/at86rf231.h','Templates/at86rf231.txt')
i3d = com.RadioHeaderWriter('${dir_install}/inc/at86rf212.h','Templates/at86rf212.txt')
i4  = com.RadioHeaderWriter('${dir_install}/inc/mma7455.h','Templates/mma7455.txt')
#=== clean ============================================================
com.Clean("distclean",["$dir_build", "$dir_install"])
com.Clean("clean",["$dir_build"])

#=== aliases ==========================================================
libtargets = map(lambda b: "l%s" % b, com["boards"])
apptargets = map(lambda b: "a%s" % b, com["boards"])
xmpltargets = map(lambda b: "x%s" % b, com["boards"])

for i in com["boards"]:
    avr.Alias(i, Split("l%s a%s x%s"%(i,i,i)))

avr.Alias('libs', libtargets)
avr.Alias('apps', apptargets)
avr.Alias('xmpli', xmplsources)
avr.Alias('xmpls', xmpltargets + xmplsources)
avr.Alias('all', libtargets +  apptargets + xmpltargets + xmplsources)

com.Alias('ddoc',['install/doc/dev'])
com.Alias('adoc',['install/doc/app'])
com.Alias('udoc',['install/doc/usr'])
com.Alias('cdoc',['install/doc/contrib'])
com.Alias('doc',['install/doc'])

com.Alias('install', [i1, i2, i3a, i3b, i3c, i4, com["dir_install"] ])

Default('all')

Help("""

Build System for uracoli project

Usage:

    scons              - build all targets
    scons <target>     - build the target
    scons -c           - clean all files
    scons -c distclean - remove all created files and directories
    scons -c clean     - remove build directory (leaving install)
    scons -c <target>  - clean all files for the target

    scons slow=1 to disable all optimizations

A <target> can be:
    all          : libraries and applications for all plattforms
    doc          : documentation
     adoc        :  application guide
     ddoc        :  developpers guide
     udoc        :  users guide
    libs         : libraries for all plattforms
    apps         : applications for all plattforms
    xmpls        : small example applications for all plattforms
    <BoardType>  : libraries and applications for specified board type
    l<BoardType> : libraries for specified board type
    a<BoardType> : applications for specified board type
    x<BoardType> : small example applications for specified board type

<BoardType> can be:
    rzusb                  : Atmel Raven USB Stick with AT86RF230 Rev. B
    rdk{230,230b,231,212}  : Atmel reference platform and compatible
                             Dresden Elektronik Radio Controller boards
                             with AT86RF230 Rev. A/B, AT86RF231, AT86RF212
    stb{230,230b,231,212}  : Dresden Elektronik Sensor Terminal Board
                             with AT86RF230 Rev. A/B, AT86RF231, AT86RF212
    psk{230,230b,231,212}  : Atmel STK541 and RCB
                             with AT86RF230 Rev. B, AT86RF231, AT86RF212
    rbb{230,230b,231,212}  : Dresden Elektronik RCB Breakout Board
                             with AT86RF230 Rev. A/B, AT86RF231, AT86RF212
    wdba1281               : Meshnetics MeshBean WDB-A1281-* development board
    mnb900                 : Meshnetics MeshBean MNZB-900 development board
    zgbl{230,231,212}      : ATZGB ZGB-LINK module
    zgbh{230,231,212}      : ATZGB EVM-HOST with ZGB-LINK module
    ict230                 : version 1.0 of In-Cirquit Radio Stick/Module
    ic{sm}230_11           : version 1.1 of In-Cirquit Radio Stick/Module
    tiny230                : Joerg's (DL8DTL) ATtiny44 with AT86RF230
    stkm16                 : ATmega16 + AT86RF230 adapter on stk500
    stkt26                 : ATtiny26 + AT86RF230 adapter on stk500
""")
