USB host library, support isochronous,bulk,interrupt and control.

Dependents:   BaseUsbHost_example BaseJpegDecode_example SimpleJpegDecode_example

Import programBaseUsbHost_example

BaseUsbHost example program

BaseUsbHostCtlEp.cpp

Committer:
va009039
Date:
2013-02-11
Revision:
5:8a2d056e9b38
Parent:
4:d931d24c2f81

File content as of revision 5:8a2d056e9b38:

// BaseUsbHostCtlEp.cpp 2013/2/11
#include "mbed.h"
#include "rtos.h"
#include "BaseUsbHost.h"
//#define DEBUG
#include "BaseUsbHostDebug.h"
#define TEST
#include "BaseUsbHostTest.h"

#pragma pack(push,1)
struct SETUP {
    uint8_t bmRequestType;// +0
    uint8_t bRequest;     // +1
    uint16_t wValue;      // +2
    uint16_t wIndex;      // +4
    uint16_t wLength;     // +6
                          // +8
    SETUP(uint8_t RequestType, uint8_t Request, uint16_t Value, uint16_t Index, uint16_t Length) {
        CTASSERT(sizeof(SETUP) == 8);
        TEST_ASSERT(sizeof(SETUP) == 8);
        bmRequestType = RequestType;
        bRequest = Request;
        wValue = Value;
        wIndex = Index;
        wLength = Length;
    };
};
#pragma pack(pop)

static uint8_t device_addr = 1;
ControlEp::ControlEp(int lowSpeed):BaseEp(0, 0, 8, lowSpeed)
{
    CTASSERT(HCTD_QUEUE_SIZE >= 3);
    TEST_ASSERT(HCTD_QUEUE_SIZE >= 3);
    HCTD* td = new HCTD(this);
    TEST_ASSERT(td);
    m_pED->TailTd = td;
    m_pED->HeadTd = td; 
    
    m_pED->Next = reinterpret_cast<HCED*>(LPC_USB->HcControlHeadED);
    LPC_USB->HcControlHeadED = reinterpret_cast<uint32_t>(m_pED);

    DBG_OHCI(LPC_USB->HcControlHeadED);
    DBG_ED(m_pED);

    int r = open(device_addr);
    if (r == USB_OK) {
        device_addr++;
    }
}

int ControlEp::SetAddress(int addr)
{
    return controlSend(0x00, 5, addr);
}

int ControlEp::GetDescriptor(int descType, int descIndex, uint8_t* data, int length)
{
    return controlReceive(0x80, 6, (descType<<8)|descIndex, 0, data, length);
}

int ControlEp::SetConfiguration(int config)
{
    return controlSend(0x00, 9, config);
}

int ControlEp::GetConfiguration(int *config)
{
    uint8_t buf[1];
    int rc = controlReceive(0x80, 8, 0, 0, buf, 1);
    *config = buf[0];
    return rc;
}

int ControlEp::SetInterfaceAlternate(int interface, int alternate)
{
    int rc = controlSend(USB_HOST_TO_DEVICE | USB_RECIPIENT_INTERFACE, 
                     SET_INTERFACE, alternate, interface, NULL, 0);
    return rc;
}

int ControlEp::GetInterface(int interface, int *alternate)
{
    uint8_t buf[1];
    int rc = controlReceive(0x81, 10, 0, interface, buf, 1);
    *alternate = buf[0];
    return rc;
}

string ControlEp::GetStringDescriptor(int index)
{
    string s = "";
    uint8_t buf[128];
    int r = GetDescriptor(USB_DESCRIPTOR_TYPE_STRING, index, buf, sizeof(buf));
    if (r != USB_OK) {
        return s;
    }
    DBG_HEX(buf, sizeof(buf));
    StandardStringDescriptor* desc = reinterpret_cast<StandardStringDescriptor*>(buf);
    if (desc->bLength <= 2 || desc->bDescriptorType != 3) {
        return s;
    }
    for(int i = 0; i < desc->bLength-2; i += 2) {
        s += desc->bString[i];
    }
    return s;
}

