#   Copyright (c) 2007...2012 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$

#=== modules ==================================================================
import os, time, sys, zipfile, glob, stat, pprint
sys.path.append("./Tools")
import ds2reg, boardcfg

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

com = Environment (
    tools = ['mingw'],
    CC="avr-gcc",
    CXX="avr-g++",
    DBGFMT=dbgfmt,
    CXXFLAGS="-g$DBGFMT -mmcu=$CPU -Wall -Wundef -fshort-enums -D$BOARD_TYPE",
    CCFLAGS="-g$DBGFMT -mmcu=$CPU -Wall -Wundef -fshort-enums -D$BOARD_TYPE",
    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"

# 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 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()

#
# This function comes from:
# http://code.activestate.com/recipes/200131-recursive-directory-listing-in-html/
def walk_tree(top = ".", depthfirst = True):
    if os.path.isdir(top):
        names = os.listdir(top)
        if not depthfirst:
            yield top, names
        for name in names:
            try:
                st = os.lstat(os.path.join(top, name))
            except os.error:
                continue
            if stat.S_ISDIR(st.st_mode):
                for (newtop, children) in walk_tree(os.path.join(top, name), depthfirst):
                    yield newtop, children
        if depthfirst:
            yield top, names
    else:
        dn, fn = os.path.split(top)
        yield dn, [fn]


##
# Retrieve a file from the Web.
def wget_file(env, target, source):
    import urllib
    ret = urllib.urlretrieve(env["URL"], str(target[0]))

##
# This the Zipfile Builder Function for generating
# arbitrary Zipfiles.
#
# The function walk_tree is used to traverse any directory
# given and recursively adding the files therein.
#
# @param target
#        Name of the Zipfile
# @param source
#        List of the source files packed into the archive
# @param env
#        From env the following keys will be used:
#        - PREFIX :
#          prefix that is prepended to each file packed in the archiv.
#        - UNPREFIX :
#          prefix that is removed from source file path.
#          It must not start with "/"
#        - RELOCATE :
#          Dicitionry that is used for translating file and directory names.
#        - COMMENT :
#          maximum 65535 byte long string that is added as comment.
#
def create_zip_file(target, source, env):
    target = str(target[0])
    print "Zip", target
    sources = map(str,source)
    prefix = env.get("PREFIX","")
    relocate = env.get("RELOCATE",{})
    unprefix = env.get("UNPREFIX", None)
    comment = env.get("COMMENT",None)
    # generate list of sourcefiles and its name mappings in zipfile
    ziplist = []
    for src in sources:
        for indirname, filelst in walk_tree(src):
            # normalize dirname to have / seperator to do dictionary lookup
            indn = indirname.replace("\\","/")
            outdirname = relocate.get(indn, indn)
            if unprefix:
                outdirname = os.path.relpath(outdirname, unprefix)
            for infilename in filelst:
                outfilename = relocate.get(infilename,infilename)
                infn = os.path.join(indirname,infilename)
                outfn = os.path.join(prefix, outdirname, outfilename)
                ziplist.append( (infn, outfn) )

    # write zipfile
    zf = zipfile.ZipFile(target,"w")
    for fn_in, fn_out in ziplist:
        zf.write(fn_in, fn_out, zipfile.ZIP_DEFLATED)
    if comment != None:
        zipfile.ZipFile.comment = comment
    zf.close()
##
# Upack the Zipfile given in source[0] to the
# directory target[0]
#
def unpack_zip_file(target, source, env):
    todir = str(target[0])
    zf = zipfile.ZipFile(str(source[0]),"r")
    try:
        zf.extractall(todir)
    except:
        for n in zf.namelist():
            dest = os.path.join(todir, n)
            destdir = os.path.dirname(dest)
            if not os.path.isdir(destdir):
                os.makedirs(destdir)
            data = zf.read(n)
            if len(data):
                f = open(dest, 'w')
                f.write(data)
                f.close()
        zf.close()


def get_packages(fname):
    import ConfigParser
    global PACKAGES
    cfgp = ConfigParser.ConfigParser()
    cfgp.read(fname)
    ret = {}
    for s in cfgp.sections():
        ret[s] = {
                    "name"    : s,
                    "boards" : [],
                    "depends" : [],
                    "files" : [],
                    "relocate" : {},
                    "comment"  : None,
                    "unprefix" : None
                 }
        d = ret[s]
        for k,v in (cfgp.items(s)):
            if k == "depends":
                d[k] = v.replace("\n"," ").split(" ")
            if k == "boards":
                d[k] = v.replace("\n"," ").split(" ")
            elif k == "files":
                d[k] = v.replace("\n"," ").split(" ")
            elif k == "relocate":
                d[k] = dict(map(lambda x: x.split(":"),v.replace("\n"," ").split(" ")))
            elif k == "comment":
                v = v.strip()
                if len(v) > 0:
                    d[k] = v
                else:
                    d[k] = None
            else:
                d[k] = v.strip()
    return ret

def write_board_cfg_h(target, source, env):
    boardnames = env.get('SELECTED_BOARDS', env["boards"].keys())
    preselbrd = env.get('PRESELECTED_BOARD', None)
    boardcfg.write_board_header_file(env['boards'], str(target[0]), boardnames, preselbrd)


# === setup the common environment ===============================
com['VERSION'] = ARGUMENTS.get("version",
                               "%s" % time.strftime("%Y%m%d"))
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["PKG_CFG_FILE"] = "packages.cfg"
com["PKG_CONFIG"]  = get_packages(com["PKG_CFG_FILE"])

# yes, it is rude to kick off windows users here, but I could not get
# a2x running under WinXP
if com.WhereIs("a2x") and \
   com.WhereIs("dblatex") and \
   com.WhereIs("pdflatex") and \
   com.WhereIs("asciidoc") and \
   sys.platform.find("win") < 0:
    com["HAVE_ASCIIDOC"] = True
else:
    com["HAVE_ASCIIDOC"] = False


# === process the board config file ==========================================
com["BOARD_CFG_FILE"] = ARGUMENTS.get("boards", "Src/Lib/Inc/boards/board.cfg")
CUSTOM_BOARD_DIR = os.path.dirname(com["BOARD_CFG_FILE"]) + "/boards"
if os.path.isdir(CUSTOM_BOARD_DIR):
    com["CUSTOM_BOARD_DIR"] = com.Dir(CUSTOM_BOARD_DIR)
else:
    com["CUSTOM_BOARD_DIR"] = None
com["boards"]    = boardcfg.get_boards(com['BOARD_CFG_FILE'])
com["boardopts"] = boardcfg.generate_board_dictionary_expanded(com['boards'])

com['BUILDERS']['RadioHeaderWriter'] = Builder(action = create_radio_headerfiles)
com['BUILDERS']['BoardCfgWriter'] = Builder(action = write_board_cfg_h)
com['BUILDERS']['DoxyfileTransformer'] =  Builder(action = configure_doxyfile)
com['BUILDERS']['TextTransformer'] =  Builder(action = configure_textfile)
com['BUILDERS']['ZipFile'] =  Builder(action = create_zip_file, suffix = '.zip')

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 = []
current_packakes = []

# process package targets
for k in com['PKG_CONFIG'].keys():
    if k in COMMAND_LINE_TARGETS:
        current_boards.extend(com['PKG_CONFIG'][k]['boards'])
        current_packakes.append(k)

# process board targets
for board in com["boardopts"].keys():
    if board in COMMAND_LINE_TARGETS:
        current_boards.append(board)

# handle special targets like "all", "help", "doc"
if 'all' in COMMAND_LINE_TARGETS or \
   len(COMMAND_LINE_TARGETS) == 0 or \
   RUN_SLOW:
    current_boards = com["boardopts"].keys()
    current_boards.sort()

if GetOption('help'):
    current_boards = []

if len(COMMAND_LINE_TARGETS) == 1 and 'doc' in COMMAND_LINE_TARGETS:
	current_boards = []

# Build Rules for Boards
for board in current_boards:
    avr['cmdline_baudrate'] = ARGUMENTS.get('baudrate', None)
    avr.SConscript('Src/Lib/SConscript',
                    variant_dir = '${dir_build}/%s/lib' % board,
                    exports="avr board",
                    duplicate = 0
                    )

    avr.SConscript('Src/App/SConscript',
                    variant_dir = '${dir_build}/%s/app' % board,
                    exports="avr board",
                    duplicate = 0
                    )

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

#
# Install Example sources
#
for xmpl in com.Glob('Src/Xmpl/xmpl*.[hc]'):
    if str(xmpl).find("lw_m") < 0:
        x = avr.Install('$dir_install_xmpl',xmpl)

for xmpl in avr.Glob('Src/Xmpl/xmpl*.c'):
    if str(xmpl).find("lw_m") < 0:
        project = os.path.split(str(xmpl))[1].replace(".c","")
        makefile = project + ".mk"
        # building makefile
        all_rule, board_rules = boardcfg.get_app_make_rules(project)
        avr.TextTransformer("install/xmpl/%s" % makefile,
                        "Templates/xmpl.mk",
                        STRINGPARAM = { 'project'     : project,
                                        'makefile'    : makefile,
                                        'all_rule'    : all_rule,
                                        'board_rules' : board_rules,
                                        'more_flags'  : ""
                                       })

        # building apsfile
        try:
            aps_configs, default_config = boardcfg.get_xmpl_aps_rules(project)
            avr.TextTransformer("install/xmpl/%s.aps" % project,
                        "Templates/xmpl.aps",
                        STRINGPARAM = { 'project'     : project,
                                        'makefile'    : makefile,
                                        'all_configs' : aps_configs,
                                        'default_config' : default_config
                                       })

            avr.InstallAs('install/xmpl/Makefile', "Src/Xmpl/Makefile.in")

        except IndexError:
            pass

# Sniffer Source Code
all_rule, board_rules = boardcfg.get_app_make_rules("sniffer")
avr.Install("install/sniffer", avr.Glob("Src/App/Sniffer/*.[hc]"))
avr.TextTransformer("install/sniffer/Makefile",
                    "Templates/app.mk",
                    STRINGPARAM = { 'project'     : "sniffer",
                                    'makefile'    : "Makefile",
                                    'all_rule'    : all_rule,
                                    'board_rules' : board_rules,
                                    'more_flags'  : "",
                                    'sources'     : "sniffer_ctrl.c sniffer_scan.c"})


# Wuart Source Code
all_rule, board_rules = boardcfg.get_app_make_rules("wuart")
avr.Install("install/wuart", ["Src/App/wuart.c",
                              "Src/App/wuart.h",
                              "Tools/sterm.py"])
avr.TextTransformer("install/wuart/Makefile",
                    "Templates/xmpl.mk",
                    STRINGPARAM = { 'project'     : "wuart",
                                    'makefile'    : "Makefile",
                                    'all_rule'    : all_rule,
                                    'board_rules' : board_rules,
                                    'more_flags'  : ""})

# Lwmesh Tlogger Application
all_rule, board_rules = boardcfg.get_app_make_rules("lwm_tlogger")
avr.InstallAs("install/lwm/lwm_tlogger.c", "Src/App/LWM_Tlogger/tlogger.c")
avr.Install("install/lwm", ["Src/App/LWM_Tlogger/meas_raven.c",
                            "Src/App/LWM_Tlogger/meas_rfa.c",
                            "Src/App/LWM_Tlogger/meas_m1281.c",
                            "Src/App/LWM_Tlogger/meas.c",
                            "Src/App/LWM_Tlogger/meas.h",
                            "Src/App/LWM_Tlogger/tlogger.h",
                            "Src/App/LWM_Tlogger/sensordata.h"
                            ])

avr.TextTransformer("install/lwm/lwm_tlogger.mk",
                    "Templates/xmpl.mk",
                    STRINGPARAM = { 'project'     : "lwm_tlogger",
                                    'makefile'    : "lwm_tlogger.mk",
                                    'all_rule'    : all_rule,
                                    'board_rules' : board_rules,
                                    'more_flags'  : "SOURCES += meas.c meas_rfa.c meas_raven.c meas_m1281.c\n"\
                                                    "CCFLAGS +="\
                                                    " -Os -fpack-struct"\
                                                    " -fshort-enums"\
                                                    " -funsigned-char"\
                                                    " -funsigned-bitfields"\
                                                    " -pedantic -std=gnu99\n"\
                                                    "LDFLAGS += -Wl,-u,vfprintf -lprintf_flt\n"
                                                    })

# Lwmesh Host Application
all_rule, board_rules = boardcfg.get_app_make_rules("lwm_host")
avr.InstallAs("install/lwm/lwm_host.c", "Src/App/LWM_Tlogger/host.c")

avr.TextTransformer("install/lwm/lwm_host.mk",
                    "Templates/xmpl.mk",
                    STRINGPARAM = { 'project'     : "lwm_host",
                                    'makefile'    : "lwm_host.mk",
                                    'all_rule'    : all_rule,
                                    'board_rules' : board_rules,
                                    'more_flags'  : "CCFLAGS +="\
                                                    " -Os -fpack-struct"\
                                                    " -fshort-enums"\
                                                    " -funsigned-char"\
                                                    " -funsigned-bitfields"\
                                                    " -pedantic -std=gnu99\n"\
                                                    "LDFLAGS += -Wl,-u,vfprintf -lprintf_flt\n"
                                                    })






# WiBo Source Code
all_rule, board_rules = boardcfg.get_app_make_rules("wibo")
avr.InstallAs("install/wibo/wibo.c", "Src/App/WiBo/BootlApp/bootlapp.c")
avr.TextTransformer("install/wibo/wibo.mk",
                    "Templates/xmpl.mk",
                    STRINGPARAM = { 'project'     : "wibo",
                                    'makefile'    : "wibo.mk",
                                    'all_rule'    : all_rule,
                                    'board_rules' : board_rules,
                                    'more_flags'  : "CCFLAGS +="\
                                                    " -Os -fpack-struct"\
                                                    " -fshort-enums"\
                                                    " -funsigned-char"\
                                                    " -funsigned-bitfields"\
                                                    " -pedantic -std=gnu99\n"\
                                                    "LDFLAGS += -Wl,--section-start,.text=$(BOOTOFFSET)\n"
                                                    })




# WiBo Host Source Code
all_rule, board_rules = boardcfg.get_app_make_rules("wibohost")
avr.Install("install/wibo", ["Src/App/WiBo/HostApp/cmdif.c",
                             "Src/App/WiBo/HostApp/cmdif.h",
                             "Src/App/WiBo/HostApp/wibohost.h",
                             "Src/App/WiBo/HostApp/wibohost.c",
                             "Src/App/WiBo/HostApp/hostapp.c",
                             "Src/App/WiBo/HostApp/hexparse.c",
                             "Src/App/WiBo/HostApp/hexparse.h",
                             "Src/App/WiBo/PyHost/wibohost.py"
                             ])

avr.TextTransformer("install/wibo/wibohost.mk",
                    "Templates/xmpl.mk",
                    STRINGPARAM = { 'project'     : "wibohost",
                                    'makefile'    : "wibohost.mk",
                                    'all_rule'    : all_rule,
                                    'board_rules' : board_rules,
                                    'more_flags'  : "SOURCES += hostapp.c cmdif.c hexparse.c\n"\
                                                    "CCFLAGS +="\
                                                    " -Os -fpack-struct"\
                                                    " -fshort-enums"\
                                                    " -funsigned-char"\
                                                    " -funsigned-bitfields"\
                                                    " -std=gnu99\n"
                                    })

# WiBo Address generator
board_mmcu_table = pprint.pformat(\
                        dict( [(b, avr['boardopts'][b].cpu) \
                               for b in avr['boardopts'].keys()]))

avr.TextTransformer('install/wibo/nodeaddr.py',
                    ["#Templates/wibo_gen_py.tpl"],
                     STRINGPARAM = {
                         'filename'  : "nodeaddr",
                         'version'   : avr['VERSION'],
                         'board'     : "UNKNOWN",
                         'mmcu_table': board_mmcu_table
                         })

# WiBo Example Application
all_rule, board_rules = boardcfg.get_app_make_rules("xmpl_wibo")
avr.InstallAs("install/wibo/xmpl_wibo.c", "Src/App/WiBo/XmplApp/main.c")
avr.TextTransformer("install/wibo/xmpl_wibo.mk",
                    "Templates/xmpl.mk",
                    STRINGPARAM = { 'project'     : "xmpl_wibo",
                                    'makefile'    : "xmpl_wibo.mk",
                                    'all_rule'    : all_rule,
                                    'board_rules' : board_rules,
                                    'more_flags'  : "BLINK = 0xffff\n\n"\
                                                    "CCFLAGS +="\
                                                    " -DBLINKPERIOD_MS=$(BLINK)"\
                                                    " -Os -fpack-struct"\
                                                    " -fshort-enums"\
                                                    " -funsigned-char"\
                                                    " -funsigned-bitfields"\
                                                    " -std=gnu99\n"
                                    })
# WiBo Doc
avr.InstallAs("install/wibo/README.txt", "Src/App/WiBo/doc.txt")

# RavenLCD source code
avr.Install("install/ravenlcd",
            [
                "Contrib/RavenLCD/Makefile",
                "Contrib/RavenLCD/RavenLCD.asciidoc",
                "Contrib/RavenLCD/analog.c",
                "Contrib/RavenLCD/analog.h",
                "Contrib/RavenLCD/cmdif.c",
                "Contrib/RavenLCD/cmdif.h",
                "Contrib/RavenLCD/lcd.c",
                "Contrib/RavenLCD/lcd.h",
                "Contrib/RavenLCD/main.c",
                "Contrib/RavenLCD/usart.c",
                "Contrib/RavenLCD/usart.h",
                "Contrib/RavenLCD/ravenlcd.aps",
                "Contrib/RavenLCD/ravenlcd.py",
            ])

#
# Contributions
#
contr = com.Clone()
contr.SConscript("Contrib/Arduino/SConscript",
               exports="contr board", duplicate=0)

contr.SConscript("Contrib/PacketCapture/SConscript",
               exports="contr board", duplicate=0)

contr.SConscript("Contrib/Rose/SConscript",
               exports="contr avr board", duplicate=0,
               variant_dir = '${dir_build}/rose')

contr.SConscript("Contrib/RavenLCD/SConscript",
               exports="avr", duplicate=0,
               variant_dir = '${dir_build}/ravlcd')
#
# Documentation targets
#
doc = com.Clone()

doc['dox_version'] = doc["VERSION"]

doc.SConscript("Doc/SConscript.all", variant_dir='build/alldoc',
               exports="doc", duplicate=0)

#=== install ==========================================================

# Create the library source distribution.
#
# This steps perform the following actions:
#  - copy the source files
#  - generate a Makefile for all boards
#  - run the Makefile with "all" target
#  - verify the make generated libs against
#    the scons generated libs.
#
srcradio = com.Install("install/src/libradio",
                        com.Glob("Src/Lib/Rf230/*.c") +
                        com.Glob("Src/Lib/P2P/*.c")
                        )
srcioutil = com.Install("install/src/libioutil",
                        com.Glob("Src/Lib/Ioutil/*.c"))
#srcwibohost = com.Install("install/src/libwibohost",
#                        com.Glob("Src/App/WiBo/HostApp/[hw][ei][xb]*.[hc]"))

all_rule, board_rules = boardcfg.get_lib_make_rules()
com.TextTransformer("install/src/Makefile",
                    "Templates/src.mk",
                    STRINGPARAM = {'all_rule'    : all_rule,
                                   'board_rules' : board_rules,
                                   'more_flags'  : "CCFLAGS +="\
                                                    " -Os -fpack-struct"\
                                                    " -fshort-enums"\
                                                    " -funsigned-char"\
                                                    " -funsigned-bitfields"\
                                                    " -std=gnu99\n"
                                   })
#
# tools for library verification
#
def get_archiv_md5(libname):
    import subprocess as sp
    import hashlib
    # strip library
    if not os.path.exists(libname):
    	return (libname,0,None)
    cmd = ["avr-strip", "-g", libname]
    sp.Popen(cmd, stdout=sp.PIPE).communicate()[0]
    # retrieve sorted list of module names from library
    cmd = ["avr-ar", "t", libname]
    tmp = sp.Popen(cmd, stdout=sp.PIPE).communicate()[0]
    m = tmp.split()
    m.sort()
    # print lib contents with sorted module names
    cmd = ["avr-ar", "p", libname] + m
    tmp = sp.Popen(cmd, stdout=sp.PIPE).communicate()[0]
    # compute md5 digest
    md5 = hashlib.md5()
    md5.update(tmp)
    return (libname,len(tmp),md5.hexdigest())

def verify_libaries_md5(env, target, source):
	fails = []
	for dutlib in glob.glob(str(source[0])+"/*.a"):
		dut = get_archiv_md5(dutlib)
		reflib = os.path.join("install/lib",os.path.basename(dutlib))
		ref = get_archiv_md5(reflib)
		# missing libraries are not treated as failure
		#if ref[2] != dut[2] and ref[2] != None:
		if ref[2] != dut[2]:
			fails.append((dut,ref))
			print "FAIL:", dut[0]
			print "  ref: ",ref
			print "  dut: ",dut
		else:
			print "OK:", dut[0], dut[2]
	f = open(str(target[0]),'w')
	for x in fails:
		f.write("%s\n%s\n" % x)
	f.close()

# run the makefile
test_libs = com.Command(
			"build/test/lib", "install/src",
			[ "make -C install/src LIBDIR=\"${TARGET.abspath}\" OBJDIR=\"${TARGET.abspath}/obj\" all"])

com.Command("build/test/log", test_libs, verify_libaries_md5)
com.InstallAs("install/README", "Doc/readme-src.txt")


# === generate pdf files from asciidoc =======================================
com.InstallAs("install/pdf/uracoli-src.txt", "Doc/uracoli-src.txt")
com.InstallAs("install/pdf/uracoli-wibo.txt", "Src/App/WiBo/doc.txt")
com.InstallAs("install/pdf/uracoli-sterm.txt", "Doc/uracoli-sterm.txt")
com.InstallAs("install/pdf/uracoli-lwmesh.txt", "Doc/uracoli-lwmesh.txt")
com.InstallAs("install/readme_epj00.txt", "Appnotes/rfarduino/demoapp_tlogger/README.txt")
if com["HAVE_ASCIIDOC"] :
    com.Command("install/pdf/uracoli-src.pdf", "install/pdf/uracoli-src.txt",
                ["a2x -v -L -f pdf $SOURCE"])

    com.Command("install/pdf/uracoli-wibo.pdf", "install/pdf/uracoli-wibo.txt",
                ["a2x -v -L -f pdf $SOURCE"])

    com.Command("install/pdf/uracoli-sterm.pdf", "install/pdf/uracoli-sterm.txt",
                ["a2x -v -L -f pdf $SOURCE"])
    com.Command("install/pdf/uracoli-lwmesh.pdf", "install/pdf/uracoli-lwmesh.txt",
                ["a2x -v -L -f pdf $SOURCE"])
    com.Command("install/readme_epj00.html", "install/readme_epj00.txt",
                ["asciidoc $SOURCE"])

com.Alias('src_dist',
          ['build/test/lib',
           'install/wuart',
           'install/wibo',
           'install/xmpl',
           'install/lwm',
           'install/ravenlcd',
           'install/pdf',
           ])

com.Command("strip_libs", com.Glob("install/lib/*.a"),["avr-strip -g $SOURCES"])


# library includes
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/hif_uart.h",
         "Src/Lib/Ioutil/hif_usb.h",
         "Src/Lib/Inc/timer.h",
         "Src/Lib/Inc/hif.h",

         "Src/Lib/Inc/p2p.h",
         "Src/Lib/Inc/p2p_protocol.h",

         ])

