#!/usr/bin/python -tt
#
# **************************************************************************
# ** upgrade-usb ***********************************************************
# **************************************************************************
# *
# * This script is used to flash the body code on to each USB device
# * and can also be used for testing.  Additionally it may be replace
# * the existing firmware on a device with any other version.
# *
# * Copyright (C) 2007, IguanaWorks Incorporated (http://iguanaworks.net)
# * Author: Joseph Dunn <jdunn@iguanaworks.net>
# *
# * Distributed under the GPL version 2.
# * See LICENSE for license details.
# */

import warnings
import traceback
import tempfile
import struct
import errno

from reflasher import *
import reflasher

#null = open(os.devnull, 'r+')

#local variables
test = False
userSaysKeep = False
userSaysKeepAll = False
onlyOne = True
defaultType = 'c'
devOK = False
skipReceiver = False

index = 1
while index < len(sys.argv):
    arg = sys.argv[index]
    if arg == "--blank-pages":
        fullFlash = True
    elif arg == "--devel-ok":
        devOK = True
    elif arg == "-h" or arg == "--help":
        printUsage()
    elif arg == "--loader":
        index += 1
        reflasher.loader = sys.argv[index]
    elif arg == "--force":
        reflasher.forceFlash = True
    elif arg == "--flash-multiple":
        onlyOne = False
    elif arg == "--body":
        index += 1
        reflasher.body = sys.argv[index]
    elif arg == "--old-firmware":
        index += 1
        reflasher.usb_ir = sys.argv[index]
    elif arg == '--keep-loader':
        userSaysKeep = True
    elif arg == '--keep-all':
        userSaysKeepAll = True
    elif arg == "-l" or arg == "--log-file":
        index += 1
        logFile = sys.argv[index]
        if logFile == "-":
            logFile = None
    elif arg == "-q" or arg == "--quiet":
        if currentLevel > LOG_FATAL:
            currentLevel -= 1
    elif arg == "--skip-receiver":
        skipReceiver = True
    elif arg == "-t" or arg == "--type":
        index += 1
        defaultType = sys.argv[index]
    elif arg == "-v" or arg == "--verbose":
        currentLevel += 1
    elif arg == "--version":
        index += 1
        reflasher.targetVersion = sys.argv[index]
    elif arg == "--dry-run":
        reflasher.UNSAFE = False
    elif arg == "--test":
        test = True
    else:
        printUsage("Unknown argument: " + arg + "\n")
    index += 1

# open the log file if specified
if logFile != None:
    sys.log = open(logFile, "a", 1)
    logFile = "-"

# find the file names to fufill the version requirements
if reflasher.targetVersion is not None:
    reflasher.targetVersion = int(reflasher.targetVersion, 0)
    if reflasher.targetVersion < 0x0100:
        if reflasher.usb_ir is None:
            reflasher.usb_ir = reflasher.targetVersion
    else:
        if reflasher.loader is None:
            reflasher.loader = reflasher.targetVersion >> 8
        if reflasher.body is None:
            reflasher.body = reflasher.targetVersion & 0xFF

# find the files that will be loaded onto the device
if reflasher.usb_ir is None:
    if reflasher.loader is None or isinstance(reflasher.loader, int):
        # find the most recent loader
        reflasher.loader = reflasher.findHexFile('loader', reflasher.loader,
                                                 devOK = devOK)

    if reflasher.loader is None:
        reflasher.usb_ir = reflasher.findHexFile('usb_ir', devOK = devOK)
    elif reflasher.body is None or isinstance(reflasher.body, int):
        reflasher.body = reflasher.findHexFile('body', reflasher.body,
                                               reflasher.body != 0,
                                               devOK = devOK)

elif isinstance(reflasher.usb_ir, int):
    reflasher.usb_ir = reflasher.findHexFile('usb_ir',
                                             reflasher.usb_ir, devOK = devOK)

# compute the target version from the files to report to the user
if reflasher.usb_ir:
    reflasher.targetVersion = hexVersion(reflasher.usb_ir)
