/**
 * The copyrights, all other intellectual and industrial
 * property rights are retained by XMOS and/or its licensors.
 * Terms and conditions covering the use of this code can
 * be found in the Xmos End User License Agreement.
 *
 * Copyright XMOS Ltd 2013
 *
 * In the case where this code is a modification of existing code
 * under a separate license, the separate license terms are shown
 * below. The modifications to the code are still covered by the
 * copyright notice above.
 *
 **/

#include "xud.h"

#define p_usb_rst null
#define clk_usb_rst null
#define PWR_MODE XUD_PWR_SELF
#define XUD_EP_COUNT_OUT   1
#define XUD_EP_COUNT_IN    2

/* Prototype for Endpoint0 function in endpoint0.xc */
void Endpoint0(chanend c_ep0_out, chanend c_ep0_in);

/* Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also
 * if the endpoint wishes to be informed of USB bus resets
 */
XUD_EpType epTypeTableOut[XUD_EP_COUNT_OUT] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE};
XUD_EpType epTypeTableIn[XUD_EP_COUNT_IN] =   {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_BUL};


/* Global report buffer, global since used by Endpoint0 core */
unsigned char g_reportBuffer[] = {0, 0, 0, 0};

/*
 * This function responds to the HID requests 
 * - It draws a square using the mouse moving 40 pixels in each direction
 * - The sequence repeats every 500 requests.
 */
void hid_mouse(chanend chan_ep_hid)
{
    int counter = 0;
    int state = 0;

    XUD_ep ep_hid = XUD_InitEp(chan_ep_hid);

    while (1)
    {
        int x;
        g_reportBuffer[1] = 0;
        g_reportBuffer[2] = 0;

        /* Move the pointer around in a square (relative) */
        counter++;
        if (counter >= 500)
        {
            counter = 0;
            if (state == 0)
            {
                g_reportBuffer[1] = 40;
                g_reportBuffer[2] = 0;
                state+=1;
            }
            else if (state == 1)
            {
                g_reportBuffer[1] = 0;
                g_reportBuffer[2] = 40;
                state+=1;
            }
            else if (state == 2)
            {
                g_reportBuffer[1] = -40;
                g_reportBuffer[2] = 0;
                state+=1;
            }
            else if (state == 3)
            {
                g_reportBuffer[1] = 0;
                g_reportBuffer[2] = -40;
                state = 0;
            }
        }

        /* Send the buffer off to the host.  Note this will return when complete */
        XUD_SetBuffer(ep_hid, g_reportBuffer, 4);
    }
}

/* The main function runs three cores: the XUD manager, Endpoint 0, and a HID endpoint. An array of
 * channels is used for both IN and OUT endpoints, endpoint zero requires both, HID requires just an
 * IN endpoint to send HID reports to the host.
 */
int main()
{
    chan c_ep_out[XUD_EP_COUNT_OUT], c_ep_in[XUD_EP_COUNT_IN];

    par
    {
        on USB_TILE: XUD_Manager(c_ep_out, XUD_EP_COUNT_OUT, c_ep_in, XUD_EP_COUNT_IN,
                                null, epTypeTableOut, epTypeTableIn,
                                p_usb_rst, clk_usb_rst, -1, XUD_SPEED_HS, PWR_MODE);

        on USB_TILE: Endpoint0(c_ep_out[0], c_ep_in[0]);

        on USB_TILE: hid_mouse(c_ep_in[1]);

    }

    return 0;
}