int ControlEp::open(int addr)
{
    TEST_ASSERT(addr >= 1 && addr <= 127);
    uint8_t buf[8];
    int r = GetDescriptor(1, 0, buf, 8);
    if (r != USB_OK) {
        return r;
    }
    TEST_ASSERT(buf[0] == 0x12);
    TEST_ASSERT(buf[1] == 0x01);
    TEST_ASSERT(buf[7] >= 8);
    update_MaxPacketSize(buf[7]);
    r = SetAddress(addr);    
    TEST_ASSERT(r == USB_OK);
    if (r != USB_OK) {
        return r;
    }
    wait_ms(2);
    update_FunctionAddress(addr);
    return USB_OK;
}

int ControlEp::controlReceive(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
                     uint8_t* data, int length) {
    DBG("Type: %02X Request: %02X Value: %04X Index: %04X %p %d\n", bmRequestType, bRequest, wValue, wIndex, data, length);
    HCTD* setup_td = m_pED->TailTd;
    SETUP setup(bmRequestType, bRequest, wValue, wIndex, length);
    setup_td->transfer(reinterpret_cast<uint8_t*>(&setup), sizeof(SETUP));
    setup_td->Control |= TD_TOGGLE_0|TD_SETUP|TD_DI; 

    HCTD* data_td = new HCTD(this);
    TEST_ASSERT(data_td);
    data_td->transfer(data, length);
    data_td->Control |= TD_TOGGLE_1|TD_IN|TD_DI; 
    setup_td->Next = data_td;

    HCTD* status_td = new HCTD(this);
    TEST_ASSERT(status_td);
    status_td->Control |= TD_TOGGLE_1|TD_OUT; // OUT(DATA1)
    data_td->Next = status_td;

    HCTD* blank_td = new HCTD(this);
    TEST_ASSERT(blank_td);
    status_td->Next = blank_td;
    m_pED->TailTd = blank_td;

    LPC_USB->HcCommandStatus |= OR_CMD_STATUS_CLF;
    LPC_USB->HcControl |= OR_CONTROL_CLE;

    int r = wait_queue_HCTD(setup_td, 100); // wait setup stage
    if (r != USB_OK) {
        return r;
    }
    HCTD* td = get_queue_HCTD(100);
    if (td == data_td) {
        delete td;
    } else {
        DBG_TD(td);
        TEST_ASSERT(td == data_td);
        return USB_ERROR;
    }
    r = wait_queue_HCTD(status_td, 100); // wait status stage
    return r;
}

int ControlEp::controlSend(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
                     const uint8_t* data, int length) {
    DBG("Type: %02X Request: %02X Value: %04X Index: %04X %p %d\n", bmRequestType, bRequest, wValue, wIndex, data, length);
    HCTD* setup_td = m_pED->TailTd;

    HCTD* status_td = new HCTD(this);
    TEST_ASSERT(status_td);
    HCTD* blank_td = new HCTD(this);
    TEST_ASSERT(blank_td);
    
    SETUP setup(bmRequestType, bRequest, wValue, wIndex, length);
    setup_td->transfer(reinterpret_cast<uint8_t*>(&setup), sizeof(SETUP));
    setup_td->Control |= TD_TOGGLE_0|TD_SETUP|TD_DI; 
    status_td->Control |= TD_TOGGLE_1|TD_IN; // IN(DATA1)
    setup_td->Next = status_td;
    status_td->Next = blank_td;

    if (length != 0) {
        HCTD* data_td = new HCTD(this);
        TEST_ASSERT(data_td);
        data_td->Control |= TD_TOGGLE_1|TD_OUT|TD_DI; 
        data_td->transfer(const_cast<uint8_t*>(data), length);
        setup_td->Next = data_td;
        data_td->Next = status_td;
    }
    m_pED->TailTd = blank_td;
    DBG_ED(m_pED);

    LPC_USB->HcCommandStatus |= OR_CMD_STATUS_CLF;
    LPC_USB->HcControl |= OR_CONTROL_CLE;
    
    int r = wait_queue_HCTD(status_td, 200); // wait status stage
    return r;
}

HCTD::HCTD(BaseEp* obj) {
    CTASSERT(sizeof(HCTD) == 36);
    TEST_ASSERT(sizeof(HCTD) == 36);
    TEST_ASSERT(obj);
    Control = TD_CC|TD_ROUNDING;
    CurrBufPtr = NULL;
    Next = NULL;
    BufEnd = NULL;
    buf_top = NULL;
    buf_size = 0;
    ep = obj;
}