package com.example.myapplication.util;

import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;

/* This class only contains constants */
public final class UsbDfuConstants {

    public static final int DFU_INTERFACE_CLASS = 0xFE;
    public static final int DFU_INTERFACE_SUBCLASS = 0x01;
    public static final int DFU_INTERFACE_PROTOCOL_RUNTIME_MODE = 0x01;
    public static final int DFU_INTERFACE_PROTOCOL_DFU_MODE = 0x02;

    public static final int DFU_DETACH_bmRequestType = 0x21;
    public static final int DFU_DETACH_bRequest = 0;
    public static final int DFU_DETACH_wValue = 0; // wTimeout == 0 as the device resets by itself

    public static final int DFU_DNLOAD_bmRequestType = 0x21;
    public static final int DFU_DNLOAD_bRequest = 1;

    public static final int DFU_UPLOAD_bRequest = 2; // not used in this application
    public static final int DFU_CLRSTATUS_bRequest = 4;
    public static final int DFU_ABORT_bRequest = 6;

    public static final int DFU_GETSTATUS_bmRequestType = 0xA1;
    public static final int DFU_GETSTATUS_bRequest = 3;
    public static final int DFU_GETSTATUS_wValue = 0;
    public static final int DFU_GETSTATUS_wLength = 6;

    public static final int DFU_GETSTATE_bmRequestType = 0xA1;
    public static final int DFU_GETSTATE_bRequest = 5;
    public static final int DFU_GETSTATE_wValue= 0;
    public static final int DFU_GETSTATE_wLength = 1;

    /* Timeout for USB transfers. Not sure if important. */
    public static final int USB_TRANSFER_TIMEOUT = 500; // ms

    /* USB Device Firmware Upgrade Specification, Revision 1.1, Section 6.1.2 */
    public static final int DFU_STATE_appIDLE = 0;
    public static final int DFU_STATE_appDETACH = 1;
    public static final int DFU_STATE_dfuIDLE = 2;
    public static final int DFU_STATE_dfuDNLOAD_SYNC = 3;
    public static final int DFU_STATE_dfuDNBUSY = 4;
    public static final int DFU_STATE_dfuDNLOAD_IDLE = 5;
    public static final int DFU_STATE_dfuMANIFEST_SYNC = 6;
    public static final int DFU_STATE_dfuMANIFEST = 7;
    public static final int DFU_STATE_dfuMANIFEST_WAIT_RESET = 8;
    public static final int DFU_STATE_dfuUPLOAD_IDLE = 9;
    public static final int DFU_STATE_dfuERROR = 10;

    /* USB Device Firmware Upgrade Specification, Revision 1.1, Section 6.1.2 */
    public static final int DFU_STATUS_OK = 0x00;
    public static final int DFU_STATUS_errTARGET = 0x01;
    public static final int DFU_STATUS_errFILE = 0x02;
    public static final int DFU_STATUS_errWRITE = 0x03;
    public static final int DFU_STATUS_errERASE = 0x04;
    public static final int DFU_STATUS_errCHECK_ERASED = 0x05;
    public static final int DFU_STATUS_errPROF = 0x06;
    public static final int DFU_STATUS_errVERIFY = 0x07;
    public static final int DFU_STATUS_errADDRESS = 0x08;
    public static final int DFU_STATUS_errNOTDONE = 0x09;
    public static final int DFU_STATUS_errFIRMWARE = 0x0A;
    public static final int DFU_STATUS_errVENDOR = 0x0B;
    public static final int DFU_STATUS_errUSBR = 0x0C;
    public static final int DFU_STATUS_errPOR = 0x0D;
    public static final int DFU_STATUS_errUNKNOWN = 0x0E;
    public static final int DFU_STATUS_errSTALLEDPKT = 0x0F;

    public static int findDfuRuntimeModeInterface(UsbDevice device)
    {
        for (int i = 0; i < device.getInterfaceCount(); i++)
        {
            if (isDfuRuntimeModeInterface(device.getInterface(i)))
            {
                return i;
            }
        }
        return -1;
    }

    public static boolean isDfuRuntimeModeInterface(UsbInterface iface)
    {
        return  iface.getInterfaceClass() == UsbDfuConstants.DFU_INTERFACE_CLASS &&                     // Application Specific Class Code
                iface.getInterfaceSubclass() == UsbDfuConstants.DFU_INTERFACE_SUBCLASS &&               // Device Firmware Upgrade Code
                iface.getInterfaceProtocol() == UsbDfuConstants.DFU_INTERFACE_PROTOCOL_RUNTIME_MODE;     // Runtime Protocol
    }

    public static int findDfuModeInterface(UsbDevice device)
    {
        for (int i = 0; i < device.getInterfaceCount(); i++)
        {
            if (isDfuModeInterface(device.getInterface(i)))
            {
                return i;
            }
        }
        return -1;
    }

    public static boolean isDfuModeInterface(UsbInterface iface)
    {
        return  iface.getInterfaceClass() == UsbDfuConstants.DFU_INTERFACE_CLASS &&         // Application Specific Class Code
                iface.getInterfaceSubclass() == UsbDfuConstants.DFU_INTERFACE_SUBCLASS &&   // Device Firmware Upgrade Code
                iface.getInterfaceProtocol() == UsbDfuConstants.DFU_INTERFACE_PROTOCOL_DFU_MODE;     // DFU Protocol
    }
}
