text: /**************************************************************************//**
   * @file     hid_mouse.c
   * @version  V3.00
   * @brief    USBD HID mouse sample file.
   *
   * @copyright SPDX-License-Identifier: Apache-2.0
   * @copyright Copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
   ******************************************************************************/
  
  /*!<Includes */
  #include <string.h>
  #include "NuMicro.h"
  #include "hid_mouse.h"
  
  signed char mouse_table[] = { -16, -16, -16, 0, 16, 16, 16, 0};
  uint8_t mouse_idx = 0;
  uint8_t move_len, mouse_mode = 1;
  
  uint8_t volatile g_u8EP2Ready = 0;
  
  void USBD_IRQHandler(void)
  {
      uint32_t volatile u32IntSts = USBD_GET_INT_FLAG();
      uint32_t volatile u32State = USBD_GET_BUS_STATE();
  
  //------------------------------------------------------------------
      if(u32IntSts & USBD_INTSTS_VBDETIF_Msk)
      {
          // Floating detect
          USBD_CLR_INT_FLAG(USBD_INTSTS_VBDETIF_Msk);
  
          if(USBD_IS_ATTACHED())
          {
              /* USB Plug In */
              USBD_ENABLE_USB();
          }
          else
          {
              /* USB Un-plug */
              USBD_DISABLE_USB();
          }
      }
  
  //------------------------------------------------------------------
      if(u32IntSts & USBD_INTSTS_BUSIF_Msk)
      {
          /* Clear event flag */
          USBD_CLR_INT_FLAG(USBD_INTSTS_BUSIF_Msk);
  
          if(u32State & USBD_ATTR_USBRST_Msk)
          {
              printf("reset\n");
              /* Bus reset */
              USBD_ENABLE_USB();
              USBD_SwReset();
          }
          if(u32State & USBD_ATTR_SUSPEND_Msk)
          {
              /* Enable USB but disable PHY */
              USBD_DISABLE_PHY();
          }
          if(u32State & USBD_ATTR_RESUME_Msk)
          {
              /* Enable USB and enable PHY */
              USBD_ENABLE_USB();
          }
      }
  
  //------------------------------------------------------------------
      if(u32IntSts & USBD_INTSTS_USBIF_Msk)
      {
          // USB event
          if(u32IntSts & USBD_INTSTS_SETUP_Msk)
          {
              // Setup packet
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_SETUP_Msk);
  
              /* 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);
              // Interrupt IN
              EP2_Handler();
          }
  
          if(u32IntSts & USBD_INTSTS_EP3)
          {
              /* Clear event flag */
              USBD_CLR_INT_FLAG(USBD_INTSTS_EP3);
          }
  
          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);
          }
      }
  }
  
  void EP2_Handler(void)  /* Interrupt IN handler */
  {
      g_u8EP2Ready = 1;
  }
  
  
  /*--------------------------------------------------------------------------*/
  /**
    * @brief  USBD Endpoint Config.
    * @param  None.
    * @retval None.
    */
  void HID_Init(void)
  {
      /* Init setup packet buffer */
      /* Buffer range 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 ==> Interrupt IN endpoint, address 1 */
      USBD_CONFIG_EP(EP2, USBD_CFG_EPMODE_IN | INT_IN_EP_NUM);
      /* Buffer range for EP2 */
      USBD_SET_EP_BUF_ADDR(EP2, EP2_BUF_BASE);
  
      /* start to IN data */
      g_u8EP2Ready = 1;
  }
  
  void HID_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_REPORT:
  //             {
  //                 break;
  //             }
              case GET_IDLE:
  //             {
  //                 break;
  //             }
              case GET_PROTOCOL:
  //            {
  //                break;
  //            }
              default:
              {
                  /* Setup error, stall the device */
                  USBD_SetStall(0);
                  break;
              }
          }
      }
      else
      {
          // Host to device
          switch(buf[1])
          {
              case SET_REPORT:
              {
                  if(buf[3] == 3)
                  {
                      /* Request Type = Feature */
                      USBD_SET_DATA1(EP1);
                      USBD_SET_PAYLOAD_LEN(EP1, 0);
                  }
                  break;
              }
              case SET_IDLE:
              {
                  /* Status stage */
                  USBD_SET_DATA1(EP0);
                  USBD_SET_PAYLOAD_LEN(EP0, 0);
                  break;
              }
              case SET_PROTOCOL:
  //             {
  //                 break;
  //             }
              default:
              {
                  // Stall
                  /* Setup error, stall the device */
                  USBD_SetStall(0);
                  break;
              }
          }
      }
  }
  
  void HID_UpdateMouseData(void)
  {
      uint8_t *buf;
  
      if(g_u8EP2Ready)
      {
          buf = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP2));
          //mouse_mode ^= 1;
  
          if(mouse_mode)
          {
              if(move_len > 5)
              {
                  /* Update new report data */
                  buf[0] = 0x00;
                  buf[1] = mouse_table[mouse_idx & 0x07];
                  buf[2] = mouse_table[(mouse_idx + 2) & 0x07];
                  buf[3] = 0x00;
                  mouse_idx++;
                  move_len = 0;
              }
          }
          else
          {
              buf[0] = buf[1] = buf[2] = buf[3] = 0;
          }
          move_len++;
          g_u8EP2Ready = 0;
          /* Set transfer length and trigger IN transfer */
          USBD_SET_PAYLOAD_LEN(EP2, 4);
      }
  }
  