USB_HID_STACK/USBHID.c

Committer:
chris
Date:
2011-10-21
Revision:
1:4d08e0ebf5dd
Parent:
0:e98d1c2b16c6

File content as of revision 1:4d08e0ebf5dd:

/* USBClass_HID.c */
/* Human Interface Device (HID) class */
/* Copyright (c) 2011 ARM Limited. All rights reserved. */

#include "stdint.h"

#include "USBEndpoints.h"
#include "USBDevice_Types.h"
#include "USBBusInterface.h"
#include "USBHID.h"

static USBHID * instHID;

/* Output report from SET_REPORT request */
static HID_REPORT outputReport;

void setInstanceHID(USBHID * _inst){ instHID = _inst;};

bool USBClass_HID_request(void)
{
    /* Called in ISR context */

    bool success = false;
    CONTROL_TRANSFER *transfer = USBDevice_getTransferPtr();
    uint8_t *hidDescriptor;

    /* Process additional standard requests */

    if ((transfer->setup.bmRequestType.Type == STANDARD_TYPE))
    {
        switch (transfer->setup.bRequest)
        {
            case GET_DESCRIPTOR:
                switch (DESCRIPTOR_TYPE(transfer->setup.wValue))
                {
                    case REPORT_DESCRIPTOR:
                        printf("get report descr\r\n");
                        if ((instHID->ReportDesc() != NULL) \
                            && (instHID->ReportDescLength() != 0))
                        {
                            transfer->remaining = instHID->ReportDescLength();
                            transfer->ptr = instHID->ReportDesc();
                            transfer->direction = DEVICE_TO_HOST;
                            success = true;
                        }
                        break;
                    case HID_DESCRIPTOR:
                            /* Find the HID descriptor, after the configuration descriptor */
                            hidDescriptor = USBDevice_findDescriptor(HID_DESCRIPTOR);
                            if (hidDescriptor != NULL) /* NULL = Not found */
                            {
                                transfer->remaining = HID_DESCRIPTOR_LENGTH;
                                transfer->ptr = hidDescriptor;
                                transfer->direction = DEVICE_TO_HOST;
                                success = true;
                            }
                            break;
                     
                    default:
                        break;
                }
                break;
            default:
                break;
        }
    }

    /* Process class-specific requests */

    if (transfer->setup.bmRequestType.Type == CLASS_TYPE)
    {
        switch (transfer->setup.bRequest)
        {
             case SET_REPORT:
                /* First byte will be used for report ID */
                outputReport.data[0] = transfer->setup.wValue & 0xff;
                outputReport.length = transfer->setup.wLength + 1;

                transfer->remaining = sizeof(outputReport.data) - 1;
                transfer->ptr = &outputReport.data[1];
                transfer->direction = HOST_TO_DEVICE;
                transfer->notify = true; /* Callback on completion */
                success = true;
            default:
                break;
        }
    }

    return success;
}

void USBClass_HID_requestCompleted(void)
{
    /* SET_REPORT request - data is now valid */

    instHID->HID_callbackSetReport(&outputReport);
}

bool USBClass_HID_sendInputReport(uint8_t endpoint, HID_REPORT *report)
{
    EP_STATUS result;

    if (report->length > MAX_HID_REPORT_SIZE)
    {
        return false;
    }

    /* Block if not configured */
    while (!USBDevice_isConfigured());
    
    /* Send report */
    result = USBBusInterface_endpointWrite(endpoint, report->data, report->length);

    if (result != EP_PENDING)
    {
        return false;
    }

    /* Wait for completion */
    do {
        result = USBBusInterface_endpointWriteResult(endpoint);
    } while ((result == EP_PENDING) && USBDevice_isConfigured());

    return (result == EP_COMPLETED);
}

#if 0
bool USBClass_HID_getOutputReport(uint8_t endpoint, HID_REPORT *report)
{
    EP_RESULT result;
    uint32_t bytesRead = 0;

    /* Block if not configured */
    while (!USBDevice_isConfigured());

    /* Read report */
    result = USBBusInterface_endpointRead(endpoint, report->data, MAX_HID_REPORT_SIZE);

    if (result != EP_PENDING)
    {
        return false;
    }

    /* Wait for completion */
    do {
        result = USBBusInterface_endpointReadResult(endpoint, &bytesRead);
    } while ((result == EP_PENDING) && USBDevice_isConfigured());

    report->length = bytesRead;

    return (result == EP_SUCCESS);
}
#endif


#define DEFAULT_CONFIGURATION (1)

USBHID::USBHID(){
    setInstanceHID(this);
    USBDevice_init(); 
    USBDevice_connect();
}

uint16_t USBHID::ReportDescLength() {
    ReportDesc(); 
    return reportLength;
}

/*
 *  Route callbacks from lower layers to class(es)
 */

void USBHID::USBCallback_busReset(void) {
    /* Called in ISR context */
    /* Called by USBDevice layer on bus reset */

    /* May be used to reset state */
}

bool USBHID::USBCallback_request() {
    /* Called in ISR context */
    /* Called by USBDevice on Endpoint0 request */

    /* This is used to handle extensions to standard requests */
    /* and class specific requests. */

    /* Return true if class handles this request */
    return USBClass_HID_request();
}

void USBHID::USBCallback_requestCompleted() {
    /* Called in ISR context */
    /* Called by USBDevice on Endpoint0 request completion */
    /* if the 'notify' flag has been set to true */

    /* In this case it is used to indicate that a HID report has */
    /* been received from the host on endpoint 0 */

    USBClass_HID_requestCompleted();
}

void USBHID::HID_callbackSetReport(HID_REPORT *report) {
    /* Called in ISR context */

    /* HID Report received by SET_REPORT request */
    /* First byte of data will be the report ID */
}

bool USBHID::USBCallback_setConfiguration(uint8_t configuration) {
    /* Called in ISR context */

    /* Set configuration. Return false if the */
    /* configuration is not supported. */
    if (configuration != DEFAULT_CONFIGURATION) {
        return false;
    }

    /* Configure endpoints > 0 */
    USBDevice_addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
    return true;
}