#!/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 *

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

#local variables
UNSAFE = True
fullFlash = False
targetVersion = None
test = False
forceFlash = 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
        loader = sys.argv[index]
    elif arg == "--force":
        forceFlash = True
    elif arg == "--flash-multiple":
        onlyOne = False
    elif arg == "--body":
        index += 1
        body = sys.argv[index]
    elif arg == "--old-firmware":
        index += 1
        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
        targetVersion = sys.argv[index]
    elif arg == "--dry-run":
        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 targetVersion is not None:
    targetVersion = int(targetVersion, 0)
    if targetVersion < 0x0100:
        if usb_ir is None:
            usb_ir = targetVersion
    else:
        if loader is None:
            loader = targetVersion >> 8
        if body is None:
            body = targetVersion & 0xFF

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

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

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

message(LOG_NORMAL,
        warningMesg + "\nUsing firmware version 0x%4.4x\n" % 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
