#! /usr/bin/python
#
# Blink all the vitesse leds once

import os
import sys
import sets
import time
import getopt
import isi.hw.vitutil as vitutil
import isi.app.lib.procs as procs

## There are 8 leds, but the 4 activity LEDs have four different
## drive signals each.
##  LINK : P1_12-15
##  ACT  : P0_16-31 (in sets of four adjacent)
## So do this:
## turn on P1_12
## flash each P0_16, P0_20, P0_24, P0_28
## turn off P1_12 and turn on P1_13
## flash each P0_17, P0_21, P0_25, P0_29
## ... through P15
SYS_CNTL_BASE = 0xBFAF0000L

def ledp0(pin):
    return (SYS_CNTL_BASE + 0x880 + (4 * pin))

def ledp1(pin):
    return (SYS_CNTL_BASE + 0x900 + (4 * pin))

## singleport is hard-coded to only test port 3,
## for de-pop'ed expander cards
## in future, we could expand this code to test specific given port(s)

_all_patterns = [
    ( [ ledp1(12), ledp0(16) ], "link: X---  activity: X---" ), 
    ( [ ledp1(12), ledp0(20) ], "link: X---  activity: -X--" ), 
    ( [ ledp1(12), ledp0(24) ], "link: X---  activity: --X-" ), 
    ( [ ledp1(12), ledp0(28) ], "link: X---  activity: ---X" ), 
    ( [ ledp1(13), ledp0(17) ], "link: -X--  activity: X---" ), 
    ( [ ledp1(13), ledp0(21) ], "link: -X--  activity: -X--" ), 
    ( [ ledp1(13), ledp0(25) ], "link: -X--  activity: --X-" ), 
    ( [ ledp1(13), ledp0(29) ], "link: -X--  activity: ---X" ), 
    ( [ ledp1(14), ledp0(18) ], "link: --X-  activity: X---" ), 
    ( [ ledp1(14), ledp0(22) ], "link: --X-  activity: -X--" ), 
    ( [ ledp1(14), ledp0(26) ], "link: --X-  activity: --X-" ), 
    ( [ ledp1(14), ledp0(30) ], "link: --X-  activity: ---X" ), 
    ( [ ledp1(15), ledp0(19) ], "link: ---X  activity: X---" ), 
    ( [ ledp1(15), ledp0(23) ], "link: ---X  activity: -X--" ), 
    ( [ ledp1(15), ledp0(27) ], "link: ---X  activity: --X-" ), 
    ( [ ledp1(15), ledp0(31) ], "link: ---X  activity: ---X" ),
    ]

_port3_patterns = [
    ( [                      ], "link: ----  activity: ----" ),
    ( [            ledp0(24) ], "link: ----  activity: --X-" ),
    ( [                      ], "link: ----  activity: ----" ),
    ( [            ledp0(25) ], "link: ----  activity: --X-" ),
    ( [                      ], "link: ----  activity: ----" ),
    ( [            ledp0(26) ], "link: ----  activity: --X-" ),
    ( [                      ], "link: ----  activity: ----" ),
    ( [            ledp0(27) ], "link: ----  activity: --X-" ),
    ( [ ledp1(14)            ], "link: --X-  activity: ----" ),
    ( [ ledp1(14), ledp0(24) ], "link: --X-  activity: --X-" ),
    ( [ ledp1(14)            ], "link: --X-  activity: ----" ),
    ( [ ledp1(14), ledp0(25) ], "link: --X-  activity: --X-" ),
    ( [ ledp1(14)            ], "link: --X-  activity: ----" ),
    ( [ ledp1(14), ledp0(26) ], "link: --X-  activity: --X-" ),
    ( [ ledp1(14)            ], "link: --X-  activity: ----" ),
    ( [ ledp1(14), ledp0(27) ], "link: --X-  activity: --X-" ),
    ]

_patterns, _ledaddrs = None, None

def init_patterns(singleport = False):
    global _patterns, _ledaddrs
    _patterns = singleport and _port3_patterns or _all_patterns
    #create a unique list of all led addresses
    _ledaddrs = sets.Set([])
    for (pat, prt) in _patterns:
        _ledaddrs.update([led for led in pat])

def led_enable(unit, addr, enable):
    return vitutil.write(unit, addr, int(not enable) << 1)

def pause():
    time.sleep(1)

## send an arbitrary isi_vitutil command
def isivitutil_misc(unit, args):
    cmd = "%s %s %s" % (vitutil._VITUTIL, args, unit)
    (status, output) = procs.get_cmd_output(cmd)
    if status != 0:
        raise RuntimeError, "command failed (%d): %s" % (status, cmd)
    return output

def init_vitesse(unit):
    # set global led control into debug mode
    isivitutil_misc(unit, "-gLD")
    # turn off all leds
    for addr in _ledaddrs:
        led_enable(unit, addr, 0)
    return

def drive_leds(unit):
    lastlit = []
    for (pat, prt) in _patterns:
        print "Lighting   %s" % prt
        # turn off any leds from the last pattern that are not repeated
        for led in filter(lambda x:x not in pat, lastlit):
            led_enable(unit, led, 0)
        # turn on all the leds in this pattern
        for led in filter(lambda x:x not in lastlit, pat):
            led_enable(unit, led, 1)
        # wait a bit
        pause()
        # remember what's lit for next time
        lastlit = pat
    # turn off all leds for cleanliness
    for led in lastlit:
        led_enable(unit, led, 0)


def cleanup_vitesse(unit):
    # set global led control into firmware-driven mode
    isivitutil_misc(unit, "-gLF")
    print " XXX: activity leds are not properly reconfigured"
    return

def usage(argv):
    print >>sys.stderr, "usage: %s [-s] unit" % os.path.basename(argv[0])
    return 2

def main(argv = None):
    singleport = False
    if argv is None:
        argv = sys.argv[1:]

    try:
        opts, argv = getopt.getopt(argv, "sh", ['singleport'])

    except getopt.error, err:
        return usage(sys.argv)

    for opt, arg in opts:
        if opt in ['-h']:
            return usage(sys.argv)
        elif opt in ['-s', '--singleport']:
            singleport = True
        # Future: could specify with -p# a given port, 1-4

    if len(argv) != 1:
        return usage(sys.argv)
    unit = argv[0]

    init_patterns(singleport)
    print "Clearing all LEDs on expander %s" % unit
    init_vitesse(unit)
    #print "Lighting LEDs in turn"
    drive_leds(unit)
    print "Returning expander %s to normal operation" % unit
    cleanup_vitesse(unit)
    return 0

if __name__ == "__main__":
    sys.exit(main())
