/*
 *  usb_device.h
 *
 * Change Logs:
 * Date          Author      Notes
 * 2024-01-09    weijiac     handle usb intr
 */

#include "usb_common.h"
#include "hal_usbd.h"
#include "hal_usbd_init.h"
#include "hal_usbd_reg.h"
#include "usb_device.h"
#include "debug.h"

void usb_intr_handle(uint8_t vINTRUSB);
void usb_ep0_handle(uint16_t vINTRTX);

void usb_ep_handle(uint16_t vINTRTX, uint16_t vINTRRX);
struct udevice *cur_usb_device = RT_NULL;

//实现中断函数，长
void usbhsfc_intr()
{
    // debug("usbhsfc_intr \n\r");
    uint8_t     vINTRUSB;
    uint16_t    vINTRTX;
    uint16_t    vINTRRX;
    /* Read interrupt registers */
    vINTRUSB  = usb_read_intrusb();
    vINTRTX   = usb_read_intrtx();
    vINTRRX  = usb_read_intrrx();
    /* Check for system interrupts */
    usb_intr_handle(vINTRUSB);
    /* Check for endpoint 0 interrupt */
    usb_ep0_handle(vINTRTX);
    usb_ep_handle(vINTRTX, vINTRRX);
    //debug("finish usbhsfc_intr\n\r");
    return;
}

//处理如usb reset connect等中断
void usb_intr_handle(uint8_t vINTRUSB)
{
    if (vINTRUSB & REG_INTRUSB_RESET)
    {
#ifdef USB_DEBUG
        debug("usb reset \n\r");
#endif
        USBReset();
        *(volatile uint32_t *)(0x20006000) &= ~((1 << 7)); //USB_PHY_CTRL0
        usb_write_intrusbe(0x07);
        usb_write_power(0x71);
        // rt_usbd_reset_handler(&spv40_usb);
        HAL_USBD_LOG("[####usb####]reset!\n");
        HAL_USBD_LOG("reset\n");
#ifdef USB_DEBUG
        debug("finish usb reset handle\n\r");
#endif
    }

    if (vINTRUSB & REG_INTRUSB_CONN)
    {
        // rt_usbd_connect_handler(&spv40_usb);
        cur_usb_device = rt_usbd_get_curr_device();
        cur_usb_device->state = USB_STATE_ATTACHED;
        HAL_USBD_LOG("[####usb####] rt_usbd_connect_handler(&spv40_usb)\n");
        HAL_USBD_LOG("connect ! \n\r");
    }

    if (vINTRUSB & REG_INTRUSB_DISCON)
    {
        // rt_usbd_disconnect_handler(&spv40_usb);
        cur_usb_device = rt_usbd_get_curr_device();
        cur_usb_device->state = USB_STATE_NOTATTACHED;
        _stop_notify(cur_usb_device);
        HAL_USBD_LOG("[####usb####] rt_usbd_disconnect_handler(&spv40_usb)\n");
    }

    if (vINTRUSB & REG_INTRUSB_SOF)
    {
        // rt_usbd_sof_handler(&spv40_usb);
        HAL_USBD_LOG("[####usb####]  rt_usbd_sof_handler(&spv40_usb)\n");
        //HAL_USBD_LOG("[####usb####]sof!\n");
    }

    /* Check for suspend mode */
    if (vINTRUSB & REG_INTRUSB_SUSPEND)
    {
        //NULL
        usbd_disconnect();
        HAL_USBD_LOG("[####usb####]  usbd_disconnect()\n");
        //HAL_USBD_LOG("*******************usb suspend*****************\n");
    }

    /* Check for resume from suspend mode */
    if (vINTRUSB & REG_INTRUSB_RESUME)
    {
        //NULL
        //AON_OSC->XTAL_CTL |= 0x01;
    }
}