boardincludes = Glob("Src/Lib/Inc/boards/*.h")
if com["CUSTOM_BOARD_DIR"]:
    boardincludes += com.Glob("$CUSTOM_BOARD_DIR/*.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')
i3e = com.RadioHeaderWriter('${dir_install}/inc/atmega_rfa1.h','Templates/atmega_rfa1.txt')
i3f = com.RadioHeaderWriter('${dir_install}/inc/at86rf232.h','Templates/at86rf232.txt')
i3g = com.RadioHeaderWriter('${dir_install}/inc/at86rf233.h','Templates/at86rf233.txt')
i4  = com.BoardCfgWriter("${dir_install}/inc/board_cfg.h", "${BOARD_CFG_FILE}")

# Build Rules for Packages
for pkg in current_packakes:
    pcfg = com['PKG_CONFIG'][pkg]
    pkgname = pcfg.get("name", pkg)
    pname = avr.subst("%s-$VERSION" % pkgname)
    prefix = pcfg.get("prefix",pname)
    flist = []
    for p in pcfg["files"]:
        flist.extend(com.Glob(p))
    ppkg = com.ZipFile(
           "#/install/%s.zip" % pname,
           flist,
           PREFIX = prefix,
           UNPREFIX = pcfg["unprefix"],
           RELOCATE = pcfg["relocate"],
           COMMENT = pcfg["comment"] )
    deps = pcfg.get("depends",None)
    print deps
    if deps != None and deps != []:
        avr.Depends(ppkg, deps.split(" "))
    avr.Alias(pkg, ppkg)


# === Prequisites for the USB package ===
cdmzip = com.Command("downloads/CDM20808.zip", [], wget_file,
            URL="http://www.ftdichip.com/Drivers/CDM/CDM20808.zip")
com.NoClean(cdmzip) # keep this if if gathered once
com.Command("build/usb/windows/ftdi", "downloads/CDM20808.zip",
            unpack_zip_file)
com.Install("build/usb/windows/cdc", "Doc/Dev/uracoli-cdc.inf")
com.Clean("build/usb/", "build/usb/windows")
#=== clean ============================================================
com.Clean("distclean",["$dir_build", "$dir_install"])
com.Clean("clean",["$dir_build"])

#=== aliases ==========================================================
libtargets = map(lambda b: "l%s" % b, com["boards"].keys())
apptargets = map(lambda b: "a%s" % b, com["boards"].keys())
xmpltargets = map(lambda b: "x%s" % b, com["boards"].keys())
for i in com["boardopts"].keys():
    avr.Alias(i, Split("l%s a%s x%s"%(i,i,i)))

avr.Alias('all', ["install"])
com.Alias('doc', ['install/doc'])

com.Alias('install', [i1, i2, i3a, i3b, i3c, i3d, i3e, i3f, i3g, i4, com["dir_install"] ])
com.Alias('packages', "psrc pdoc psniffer parduino".split())

com.Help("""

Build System for the 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

    Use "scons slow=1 <args>" to disable all optimizations

A <target> can be:
    all          : libraries and applications for all plattforms
    doc          : documentation
    xmpl         : build example source directory
    <BoardType>  : libraries and applications for specified board type

Special Targets:
    arduino      : create an arduino update directory
    ravlcd       : build firmware for raven lcd controller
    roseapps     : build rocket sensor applications

Pakages:
    psrc         : Source Package
    pdoc         : Documentation Package
    psniffer     : Sniffer Package
    parduino     : Adruino Package

The follwing <BoardType>s are defined in $BOARD_CFG_FILE:

""" + (boardcfg.show_boards(com["boards"])))
