#include "include.h"
#include "usb_com.h"
#include "usb_dev_enum.h"
#include "usb_hid.h"
#include "usb_audio.h"
#include "usb_vendor.h"

ep_cb_t ep_cb;

usb_handler_cb_t usb_handler_cb;

#define SWDIAG(func, filed, value)


AT(.com_text.thread.driver)
void thread_driver_event_handle(uint8_t msg)
{
    switch (msg) {
#if USB_HID_EN
        case THREAD_DRIVER_MSG_HID_IN:
            usb_hid_send_kick();
            break;
#endif

#if USB_VENDOR_EN
        case THREAD_DRIVER_MSG_VENDOR_IN:
            usb_vendor_send_kick();
            break;
#endif

#if USB_EN
        case THREAD_DRIVER_MSG_USB_IND:
            if (sys_cb.usb_is_active) {
                wireless_send_ctrl_cmd(WIRELESS_CTRL_CMD_CODE_USB_CONNECTED, 0, NULL);
            }
            break;
#endif // USB_EN

#if USB_MIC_EN
        case THREAD_DRIVER_MSG_UAC_MIC_CTRL:
            if (uda_mic_check()) {
                wireless_send_ctrl_cmd(WIRELESS_CTRL_CMD_CODE_MIC_ALLOW, 0, NULL);
            }
            break;

        case THREAD_DRIVER_MSG_UAC_DEC:
            if (uda_mic_check()) {
                SWDIAG(DEC, IO, ENTER);
                #if (AUDIO_DEC_ADPCM_EN)
                    usb_audio_mic_stream(NULL, ADPCM_BYTE_2_SAMPLE(AUDIO_MIC_PACKET_SIZE));
                #elif (AUDIO_DEC_MSBC_EN)
                    usb_audio_mic_stream(NULL, 120);
                #elif (AUDIO_DEC_SBC_EN)
                    usb_audio_mic_stream(NULL, 128);
                #endif
                SWDIAG(DEC, IO, EXIT);
            }
            break;
#endif

        default:
            break;
    }
}

void usb_ep_callback_register(ep_handler callback, uint8_t ep_index, uint8_t ep_dir)
{
    if (ep_index < EP_CNT) {
        if (ep_dir) {
            ep_cb.eptx_handler[ep_index] = callback;
        } else {
            ep_cb.eprx_handler[ep_index] = callback;
        }
    }
}

void usb_ep_reset_deal(void)
{
#if USB_HID_EN
    usb_int_ep_reset();
#endif

#if USB_AUDIO_EN
    usb_isoc_ep_reset();
#endif

#if USB_VENDOR_EN
    usb_vendor_ep_reset();
#endif
}

AT(.usbdev.com)
void usb_device_process(void)
{
#if USB_HID_EN
    usb_hid_process();
#endif

#if USB_AUDIO_EN
    usb_audio_process();
#endif

#if USB_VENDOR_EN
    usb_vendor_process();
#endif
}

AT(.com_text.isr.sof)
void usb_sof_callback(void)
{
    // Enter: interrupt IRQ

#if USB_HID_EN
    usb_sof_hid_isr();
#endif

    // Exit: interrupt IRQ
}

AT(.usbdev.com)
bool usb_event_callback(uint8_t event, spb_wrap_t *spb, uint8_t *data, uint8_t data_len)
{
    switch (event){
        case MSG_USB_EP_RESET:
            printf("-->MSG_USB_EP_RESET\n");
            ude_state_reset(&ude_cb);
            usb_ep_reset_deal();
            break;

        case MSG_USB_EP0_CTL_FLOW:
            return usb_ep0_ctl_callback(spb, data, data_len);

        case MSG_USB_SUSPEND:
            printf("--->MSG_USB_SUSPEND\n");
            #if USB_HID_EN
            usb_hid_suspend_callback(true);
            #endif
            break;

        case MSG_USB_RESUME:
            printf("--->MSG_USB_RESUME\n");
            #if USB_HID_EN
            usb_hid_suspend_callback(false);
            #endif
            break;

        case MSG_USB_EP1_IN:
            if (ep_cb.eptx_handler[1]) {
                ep_cb.eptx_handler[1]();
            }
            break;

        case MSG_USB_EP1_OUT:
            if (ep_cb.eprx_handler[1]) {
                ep_cb.eprx_handler[1]();
            }
            break;

        case MSG_USB_EP2_IN:
            if (ep_cb.eptx_handler[2]) {
                ep_cb.eptx_handler[2]();
            }
            break;

        case MSG_USB_EP2_OUT:
            if (ep_cb.eprx_handler[2]) {
                ep_cb.eprx_handler[2]();
            }
            break;

        case MSG_USB_EP3_IN:
            if (ep_cb.eptx_handler[3]) {
                ep_cb.eptx_handler[3]();
            }
            break;

        case MSG_USB_EP3_OUT:
            if (ep_cb.eprx_handler[3]) {
                ep_cb.eprx_handler[3]();
            }
            break;

        default:
            return false;
    }

    return true;
}

bool usb_ep_init_handler(void)
{
#if USB_HID_EN
    udh_init();
#endif
#if USB_AUDIO_EN
    uda_init();
#endif
#if USB_VENDOR_EN
    udv_init();
#endif
    return true;
}

void usb_device_init(void)
{
    usb_handler_cb.init = usb_ep_init_handler;
    usb_handler_cb.evt = usb_event_callback;

    usb_handler_register(&usb_handler_cb);
    usb_sof_hook_register(usb_sof_callback);

    thread_driver_user_callback_register(thread_driver_event_handle);

    usb_init();

#if USB_AUDIO_EN
    usb_audio_init();
#endif

#if USB_HID_EN
    usb_hid_init();
#endif // USB_HID_EN

#if USB_VENDOR_EN
    usb_vendor_init();
#endif // USB_VENDOR_EN
}

void usb_device_deinit(void)
{
#if USB_AUDIO_EN
    usb_audio_deinit();
#endif

#if USB_HID_EN
    usb_hid_deinit();
#endif // USB_HID_EN

#if USB_VENDOR_EN
    usb_vendor_deinit();
#endif
}
