#ifndef _USB_DEVICE_H_
#define _USB_DEVICE_H_
//----------------------------------------------------------------------------
///
/// \brief  USB device
///
///         See implementation files for further information.
//
/// \date   2018025
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


//---Includes-----------------------------------------------------------------


//---Own------------------------------

#include <biwak/usb.hpp>
#include <biwak/usb_defines.h>
#include <biwak/usb_descriptor.h>
#include <sys/types.h>
//#include <machine/endian.h>
//#include <stm/stm32_usb.h>


//---Defines------------------------------------------------------------------


/*  EP0 State */
#define USBD_EP0_IDLE                                     0
#define USBD_EP0_SETUP                                    1
#define USBD_EP0_DATA_IN                                  2
#define USBD_EP0_DATA_OUT                                 3
#define USBD_EP0_STATUS_IN                                4
#define USBD_EP0_STATUS_OUT                               5
#define USBD_EP0_STALL                                    6

#define USBD_EP_TYPE_CTRL                                 0
#define USBD_EP_TYPE_ISOC                                 1
#define USBD_EP_TYPE_BULK                                 2
#define USBD_EP_TYPE_INTR                                 3

//#define USB_HANDLE_TYPE    PCD_HandleTypeDef

//---Declaration--------------------------------------------------------------

class CUsbRequest;
class CUsbClass;
class CUsb;

class CUsbDevice :public IUsbCallbacks
{
    private:

    public:
      CUsb &usb;
      CUsbDescriptor descriptor;

      int ep0_state;
      unsigned int ep0_data_len;
      USBD_EndpointTypeDef    ep_in[15];
      USBD_EndpointTypeDef    ep_out[15];
      int dev_state;
      USBD_SpeedTypeDef dev_speed;
      int dev_default_config;
      int dev_config;
      int dev_config_status;
      int dev_remote_wakeup;
      int dev_address;
      int dev_test_mode;
      CUsbClass *pClass;
      bool m_active=false;

      CUsbDevice(CUsb &_usb);

      virtual USBD_StatusTypeDef dataOutStage(uint8_t epnum, uint8_t *pdata, int len) override;
      virtual USBD_StatusTypeDef dataInStage(uint8_t epnum, uint8_t *pdata, int len) override;
      virtual USBD_StatusTypeDef setupStage(uint8_t *pdata) override;
      virtual USBD_StatusTypeDef SOF() override;
      virtual USBD_StatusTypeDef reset() override;
      virtual USBD_StatusTypeDef suspend() override;
      virtual USBD_StatusTypeDef resume() override;
      virtual USBD_StatusTypeDef ISOOUTIncomplete() override;
      virtual USBD_StatusTypeDef ISOINIncomplete() override;
      virtual USBD_StatusTypeDef connect() override;
      virtual USBD_StatusTypeDef disconnect() override;

      void getDescriptor(CUsbRequest &req);
      void setAddress( CUsbRequest &req);
      void setConfig( CUsbRequest &req);
      void getConfig( CUsbRequest &req);
      void getStatus( CUsbRequest &req);
      void setFeature( CUsbRequest &req);
      void clrFeature( CUsbRequest &req);
      void ctlError( CUsbRequest &req);
      void ctlSendStatus( );

      int stdEPReq (CUsbRequest &req);
      int  ctlSendData(uint8_t *pbuf, uint16_t len);
      void setSpeed( USBD_SpeedTypeDef speed );
      USBD_StatusTypeDef ctlContinueSendData (uint8_t *pbuf, uint16_t len);
      USBD_StatusTypeDef ctlReceiveStatus();
      USBD_StatusTypeDef prepareReceive(
                                                uint8_t ep_addr,
                                                uint8_t *pbuf,
                                                uint16_t size);
      USBD_StatusTypeDef runTestMode ();
      //virtual USBD_StatusTypeDef dataOutStage( uint8_t epnum, uint8_t *pdata) override;
      USBD_StatusTypeDef ctlContinueRx (uint8_t *pbuf, uint16_t len);

      USBD_StatusTypeDef setClassConfig(uint8_t cfgidx);
      USBD_StatusTypeDef registerClass(CUsbClass *_pClass);
      bool isActive()
      {
         return( m_active );
      }
};

#define __utohs(a) (a)

class CUsbRequest
{
   typedef struct __attribute__ ( ( packed ) )
   {
      uint8_t   bmRequest;
      uint8_t   bRequest;
      uint16_t  wValue;
      uint16_t  wIndex;
      uint16_t  wLength;
   }R;
   public:
      int mRequest;
      int request;
      int value;
      int index;
      unsigned int length;
      CUsbRequest(uint8_t *data)
      {
         R *s=(R *)data;
         mRequest=s->bmRequest;
         request=s->bRequest;
         value=__utohs(s->wValue);
         index=__utohs(s->wIndex);
         length=__utohs(s->wLength);
      }
};


//---fin----------------------------------------------------------------------
#endif // ? ! _USB_H_