// //区分ep0中断setup事务还是out事务，0为setup事务，1为out事务
// //区分方式，在每次读完setup包之后，判断是device to host还是host to device ,如果是host to device，则将该bit置1，根据经验，ep0 host to device 不会出现分包情况
static uint8_t ep0_intr_class = 0;
uint8_t usb_setup_data[M_EP0_MAXP] = {0};   //ep0 buffer
struct ep_msg ep0_msg = {0, 0};
//处理端点0中断
//usb仅处理端点0的事务，其他端点调用对应端点的注册的回调函数
void usb_ep0_handle(uint16_t vINTRTX)
{
    uint8_t     old_INDEX;
    uint8_t     vCSR0, vCOUNT0;

    if (vINTRTX & REG_INTRTX_EP(0))
    {
        old_INDEX = usb_read_index();
        usb_write_index(0x0);
        vCOUNT0 = usb_read_count0();    //count0 指endpoint0 fifo中存在的字节数

        if (vCOUNT0 > 0)
        {
            if (ep0_intr_class && (vCOUNT0 != 8))
            {
                //ep 0 out treansaction
                ep0_intr_class = 0;
                // rt_usbd_ep0_out_handler(&spv40_usb, vCOUNT0);
                ep0_msg.size = vCOUNT0;
                /* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ ep0 out handle ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
                _ep0_out_notify(rt_usbd_get_curr_device(), &ep0_msg);
                // debug("ep0 out handle\n\r");
                /* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ep0 out handle ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */
            }
            else
            {   
                FIFORead(0, vCOUNT0, usb_setup_data);
                if(ep0_intr_class == 1)
                {
                    // debug("ep0_intr_class == 1 ,but not ep0 out handle\n\r");
                    // debug("vCOUNT0 %d\n\r",vCOUNT0);
                    // for(int ee = 0;ee<vCOUNT0;ee++)
                    // {
                    //     debug("usb_setup_data[%d] = 0x%02x \n\r",ee,usb_setup_data[ee]);
                    // }
                }
                
                ep0_intr_class = 0;

                if (usb_read_csr0() & REG_CSR0_RXPKTRDY)
                {
                    usb_write_csr0(usb_read_csr0() | REG_CSR0_SERVICED_RXPKTRDY);
                }
                
#if 0
                HAL_USBD_LOG("[####usb####]vCOUNT0:%d, EP0 read: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", vCOUNT0,
                             usb_setup_data[0], usb_setup_data[1], usb_setup_data[2], usb_setup_data[3], usb_setup_data[4], usb_setup_data[5], usb_setup_data[6], usb_setup_data[7]);
#endif
                /* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓setup handle ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
                _setup_request(rt_usbd_get_curr_device(), usb_setup_data);
                /* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑setup handle ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */
                HAL_USBD_LOG("vCOUNT0 = %d \n\r", vCOUNT0);
                HAL_USBD_LOG("usb_setup_data->request_type = %d \n\r", ((struct urequest *)usb_setup_data)->request_type);
                HAL_USBD_LOG("usb_setup_data->bRequest = %d \n\r", ((struct urequest *)usb_setup_data)->bRequest);
                HAL_USBD_LOG("usb_setup_data->wValue = %d \n\r", ((struct urequest *)usb_setup_data)->wValue);
                HAL_USBD_LOG("usb_setup_data->wIndex = %d \n\r", ((struct urequest *)usb_setup_data)->wIndex);
                HAL_USBD_LOG("usb_setup_data->wLength = %d \n\r", ((struct urequest *)usb_setup_data)->wLength);

                if (((struct urequest *)usb_setup_data)->wLength && !(((struct urequest *)usb_setup_data)->request_type & 0x80))
                {
                    ep0_intr_class = 1;
                    // debug("ep0_intr_class = 1 \n\r");
                    // debug("usb_setup_data->request_type = 0x%02x \n\r", ((struct urequest *)usb_setup_data)->request_type);
                    // debug("usb_setup_data->bRequest = 0x%02x \n\r", ((struct urequest *)usb_setup_data)->bRequest);
                    // debug("usb_setup_data->wValue = 0x%04x \n\r", ((struct urequest *)usb_setup_data)->wValue);
                    // debug("usb_setup_data->wIndex = 0x%04x \n\r", ((struct urequest *)usb_setup_data)->wIndex);
                    // debug("usb_setup_data->wLength = 0x%04x \n\r", ((struct urequest *)usb_setup_data)->wLength);
                }
            }
        }
        else
        {
            rt_usbd_ep0_in_handler((rt_usbd_get_curr_device())->dcd);

            if (usb_read_csr0() & REG_CSR0_RXPKTRDY)
            {
                usb_write_csr0(usb_read_csr0() | REG_CSR0_SERVICED_RXPKTRDY);
            }
        }

        /* Check for SentStall */
        vCSR0 = usb_read_csr0();

        if (vCSR0 & REG_CSR0_SENTSTALL)
        {
            HAL_USBD_LOG("SENTSTALL\n");
            usb_write_csr0((vCSR0 & ~REG_CSR0_SENTSTALL) & 0xff);
        }

        /* Check for SetupEnd */
        vCSR0 = usb_read_csr0();

        if (vCSR0 & REG_CSR0_SETUPEND)
        {
            usb_write_csr0((vCSR0 | REG_CSR0_SERVICED_SETUPEND) & 0xff);
        }

        usb_write_index(old_INDEX);
    }
}

