#include "core/config.h"

#if CONFIG_AUTOMAT_MODE_USB_POWERBANK && CONFIG_AUTOMAT_MODE
#include "usbapp/usb_application_enumspy.h"
#include "usb/usb_bridge.h"
#include "usb/usb_config.h"
#include "usbd_vendor.h"
#include "core/csect.h"

#if CONFIG_AUTOMAT_MODE_USB_POWERBANK_ENUMTIMEOUT > 0
#define ENUMERATE_TIMEOUT  CONFIG_AUTOMAT_MODE_USB_POWERBANK_ENUMTIMEOUT
#else
#define ENUMERATE_TIMEOUT  5000
#endif

static uint32_t nEnumerateTimeout = 0; // Enumerate timeout counter, 0 = disabled.
static bool bUsbEnumerated = false; 
static void USBApplicationEnumSpy_startEnumerateTimeout();
static void USBApplicationEnumSpy_stopEnumerateTimeout();
static void USBApplicationEnumSpy_Tick1ms();
static bool USBApplicationEnumSpy_checkEnumerateTimeout();

static int8_t fEnumSpyInit();
static int8_t fEnumSpyDeInit();
static void   fEnumSpyReset();
static bool   fEnumSpySetup( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success );
static size_t fEnumSpyControlRx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining );
static size_t fEnumSpyControlTx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining );

const sUSBAppEntry_Control_t usbapplication_ACM_planarproto_enumspy = {

     .fUsbInit     = fEnumSpyInit,
     .fUsbDeInit   = fEnumSpyDeInit,
     .fUsbSetup    = fEnumSpySetup,
     .fUsbCtlEpRx  = fEnumSpyControlRx,
     .fUsbCtlEpTx  = fEnumSpyControlTx,
     .fResetEvent  = fEnumSpyReset,
};

const sUsbApplicationEnumSpyHandle_t UsbApplicationEnumSpyHandle = {

     .startEnumerateTimeout = USBApplicationEnumSpy_startEnumerateTimeout,
     .stopEnumerateTimeout = USBApplicationEnumSpy_stopEnumerateTimeout,

     .checkEnumerateTimeout = USBApplicationEnumSpy_checkEnumerateTimeout,
     .timerTickEventIrq1ms = USBApplicationEnumSpy_Tick1ms
};

static int8_t fEnumSpyInit()
{
    bUsbEnumerated = false;
    nEnumerateTimeout = 0; // reset and disable counter

    return 0;
}

static int8_t fEnumSpyDeInit()
{
    bUsbEnumerated = false;
    nEnumerateTimeout = 0; // reset and disable counter

    return 0;
}  

static void fEnumSpyReset()
{
    // USB Standard: "9.1.2 Bus Enumeration"
    // "The host then issues a port enable and reset command to that port."
    // "The hub performs the required reset processing for that port (see Section 11.5.1.5). When the reset
    //  signal is released, the port has been enabled. The USB device is now in the Default state and can draw
    //  no more than 100 mA from VBUS. All of its registers and state have been reset and it answers to the
    //  default address."

    nEnumerateTimeout = 0;  // reset and disable counter
    bUsbEnumerated = true;  // Reset signal received: USB has been enumerated
} 

static bool fEnumSpySetup( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success )
{       
    return false;
}

static size_t fEnumSpyControlRx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining )
{
    return 0;
}
  
static size_t fEnumSpyControlTx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining )
{
    return 0;
}

// Reset and restart the Enumerate timeout
static void USBApplicationEnumSpy_startEnumerateTimeout()
{
    __DI__ 
        nEnumerateTimeout = 1;  // 0 - disabled, 1 - initial value
    __EI__    
}

// Stop Enumerate timeout
static void USBApplicationEnumSpy_stopEnumerateTimeout()
{
    __DI__ 
        nEnumerateTimeout = 0;  // 0 - disabled, 1 - initial value
    __EI__    
}

static void USBApplicationEnumSpy_Tick1ms()
{
    if( (nEnumerateTimeout > 0) && (nEnumerateTimeout <= ENUMERATE_TIMEOUT) )
    {
        nEnumerateTimeout ++;
    }
}

// USBApplicationEnumSpy_checkEnumerateTimeout
// Check if the host had not enumerate the device for a long time (ENUMERATE_TIMEOUT)
// Returns: true in case the device had not been enumerated for a ENUMERATE_TIMEOUT ms
static bool USBApplicationEnumSpy_checkEnumerateTimeout()
{
    bool timeout = false;
    bool enumerated = false;
    __DI__
    // The timeout is considered as expired when the counter exceedes the ENUMERATE_TIMEOUT value.
    timeout = ( nEnumerateTimeout > ENUMERATE_TIMEOUT );
    enumerated = bUsbEnumerated;
    __EI__

    return (timeout && !enumerated);
}
#endif 