# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
#
# callgate.py - thin wrapper around modckcc and the bootloader and its services.
#
import ckcc

def get_bl_version():
    # version string and related details
    # something like:   ('1.0.0', [('time', '20180220.092345'), ('git', 'master@f8d1758')])
    rv = bytearray(64)
    ln = ckcc.gate(0, rv, 0)
    ver, *args = str(rv[0:ln], 'utf8').split(' ')
    return ver, [tuple(i.split('=', 1)) for i in args]
    
def get_bl_checksum(salt=0):
    # salted checksum over code
    rv = bytearray(32)
    ckcc.gate(1, rv, salt)
    return rv
    
def enter_dfu(msg=0):
    # enter DFU while showing a message
    #   0 = normal DFU
    #   1 = downgrade attack detected
    #   2 = blankish
    #   3 = i am bricked
    #
    ckcc.oneway(2, msg)

def show_logout(dont_clear=0):
    # wipe memory and die, shows standard message
    # dont_clear=1 => don't clear OLED
    # 2=> restart system after wipe
    ckcc.oneway(3, dont_clear)

def get_genuine():
    return ckcc.gate(4, None, 0)
def clear_genuine():
    ckcc.gate(4, None, 1)
def set_genuine():
    # does checksum over firmware, and might set green
    return ckcc.gate(4, None, 3)

def get_is_bricked():
    # see if we are a brick?
    return ckcc.gate(5, None, 0) != 0

def set_bag_number(s):
    assert 3 <= len(s) < 32
    arg = bytearray(32)     # zero pad
    arg[0:len(s)] = s
    return ckcc.gate(19, arg, 1)

def set_rdp_level(n):
    # complex hardware rules around these changes.
    assert n in {0,1,2}
    return ckcc.gate(19, None, 100+n)

def get_factory_mode():
    # are we in normal RDP=2 mode (else in factory setup time)
    arg = bytearray(1)
    ckcc.gate(19, arg, 2)
    return (arg[0] != 2)

def get_bag_number():
    arg = bytearray(32)
    ckcc.gate(19, arg, 0)

    if arg[0] == 0xff:
        return None

    rv = bytes(arg)
    return str(rv[0:rv.index(b'\0')], 'ascii')

def get_highwater():
    arg = bytearray(8)
    ckcc.gate(21, arg, 0)

    return bytes(arg)
    
def set_highwater(ts):
    arg = bytearray(ts)
    return ckcc.gate(21, arg, 2)

def has_608():
    return ckcc.gate(6, None, 0) == 0

def has_608b():
    config = bytearray(128)
    ckcc.gate(20, config, 0)
    return (config[7] >= 0x3)

def fast_wipe(silent=True):
    # mk4: wipe seed, also reboots immediately: can stop and show a screen or not
    ckcc.oneway(23, 0xBeef if silent else 0xdead);

def fast_brick():
    # mk4: brick and reboot. Near instant. Shows brick screen.
    ckcc.oneway(24, 0xDead);

def mcu_key_usage():
    # mk4: avail/consumed/total stats, one will be in use typically
    from ustruct import unpack
    arg = bytearray(3*4)
    ckcc.gate(25, arg, 0);
    return unpack('3I', arg)

def read_rng(source=2):
    # return random bytes from a secure source
    # - first byte is # of valid random bytes
    arg = bytearray(33)
    rv = ckcc.gate(26, arg, source);
    assert not rv
    return arg[1:1+arg[0]]

def get_se_parts():
    # mk4: report part names
    # - gets a nul-terminated string, w/ newline between them
    arg = bytearray(80)
    rv = ckcc.gate(27, arg, 0);
    if rv:
        # happens w/ obsolete versions of bootrom that never left Toronto
        return ['SE1', 'SE2']
    ln = bytes(arg).find(b'\0')
    return arg[0:ln].decode().split('\n')
    

# EOF