//除了端点0，其他端点只能为IN 或 OUT，所以注册不管是in还是out都调用一个回调函数是合理的。
static uint8_t i = 0;
void usb_ep_handle(uint16_t vINTRTX, uint16_t vINTRRX)
{
    //tx
    if (vINTRTX & (0x01 << 0x1))
    {
        //rt_usbd_ep_in_handler(&spv40_usb, USB_DIR_IN | 0x1, 0);
        hal_usbd_ep_function_call(1);
        HAL_USBD_LOG("in_h ep:%d\n", 0x1);
    }

    if (vINTRTX & (0x01 << 0x2))
    {
        hal_usbd_ep_function_call(2);
        HAL_USBD_LOG("in_h ep:%d\n", 0x2);
    }

    if (vINTRTX & (0x01 << 0x3))
    {
        hal_usbd_ep_function_call(3);
        HAL_USBD_LOG("in_h ep:%d\n", 0x3);
    }

    if (vINTRTX & (0x01 << 0x4))
    {
        hal_usbd_ep_function_call(4);
        HAL_USBD_LOG("in_h ep:%d\n", 0x4);
    }

    if (vINTRTX & (0x01 << 0x5))
    {
        hal_usbd_ep_function_call(5);
        HAL_USBD_LOG("in_h ep:%d\n", 0x5);
    }

    if (vINTRTX & (0x01 << 0x6))
    {
        hal_usbd_ep_function_call(6);
        HAL_USBD_LOG("in_h ep:%d\n", 0x6);
    }

    //rx
    if (vINTRRX & (0x01 << 0x1))
    {
        //rt_usbd_ep_in_handler(&spv40_usb, USB_DIR_IN | 0x1, 0);
        hal_usbd_ep_function_call(1);
        HAL_USBD_LOG("in_h ep:%d\n", 0x1);
    }

    if (vINTRRX & (0x01 << 0x2))
    {
        hal_usbd_ep_function_call(2);
        HAL_USBD_LOG("in_h ep:%d\n", 0x2);
    }

    if (vINTRRX & (0x01 << 0x3))
    {
        hal_usbd_ep_function_call(3);
        HAL_USBD_LOG("in_h ep:%d\n", 0x3);
    }

    if (vINTRRX & (0x01 << 0x4))
    {
        hal_usbd_ep_function_call(4);
        HAL_USBD_LOG("in_h ep:%d\n", 0x4);
    }

    if (vINTRRX & (0x01 << 0x5))
    {
        hal_usbd_ep_function_call(5);
        HAL_USBD_LOG("in_h ep:%d\n", 0x5);
    }

    if (vINTRRX & (0x01 << 0x6))
    {
        hal_usbd_ep_function_call(6);
        HAL_USBD_LOG("in_h ep:%d\n", 0x6);
    }
}

