text: /***************************************************************************//**
   * @file     micro_printer.c
   * @brief    M480 series USBD driver Sample file
   * @version  2.0.0
   *
   * @copyright (C) 2016 Nuvoton Technology Corp. All rights reserved.
   ******************************************************************************/
  
  #include "NuMicro.h"
  #include "micro_printer.h"
  
  uint32_t volatile g_u32OutToggle = 0;
  
  /*--------------------------------------------------------------------------*/
  void USBD_IRQHandler(void)
  {
      uint32_t u32IntSts = USBD_GET_INT_FLAG();
      uint32_t u32State = USBD_GET_BUS_STATE();
  
  //------------------------------------------------------------------
      if (u32IntSts & USBD_INTSTS_FLDET)
      {
          // Floating detect
          USBD_CLR_INT_FLAG(USBD_INTSTS_FLDET);
  
          if (USBD_IS_ATTACHED())
          {
              /* USB Plug In */
              USBD_ENABLE_USB();
          }
          else
          {
              /* USB Un-plug */
              USBD_DISABLE_USB();
          }
      }
  
  //------------------------------------------------------------------
      if (u32IntSts & USBD_INTSTS_BUS)
      {
          /* Clear event flag */
          USBD_CLR_INT_FLAG(USBD_INTSTS_BUS);
  
          if (u32State & USBD_STATE_USBRST)
          {
              /* Bus reset */
              USBD_ENABLE_USB();
              USBD_SwReset();
              g_u32OutToggle = 0;
          }
          if (u32State & USBD_STATE_SUSPEND)
          {
              /* Enable USB but disable PHY */
              USBD_DISABLE_PHY();
          }
          if (u32State & USBD_STATE_RESUME)
          {
              /* Enable USB and enable PHY */
              USBD_ENABLE_USB();
          }
      }
  
  //------------------------------------------------------------------
      if(u32IntSts & USBD_INTSTS_WAKEUP)
      {
          /* Clear event flag */
          USBD_CLR_INT_FLAG(USBD_INTSTS_WAKEUP);
      }
  
      if (u32IntSts & USBD_INTSTS_USB)
      {
          // USB event
          if (u32IntSts & USBD_INTSTS_SETUP)
          {
              // Setup packet
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_SETUP);
  
              /* Clear the data IN/OUT ready flag of control end-points */
              USBD_STOP_TRANSACTION(EP0);
              USBD_STOP_TRANSACTION(EP1);
  
              USBD_ProcessSetupPacket();
          }
  
          // EP events
          if (u32IntSts & USBD_INTSTS_EP0)
          {
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_EP0);
  
              // control IN
              USBD_CtrlIn();
          }
  
          if (u32IntSts & USBD_INTSTS_EP1)
          {
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_EP1);
  
              // control OUT
              USBD_CtrlOut();
          }
  
          if (u32IntSts & USBD_INTSTS_EP2)
          {
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_EP2);
          }
  
          if (u32IntSts & USBD_INTSTS_EP3)
          {
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_EP3);
              if (g_u32OutToggle == (USBD->EPSTS0 & USBD_EPSTS0_EPSTS3_Msk))
              {
                  USBD_SET_PAYLOAD_LEN(EP3, EP3_MAX_PKT_SIZE);
              }
              else
              {
                  // Bulk Out -> receive printer data
                  PTR_Data_Receive();
                  g_u32OutToggle = USBD->EPSTS0 & USBD_EPSTS0_EPSTS3_Msk;
              }
          }
  
          if (u32IntSts & USBD_INTSTS_EP4)
          {
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_EP4);
          }
  
          if (u32IntSts & USBD_INTSTS_EP5)
          {
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_EP5);
          }
  
          if (u32IntSts & USBD_INTSTS_EP6)
          {
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_EP6);
          }
  
          if (u32IntSts & USBD_INTSTS_EP7)
          {
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_EP7);
          }
      }
  }
  
  /*--------------------------------------------------------------------------*/
  /**
    * @brief  USBD Endpoint Config.
    * @param  None.
    * @retval None.
    */
  void PTR_Init(void)
  {
      /* Init setup packet buffer */
      /* Buffer for setup packet -> [0 ~ 0x7] */
      USBD->STBUFSEG = SETUP_BUF_BASE;
  
      /*****************************************************/
      /* EP0 ==> control IN endpoint, address 0 */
      USBD_CONFIG_EP(EP0, USBD_CFG_CSTALL | USBD_CFG_EPMODE_IN | 0);
      /* Buffer range for EP0 */
      USBD_SET_EP_BUF_ADDR(EP0, EP0_BUF_BASE);
  
      /* EP1 ==> control OUT endpoint, address 0 */
      USBD_CONFIG_EP(EP1, USBD_CFG_CSTALL | USBD_CFG_EPMODE_OUT | 0);
      /* Buffer range for EP1 */
      USBD_SET_EP_BUF_ADDR(EP1, EP1_BUF_BASE);
  
      /*****************************************************/
      /* EP2 ==> Bulk IN endpoint, address 1 */
      USBD_CONFIG_EP(EP2, USBD_CFG_EPMODE_IN | BULK_IN_EP_NUM);
      /* Buffer offset for EP2 */
      USBD_SET_EP_BUF_ADDR(EP2, EP2_BUF_BASE);
  
      /* EP3 ==> Bulk Out endpoint, address 2 */
      USBD_CONFIG_EP(EP3, USBD_CFG_EPMODE_OUT | BULK_OUT_EP_NUM);
      /* Buffer offset for EP3 */
      USBD_SET_EP_BUF_ADDR(EP3, EP3_BUF_BASE);
      /* trigger receive OUT data */
      USBD_SET_PAYLOAD_LEN(EP3, EP3_MAX_PKT_SIZE);
  
      /* EP4 ==> Interrupt IN endpoint, address 3 */
      USBD_CONFIG_EP(EP4, USBD_CFG_EPMODE_IN | INT_IN_EP_NUM);
      /* Buffer offset for EP4 ->  */
      USBD_SET_EP_BUF_ADDR(EP4, EP4_BUF_BASE);
  }
  
  void PTR_ClassRequest(void)
  {
      uint8_t buf[8];
  
      USBD_GetSetupPacket(buf);
  
      if (buf[0] & 0x80)   /* request data transfer direction */
      {
          // Device to host
          switch (buf[1])
          {
          case GET_PORT_STATUS:
          {
              /* Data stage */
              USBD_SET_DATA1(EP0);
              USBD_SET_PAYLOAD_LEN(EP0, 0);
              /* Status stage */
              USBD_PrepareCtrlOut(0,0);
              break;
          }
          default:
          {
              /* Setup error, stall the device */
              USBD_SetStall(0);
              break;
          }
          }
      }
      else
      {
          // Host to device
      }
  }
  
  /* Receive printer command and data from host */
  void PTR_Data_Receive(void)
  {
      uint8_t *pu8Buf = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP3));
      uint32_t u32Size = USBD_GET_PAYLOAD_LEN(EP3);
  
      /* trigger next OUT data */
      USBD_SET_PAYLOAD_LEN(EP3, EP3_MAX_PKT_SIZE);
  }
  