else:
    reflasher.targetVersion = hexVersion(reflasher.loader) << 8
    if reflasher.body:
        reflasher.targetVersion |= hexVersion(reflasher.body)

message(LOG_NORMAL, warningMesg + "\nUsing firmware version 0x%4.4x\n" % reflasher.targetVersion)

# must default to at least a 1 character string
default = ' '
line = defaultType
while True:
    try:
        # reconnect as necessary
        reconnect()

        if line == 'c':
            line = ''
            features = deviceFeatures()
            if not features:
                if not isinstance(features, bool):
                    line = 'u'
            elif features == iguanaIR.IG_HAS_SOCKETS:
                line = 's'
            elif features == iguanaIR.IG_HAS_BOTH:
                line = 'h'
            elif features == iguanaIR.IG_HAS_LEDS:
                line = 'l'

        # check user input
        type = None
        while True:
            if line and line[0].lower() in 'ushlc':
                type = line[0].lower()
                default = type.upper()
                line = ' '
                break

            selection = '[u/s/h/l]'.replace(default.lower(), default)
            if default.strip() and onlyOne:
                raise KeyboardInterrupt()

            message(LOG_NORMAL, """
What kind of device is plugged in?
  unenclosed, 2 socket, hybrid, or 2 LED? %s
""" % selection)
            line = sys.stdin.readline().strip()
            if not line:
                line = default

        if type == 'u':
            type = 'unenclosed'
            plugs = ()
            leds = (0x0,)
            features = 0
        elif type == 's':
            type = '2 socket'
            plugs = (0xF, 0x1, 0x2, 0x4, 0x8, 0x4, 0x2, 0x1, 0xF)
            leds = ()
            features = iguanaIR.IG_HAS_SOCKETS
        elif type == 'h':
            type = 'hybrid'
            plugs = (0xC, 0x4, 0x8, 0x4, 0xC)
            leds = (0x1,)
            features = iguanaIR.IG_HAS_BOTH
        elif type == 'l':
            type = '2 LED'
            plugs = ()
            leds = (0x1, 0x4)
            features = iguanaIR.IG_HAS_LEDS

        # reflash the device with information about what kind it is
        message(LOG_NORMAL, 'Writing firmware to "%s" device.\n' % type)
        if not userSaysKeepAll:
            reflashDevice(features, userSaysKeep)
        if not test:
            continue

        # connect to the device and check the version
        message(LOG_NORMAL, "Checking device version to test.\n")
        version = deviceVersion()
        if ((version >> 8) == 0 or (version & 0xFF) == 0) and \
           version != 3 and \
           version != 4:
            message(LOG_ERROR,
                    "This script cannot test a version %s device.\n" % version)
            continue

        if not skipReceiver:
            message(LOG_NORMAL, "Checking receiver.\n")
            if not checkReceiver():
                message(LOG_ERROR, "Receiver FAILURE.\n")
                continue

        if plugs:
            message(LOG_NORMAL, "Doing sockets tests.\n")
            for channels in plugs:
                deviceTransaction(iguanaIR.IG_DEV_SETCHANNELS,
                                  chr(channels))
                sendPanasonicPower()
                time.sleep(0.1)

        if leds:
            message(LOG_NORMAL, "Doing led tests.\n")
            for channels in leds:
                message(LOG_NORMAL, "Press enter to send panasonic power on channel %s.\n" % channels)
                line = sys.stdin.readline()
                deviceTransaction(iguanaIR.IG_DEV_SETCHANNELS,
                                  chr(channels))
                sendPanasonicPower()
                if len(leds) == 1:
                    message(LOG_NORMAL, "Press enter to send again.\n")
                else:
                    message(LOG_NORMAL,
                            "Flip, then press enter to send again.\n")
                line = sys.stdin.readline()
                deviceTransaction(iguanaIR.IG_DEV_SETCHANNELS,
                                  chr(channels))
                sendPanasonicPower()

    except KeyboardInterrupt:
        if type is None or onlyOne:
            break
