// -----------------------------------------------------------------------------
// USB Library "usblib"
// Target:  for lpc17xx
// Author:  Sychov A.
// Date:    12/10/2018
// Version: 1.0
// -----------------------------------------------------------------------------
// File:    USB-hooks header
// Version: 1.0
// -----------------------------------------------------------------------------

#ifndef USB_HOOKS_H
#define USB_HOOKS_H
    
    #include "usb/usb_transfers.h"
    #include "usb/usb_spec.h"

    // USB-Callbacks (Hooks)

    // fUsbEpIrqHandler_t:
    // Callback-type function is called on each interrupt of any endpoint.    
    // @EndpointStatus - 32-bit word of flags, where each bit represents
    // each physical endpoint.
    // Bit 0 - EP0RX
    // Bit 1 - EP0TX
    // Bit 2 - EP1RX
    // Bit 3 - EP1TX, and etc.
    // The value 1 in the bit means an interrupt occurred on apropriate endpoint.
    // The notification type function code must clear the interrupt in hardware itself.
    typedef void (* fUsbEpIrqHandler_t )( uint32_t EndpointStatus );

    // fUsbBusReset_t:
    // The notification type function is called on USB-bus reset event
    typedef void (* fUsbBusReset_t)(); 

    // fUsbSetIface_t:
    // The notification type function is called to inform the application of interface activating
    // The function must return 'true' if application able to activate specified interface, and 'false' otherwise.
    // In case of 'false', the USB-request causes request error.
    // The callee should take account the bAlternateSetting of specified @iface, active bAlternateSetting value can be requested by @fUsbGetIface_t
    typedef bool (* fUsbSetIface_t)( uint8_t cfgidx, uint8_t ifidx, const sUSBInterfaceDescriptor_t * ifdesc );    

    // fUsbClrIface_t:
    // The notification type function is called to inform the application of interface de-activating
    // The callee should take account the bAlternateSetting of specified @iface, active bAlternateSetting value can be requested by @fUsbGetIface_t
    typedef void (* fUsbClrIface_t)( uint8_t cfgidx, uint8_t ifidx, const sUSBInterfaceDescriptor_t * ifdesc );

    // fUsbGetIface_t:
    // The request-type function is called to query the interface active alternate setting
    // If this callback is not specified, the alternate setting = 0 will be reported in GET_INTERFACE request
    typedef bool (* fUsbGetIface_t)( uint8_t cfgidx, uint8_t ifidx, uint8_t * pAltSetting );

    // fUsbSuspendEvent_t:
    // The notification type function is called on USB suspending/resuming event
    // @suspend - suspend state, true - USB-Controller is suspended, false - USB-Controller is resumed
    typedef void (* fUsbSuspendEvent_t)( bool suspend );

    // The data arrival event
    // This hook is called to process the portion of data by application
    // @pSetup - the setup packet caused the callback call
    // @rx - the transfer to read data from
    // @idx - the data index, equals to the number of bytes already sent in request
    // @bytesRemaining - the whole amount of bytes needed to receive more.
    // For control transfers (EP0) this number depends on the @wLength.
    // Note: @tx refers to the Transfer-object with small buffer with the size 
    // less than @bytesRemaining. The user must read the bytes from transfer @tx
    // and return the read bytes count. This value is provided by usb_read_transfer().
    // The @bytesRemaining is amount of remaining bytes to receive incliding the bytes
    // queued into @rx transfer.
    typedef size_t (* fUsbCtlEpRx_t) ( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining );

    // The data requesting event
    // This hook is called to provide the portion of data for the usb-core
    // @pSetup - the setup packet caused the callback call
    // @tx - the transfer to write data into
    // @idx - the data index, equals to the number of bytes already received in request
    // @bytesRemaining - the whole amount of bytes needed to send more.
    // For control transfers (EP0) this number depends on the @wLength.
    // Note: @rx refers to the Transfer-object with small buffer with the size 
    // less than @bytesRemaining. The user must write not more than @bytesRemaining
    // in each callback call until the Transfer-buffer is full. Since the transfer
    // buffer fulls, the usb_write_transfer() returns 0.
    // The function must return the written bytes count into the transfer @tx
    // This value is provided by usb_write_transfer().    
    typedef size_t (* fUsbCtlEpTx_t) ( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining );

    // fUsbSetupRx_t:
    // The callback type function is called on each received SETUP packet in Control Endpoint.
    // The function is called twice: firstly before the packet processing in the kernel,
    // secondly afther the processing.
    // In case the callback function code processes the SETUP packet itself and wants to
    // intercept it and make the packet aren't processed in the kernel, the function must
    // return 'false' at first stage. Otherwise, in case the function returns 'true', it 
    // should not process the packet, but can use the event as notification.
    // The second stage does not appear in case the first stage function returns 'false'.
    // Otherwise, the second stage function is called after the packet is processed in 
    // kernel. It does not matter what value the function returns in this stage.
    // @bFirstStage - stage flag. For first stage - 'true', for second - 'false'
    // @success - the indicator whether the setup packet is processed correcly at second stage. 
    // For first stage @success is always false.
    typedef bool (* fUsbSetupRx_t) ( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success );
   
    typedef bool (* fUsbDataRx_t)(   uint8_t bEpLogAddress,
                                     sUSBTransfer_t * rx );

    typedef bool (* fUsbDataTx_t)(   uint8_t bEpLogAddress,
                                     sUSBTransfer_t * tx );

    // fUsbDataErr_t
    // Notify-type callback is called when a USB error occurred
    // @bConfValue - active configuration value
    // @bIntNumber - active interface number
    // @bEpLogAddress - active endpoint address
    // @error - error mask, see USB Error flags below.
    // To proceed, the function must return true.
    // Otherwise, if function returns false, the library may interrupt current operation
    typedef bool (* fUsbDataErr_t)(  uint8_t bEpLogAddress,
                                               uint32_t error );

    typedef int8_t (* fUsbInit_t )(void);
    typedef int8_t (* fUsbDeInit_t )(void);

    typedef bool   (* fUsbDataInit_t )( uint8_t epnum );
    typedef void   (* fUsbDataDeInit_t )( uint8_t epnum );
                   
    // Enumeration-Level hooks:
    typedef struct
    {
        fUsbSetupRx_t       fUsbSetup;        // optional
        fUsbCtlEpRx_t       fUsbCtlEpRx;      // optional
        fUsbCtlEpTx_t       fUsbCtlEpTx;      // optional
        fUsbEpIrqHandler_t  fIrqHandler;      // optional        
        fUsbBusReset_t      fResetEvent;      // optional
        fUsbSuspendEvent_t  fSuspendEvent;    // optional
        fUsbSetIface_t      fSetIface;        // optional SetInterface/SetConfiguration request handler
        fUsbClrIface_t      fClrIface;        // optional SetInterface/SetConfiguration request handler
        fUsbGetIface_t      fGetIface;        // optional (GET_INTERFACE request)
        fUsbDataRx_t        fDataRxHandler;   // optional ( endpoints I/O )
        fUsbDataTx_t        fDataTxHandler;   // optional ( endpoints I/O )
        fUsbDataErr_t       fDataErrHandler;  // optional ( endpoints I/O )
    }
    sUSBHooks_t;

    typedef struct
    {
       fUsbInit_t          fUsbInit;
       fUsbDeInit_t        fUsbDeInit;
       fUsbSetupRx_t       fUsbSetup;  
       fUsbCtlEpRx_t       fUsbCtlEpRx;
       fUsbCtlEpTx_t       fUsbCtlEpTx;
       fUsbBusReset_t      fResetEvent; 
    }
    sUSBAppEntry_Control_t;

    typedef struct
    {
       fUsbDataInit_t      fDataInitHandler;   // optional
       fUsbDataRx_t        fDataRxHandler;     // optional
       fUsbDataTx_t        fDataTxHandler;     // optional
       fUsbDataErr_t       fDataErrHandler;    // optional
       fUsbDataDeInit_t    fDataDeInitHandler; // optional
    }
    sUSBAppEntry_Data_t;

    // USB Error flags for @fUsbDataErr_t:
    #define USB_ERR_NOERR       0 
    #define USB_ERR_RX          (1<<0)   // common receive error       
    #define USB_ERR_TX          (1<<1)   // common transmit error       
    #define USB_ERR_TX_NODATA   (1<<2)   // no data available to transmit
    #define USB_ERR_STALL       (1<<3)   // endpoint is stalled
#endif    