#
# Replacement for modckcc.c and complexity of the bootloader.
#
# REMINDER: you must recompile coldcard-mpy if you change this file!
#
import ustruct
#from ubinascii import hexlify as b2a_hex
#from ubinascii import unhexlify as a2b_hex
#import utime as time

from uerrno import *
ERANGE = const(34)

rng_fd = open('/dev/urandom', 'rb')

# Emulate the red/green LED
import sys
global genuine_led
try:
    led_pipe = open(int(sys.argv[3]), 'wb')
    led_pipe.write(b'\x01')
except:
    pass
genuine_led = True

if 1:
    # remove pauses that lengthen test case times...
    async def no_drama(msg, seconds):
        print("Pause (%ds): %s" % (seconds, msg))
    import ux
    ux.ux_dramatic_pause = no_drama
        
# HACK: reduce size of heap in Unix simulator to be more similar to 
# actual hardware, so we can enjoy those out-of-memory errors too!
# target, post boot: 25376 bytes
# - not entirely fair because our pointers may be 64bit
# - heap for unix port defined (in unix/main.c) to be 1M * ptr size bytes
# - arm version seems to be able to handle much lower heap size??
# - unix is not freezing the main code, so those bytecodes take major memory
#balloon = bytearray(700*1024)


# patch in monitoring of text on screen
if 1:
    import sim_display


###  remainder should be module functions from real ckcc  ###

def rng():
    # return 30 bit random number
    return ustruct.unpack('I', rng_fd.read(4))[0] >> 2

def rng_bytes(buf):
    # Fill a buffer with random bits; caller must provide sized buffer
    actual = rng_fd.readinto(buf)
    assert actual == len(buf)

def pin_prefix(pin, buf_out):
    # return 4 bytes (32-bit number)
    # real thing is nothing like this!
    from uhashlib import sha256

    buf_out[0:4] = sha256(pin).digest()[0:4]

    return 0

def gate(method, buf_io, arg2):
    # the "callgate" into the bootloader

    # - only spuratically implemented (say it like in _Clueless_)
    # - none of the error checking is repeated here
    # - not trying too hard to fake the hardware-related features

    if method == 0:
        # version string
        hc = b'1.0.0 time=20180220.092345 git=master@f8d1758'
        buf_io[0:len(hc)] = hc
        return len(hc)

    if method == 16:
        if len(buf_io) < 8: return ERANGE
        return pin_prefix(buf_io[0:arg2], buf_io)

    if method == 18:
        from sim_secel import pin_stuff
        return pin_stuff(arg2, buf_io)

    if method == 4:
        # control the green/red light
        global genuine_led
        if arg2 == 1:
            # clear it
            genuine_led = False
            led_pipe.write(b'\x00')
        return 1 if genuine_led else 0

    if method == 5:
        # are we a brick? No.
        return 0

    if method == 19:
        # bag number
        if arg2 == 0:
            buf_io[0:32] = b'CSIM0000' + b'\0'*(32-8)
        if arg2 == 1:
            # not supported: write
            return buf_io

    if method == 21:
        # high water mark
        if arg2 == 0:
            buf_io[0:8] = b'\x18\x07\x11\x19S\x08\x00\x00'
        return 0

    return ENOENT

def oneway(method, arg2):

    print("\n\nNOTE: One-way callgate into bootloader: method=%d arg2=%d\n\n" % (method, arg2))
    raise SystemExit

def is_simulator():
    return True


def get_sim_root_dirs():
    # return a single path and list of files to pretend to find there
    import ffilib, os
    libc = ffilib.libc()

    b = bytearray(500)
    cwd = libc.func("s", "getcwd", "pi")(b, len(b))
    assert cwd

    return cwd, cwd+'/MicroSD'

def presume_green():
    global genuine_led
    assert genuine_led == True

def breakpoint():
    raise SystemExit

def watchpoint():
    pass

def vcp_enabled(_):
    return True

# EOF
