#   Copyright (c) 2013 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$

# === import ==================================================================
import os, time, hashlib, sqlite3, subprocess
from utilities import *
# === globals =================================================================

# === functions ===============================================================
def announce_config(cfg):
    global CFGDATA
    CFGDATA = cfg
    try:
        dbname = CFGDATA.get("CONFIG", "dbfile")
    except:
        dbname = "regression.db"
    open_db(dbname)

def open_db(dbfile):
    global DB_CONN, DB_CURS, CFGDATA
    print "open_db:", dbfile
    DB_CONN = sqlite3.connect(dbfile)
    DB_CURS = DB_CONN.cursor()
    DB_CURS.execute("CREATE TABLE IF NOT EXISTS firmware "\
                    "(board TEXT, fwname TEXT, md5 TEXT)")

def is_node_flashed(devname, fwname):
    x = DB_CURS.execute("SELECT * FROM firmware WHERE board = ?", (devname,))
    data = x.fetchone()
    rv = False
    if data:
        board, dbfwname, fwdigest = map(str,data)
        z = get_md5(fwname)
        if fwdigest == z and devname == board and fwname == dbfwname:
            print "firmware does match - no flash"
            rv = True
        else:
            print "firmware does not matches - need reflash"
            rv = False
    return rv

def update_node_flashed(devname, fwname):
    x = DB_CURS.execute("SELECT * FROM firmware WHERE board = ?", (devname,))
    fwdigest = get_md5(fwname)
    data = dict(fwname = fwname, board = devname, md5 = fwdigest)
    if x.fetchone():
        cmd = "UPDATE firmware SET fwname=:fwname, "\
              " md5 = :md5 WHERE board = :board"
    else:
        cmd = "INSERT INTO firmware VALUES(:board, :fwname, :md5)"
    DB_CURS.execute(cmd, data)
    DB_CONN.commit()



def ping_dude(devname):
    global CFGDATA
    cmd = CFGDATA.get('CONFIG', 'programmer') + " " +\
          CFGDATA.get(devname, 'jtagopts') + ""
    rc, stdout, stderr = execute(cmd)
    if rc != 0:
        print "ping_dude failed"
        print "cmd: %s" % cmd
        print "rc = %d" % rc
        print "stderr: %s" % stderr.replace("\n", "\nstderr: ")
        print "stdout: %s" % stdout.replace("\n", "\nstdout: ")
        fatal_error("ping_dude() failed for %s" % devname)

# e.g. prog_template = "install/bin/xmpl_hif_%s.hex"
def load_firmware(devname, prog_template, force_flash = False):
    global CFGDATA
    cmd = CFGDATA.get('CONFIG', 'programmer') + " " +\
          CFGDATA.get(devname, 'jtagopts') + ""
    bn = CFGDATA.get(devname, 'boardname')
    prog = prog_template % bn

    assert(os.path.exists(prog))

    if is_node_flashed(devname, prog) and not force_flash:
        do_flash = False
    else:
        do_flash = True

    if do_flash:
        cmd += " -U fl:w:%s:i" % prog
        rc,stdout,stderr = execute(cmd)
        if rc == 0:
            update_node_flashed(devname, prog)
        else:
            print "ping_dude failed"
            print "cmd: %s" % cmd
            print "rc = %d" % rc
            print "stderr: %s" % stderr.replace("\n", "\nstderr: ")
            print "stdout: %s" % stdout.replace("\n", "\nstdout: ")
            fatal_error("load_firmware() failed for %s" % devname)
    else:
        ping_dude(devname)
    time.sleep(2)

def get_md5(fname):
    try:
        f = open(fname, "r")
        m = hashlib.md5()
        m.update(f.read())
        rv = m.hexdigest()
        f.close()
    except:
        rv = None
    return rv

# === classes =================================================================

# === init ====================================================================
