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

Dependents:   BaseUsbHost_example BaseJpegDecode_example SimpleJpegDecode_example

Import programBaseUsbHost_example

BaseUsbHost example program

BaseUsbHost.h

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

File content as of revision 5:8a2d056e9b38:

// BaseUsbHost.h 2013/2/11
#pragma once
#include <vector>
#include <string>

#define USB_OK            0
#define USB_PROCESSING   -1
#define USB_ERROR        -2
#define USB_ERROR_MEMORY -3
#define USB_ERROR_STALL  -4
#define USB_ERROR_DEVICE_NOT_RESPONDING -5

// USB STANDARD REQUEST DEFINITIONS
#define  USB_DESCRIPTOR_TYPE_DEVICE         1
#define  USB_DESCRIPTOR_TYPE_CONFIGURATION  2
#define  USB_DESCRIPTOR_TYPE_STRING         3
#define  USB_DESCRIPTOR_TYPE_INTERFACE      4
#define  USB_DESCRIPTOR_TYPE_ENDPOINT       5
#define  USB_DESCRIPTOR_TYPE_HUB         0x29
// ----------- Control RequestType Fields  -----------
#define  USB_DEVICE_TO_HOST      0x80
#define  USB_HOST_TO_DEVICE      0x00
#define  USB_REQUEST_TYPE_CLASS  0x20
#define  USB_RECIPIENT_DEVICE    0x00
#define  USB_RECIPIENT_INTERFACE 0x01
#define  USB_RECIPIENT_OTHER     0x03
// -------------- USB Standard Requests  --------------
#define  GET_STATUS              0
#define  CLEAR_FEATURE           1
#define  SET_FEATURE             3
#define  SET_ADDRESS             5
#define  GET_DESCRIPTOR          6
#define  SET_CONFIGURATION       9
#define  SET_INTERFACE           11

#pragma pack(push,1)
struct StandardDeviceDescriptor {// offset 
    uint8_t bLength;            // +0
    uint8_t bDescriptorType;    // +1
    uint16_t bcdUSB;            // +2
    uint8_t bDeviceClass;       // +4
    uint8_t bDeviceSubClass;    // +5
    uint8_t bDeviceProtocol;    // +6
    uint8_t bMaxPacketSize;     // +7
    uint16_t idVendor;          // +8
    uint16_t idProduct;         // +10
    uint16_t bcdDevice;         // +12
    uint8_t iManufacturer;      // +14
    uint8_t iProduct;           // +15
    uint8_t iSerialNumber;      // +16
    uint8_t bNumConfigurations; // +17
};                              // +18

struct StandardConfigurationDescriptor {// offset
    uint8_t bLength;               // +0
    uint8_t bDescriptorType;       // +1
    uint16_t wTotalLength;         // +2
    uint8_t bNumInterfaces;        // +4
    uint8_t bConfigurationValue;   // +5
    uint8_t iConfiguration;        // +6
    uint8_t bmAttributes;          // +7
    uint8_t bMaxPower;             // +8
};                                 // +9

struct StandardInterfaceDescriptor {// offset
    uint8_t bLength;           // +0      
    uint8_t bDescriptorType;   // +1
    uint8_t bInterfaceNumber;  // +2
    uint8_t bAlternateSetting; // +3
    uint8_t bNumEndpoints;     // +4
    uint8_t bInterfaceClass;   // +5
    uint8_t bInterfaceSubClass;// +6
    uint8_t bInterfaceProtocol;// +7
    uint8_t iInterface;        // +8
};                             // +9

struct StandardEndpointDescriptor {// offset
    uint8_t bLength;          // +0
    uint8_t bDescriptorType;  // +1
    uint8_t bEndpointAddress; // +2
    uint8_t bmAttributes;     // +3
    uint16_t wMaxPacketSize;  // +4
    uint8_t bInterval;        // +6
};                            // +7

struct StandardStringDescriptor {// offset
    uint8_t bLength;          // +0
    uint8_t bDescriptorType;  // +1
    char bString[0];          // +2
};                            // +3

struct HubDescriptor {        // offset
    uint8_t bDescLength;      // +0
    uint8_t bDescriptorType;  // +1
    uint8_t bNbrPorts;        // +2
    uint16_t wHubCharacteristics;// +3
    uint8_t bPwrOn2PwrGood;   // +5
    uint8_t bHubContrCurrent; // +6
    uint8_t DeviceRemovable;  // +7
    uint8_t PortPweCtrlMak;   // +8
};                            // +9
#pragma pack(pop)

// ------------------ HcControl Register ---------------------
#define  OR_CONTROL_PLE                 0x00000004
#define  OR_CONTROL_IE                  0x00000008
#define  OR_CONTROL_CLE                 0x00000010
#define  OR_CONTROL_BLE                 0x00000020
#define  OR_CONTROL_HCFS                0x000000C0
#define  OR_CONTROL_HC_OPER             0x00000080
// ----------------- HcCommandStatus Register -----------------
#define  OR_CMD_STATUS_HCR              0x00000001
#define  OR_CMD_STATUS_CLF              0x00000002
#define  OR_CMD_STATUS_BLF              0x00000004
// --------------- HcInterruptStatus Register -----------------
#define  OR_INTR_STATUS_WDH             0x00000002
#define  OR_INTR_STATUS_UE              0x00000010
#define  OR_INTR_STATUS_FNO             0x00000020
#define  OR_INTR_STATUS_RHSC            0x00000040
// --------------- HcInterruptEnable Register -----------------
#define  OR_INTR_ENABLE_WDH             0x00000002
#define  OR_INTR_ENABLE_FNO             0x00000020
#define  OR_INTR_ENABLE_RHSC            0x00000040
#define  OR_INTR_ENABLE_MIE             0x80000000
// ---------------- HcRhDescriptorA Register ------------------
#define  OR_RH_STATUS_LPSC              0x00010000
#define  OR_RH_STATUS_DRWE              0x00008000
// -------------- HcRhPortStatus[1:NDP] Register --------------
#define  OR_RH_PORT_CCS                 0x00000001
#define  OR_RH_PORT_PRS                 0x00000010
#define  OR_RH_PORT_CSC                 0x00010000
#define  OR_RH_PORT_PRSC                0x00100000

// TRANSFER DESCRIPTOR CONTROL FIELDS
#define  TD_ROUNDING     (uint32_t)(0x00040000) /* Buffer Rounding */
#define  TD_SETUP        (uint32_t)(0x00000000) /* Direction of Setup Packet */
#define  TD_IN           (uint32_t)(0x00100000) /* Direction In */
#define  TD_OUT          (uint32_t)(0x00080000) /* Direction Out */
#define  TD_DELAY_INT(x) (uint32_t)((x) << 21)  /* Delay Interrupt */
#define  TD_DI           (uint32_t)(7<<21)      /* desable interrupt */
#define  TD_TOGGLE_0     (uint32_t)(0x02000000) /* Toggle 0 */
#define  TD_TOGGLE_1     (uint32_t)(0x03000000) /* Toggle 1 */
#define  TD_CC           (uint32_t)(0xF0000000) /* Completion Code */

class BaseEp;
struct HCTD {    // HostController Transfer Descriptor
    __IO uint32_t Control;    // +0 Transfer descriptor control
    __IO uint8_t* CurrBufPtr; // +4 Physical address of current buffer pointer
    HCTD* Next;               // +8 Physical pointer to next Transfer Descriptor
    uint8_t*  BufEnd;         // +12 Physical address of end of buffer
    uint8_t* buf_top;         // +16 Buffer start address
    uint16_t buf_size;        // +20 buffer size size
    uint8_t _dummy[10];       // +22 dummy
    BaseEp* ep;               // +32 endpoint object
                              // +36
    HCTD(BaseEp* obj);
    inline void* operator new(size_t size) {
        void* p;
        if (posix_memalign(&p, 16, size) == 0) {
            return p;
        }
        return NULL;
    }

    inline void operator delete(void* p) {
        free(p);
    }

    inline void transfer(uint8_t* data, int len) {
        CurrBufPtr = data;
        buf_top = data;
        buf_size = len;
        BufEnd = const_cast<uint8_t*>(data)+len-1;
    }

    inline int status() {
        if (CurrBufPtr) {
            return CurrBufPtr - buf_top;
        }
        return buf_size;
    }
    
    inline uint8_t ConditionCode() {
        return Control>>28;
    }    
}; 

struct HCITD {    // HostController Isochronous Transfer Descriptor
    __IO uint32_t Control;      // +0 Transfer descriptor control
    uint8_t*  BufferPage0;      // +4 Buffer Page 0
    HCITD* Next;                // +8 Physical pointer to next Isochronous Transfer Descriptor
    uint8_t*  BufferEnd;        // +12 buffer End
    __IO uint16_t OffsetPSW[8]; // +16 Offset/PSW
    BaseEp* ep;                 // +32 endpoint object
    __IO uint8_t buf[0];        // +36 buffer
                                // +36
    HCITD(BaseEp* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize);
    inline void* operator new(size_t size, int buf_size) {
        void* p;
        if (posix_memalign(&p, 32, size+buf_size) == 0) {
            return p;
        }
        return NULL;
    }

    inline void operator delete(void* p) {
        free(p);
    }

    inline uint16_t StartingFrame() {
        return Control & 0xffff;
    }

    inline uint8_t FrameCount() {
        return ((Control>>24)&7)+1;
    }    

    inline uint8_t ConditionCode() {
        return Control>>28;
    }
};

struct HCED {    // HostController EndPoint Descriptor
    __IO uint32_t Control; // +0 Endpoint descriptor control
    HCTD* TailTd;          // +4 Physical address of tail in Transfer descriptor list
    __IO HCTD* HeadTd;     // +8 Physcial address of head in Transfer descriptor list
    HCED* Next;            // +12 Physical address of next Endpoint descriptor
                           // +16
    HCED(int addr, uint8_t ep, uint16_t size, int lowSpeed) {
        Control =  addr            | /* USB address */
        ((ep & 0x7F) << 7)         | /* Endpoint address */
        (ep!=0?(((ep&0x80)?2:1) << 11):0)| /* direction : Out = 1, 2 = In */
        ((lowSpeed?1:0) << 13)     | /* speed full=0 low=1 */
        (size << 16);                /* MaxPkt Size */
        Next = NULL;
    }

    inline void* operator new(size_t size) {
        void* p;
        if (posix_memalign(&p, 16, size) == 0) {
            return p;
        }
        return NULL;
    }

    inline void operator delete(void* p) {
        free(p);
    }

    inline uint8_t FunctionAddress() {
        return Control & 0x7f;
    }

    inline int Speed() {
        return (Control>>13)&1;
    }

    inline void setFunctionAddress(int addr) {
        Control &= ~0x7f;
        Control |= addr;
    }

    inline void setMaxPacketSize(uint16_t size) {
        Control &= ~0xffff0000;
        Control |= size<<16;
    }
};

struct HCCA {    // Host Controller Communication Area
    HCED* InterruptTable[32]; // +0 Interrupt Table
    __IO uint16_t FrameNumber;// +128 Frame Number
    __IO uint16_t Pad1;       // +130
    __IO HCTD* DoneHead;      // +132 Done Head
    uint8_t Reserved[116];    // +136 Reserved for future use
    uint8_t Unknown[4];       // +252 Unused
                              // +256
    inline void* operator new(size_t size) {
        void* p;
        if (posix_memalign(&p, 256, size) == 0) {
            return p;
        }
        return NULL;
    }

    inline void operator delete(void* p) {
        free(p);
    }
};

class BaseUsbHost {
public:
    BaseUsbHost();
    void irqHandler();
    // report
    uint32_t m_report_irq; 
    uint32_t m_report_RHSC;
    uint32_t m_report_FNO; 
    uint32_t m_report_WDH;  
    uint32_t m_report_sp;
private:
    void init_hw_ohci(HCCA* pHcca);
    void ResetRootHub();
    HCCA* m_pHcca;
};

#define HCTD_QUEUE_SIZE 3

class BaseEp { // endpoint
public:
    BaseEp(int addr, uint8_t ep = 0, uint16_t size = 8, int lowSpeed = 0);
    int GetAddr();
    int GetLowSpeed();
    void update_FunctionAddress(int addr);
    void update_MaxPacketSize(uint16_t size);
    int transfer(uint8_t* buf, int len);
    int status(uint32_t millisec=osWaitForever);
    //
    virtual void enable() = 0;
    virtual void irqWdhHandler(HCTD* td) {m_queue.put(td);} // WDH
    int wait_queue_HCTD(HCTD* wait_td, uint32_t millisec=osWaitForever);
    // report
    uint8_t m_ConditionCode;
    int m_report_queue_error;
protected:
    int send_receive(uint8_t* buf, int len, int millisec);
    HCTD* get_queue_HCTD(uint32_t millisec=osWaitForever);
    HCED* m_pED;
    Queue<HCTD, HCTD_QUEUE_SIZE> m_queue; // TD done queue
    int m_td_queue_count;
};

class ControlEp : public BaseEp {
public:
    ControlEp(int lowSpeed = 0);
    int GetDescriptor(int descType, int descIndex, uint8_t* data, int length);
    int SetAddress(int addr); // device address 
    int SetConfiguration(int config);
    int GetConfiguration(int *config);
    int SetInterfaceAlternate(int interface, int alternate);
    int GetInterface(int interface, int *alternate);
    int controlSend(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex=0, const uint8_t* data=NULL, int length=0);
    int controlReceive(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t* data, int length);
    string GetStringDescriptor(int index);
private:
    int open(int addr);
    virtual void enable(){};
};

class BulkEp : public BaseEp {
public:
    BulkEp(int addr, uint8_t ep, uint16_t size);
    int bulkSend(const uint8_t* buf, int len, int millisec=osWaitForever);
    int bulkReceive(uint8_t* buf, int len, int millisec=osWaitForever);
private:
    virtual void enable();
};

class InterruptEp : public BaseEp {
public:
    InterruptEp(int addr, uint8_t ep, uint16_t size, int lowSpeed=0);
    int interruptReceive(uint8_t* buf, int len, int millisec=osWaitForever);
private:
    virtual void enable();
};

class IsochronousEp : public BaseEp {
public:
    IsochronousEp(int addr, uint8_t ep, uint16_t size);
    void reset(int delay_ms = 100);
    HCITD* isochronousReveive(int millisec=osWaitForever);
    int isochronousSend(uint8_t* buf, int len, int millisec=osWaitForever);
    HCITD* get_queue_HCITD(int millisec);
    uint16_t m_PacketSize;
private:
    HCITD* new_HCITD(BaseEp* obj);
    int m_itd_queue_count;
    uint16_t m_FrameNumber;
    int m_FrameCount; // 1-8
    virtual void enable();
};

// --- HUB --------------------------------------------------
class UsbHub {
public:
    UsbHub(ControlEp* ctlEp = NULL);
    static bool check(ControlEp* ctlEp);
    int SetPortPower(int port);
    int ClearPortPower(int port);
    vector<ControlEp*> PortEp;
    template<class T> ControlEp* search(int skip = 0) {
        for(vector<ControlEp*>::iterator it = PortEp.begin(); it != PortEp.end(); ++it) {
            if (T::check(*it)) {
                if (skip-- <= 0) {
                    return *it;
                }
            }
        }
        return NULL;   
    }
    template<class T> ControlEp* assign(int port) {
        if (port >= 0 && port < PortEp.size()) {
            return PortEp[port];
        }
        return NULL;
    }
private:
    int PortReset(int port);
    int SetPortFeature(int feature, int index);
    int ClearPortFeature(int feature, int index);
    int SetPortReset(int port);
    int GetPortStatus(int port, uint32_t* status);
    ControlEp* m_ctlEp;
};

// --- UVC --------------------------------------------------
#define _30FPS  333333
#define _25FPS  400000
#define _20FPS  500000
#define _15FPS  666666
#define _10FPS 1000000
#define _5FPS  2000000
#define _1FPS 10000000

#define SET_CUR  0x01
#define GET_CUR  0x81
#define GET_MIN  0x82
#define GET_MAX  0x83
#define GET_RES  0x84
#define GET_LEN  0x85
#define GET_INFO 0x86
#define GET_DEF  0x87

#define VS_PROBE_CONTROL  0x01
#define VS_COMMIT_CONTROL 0x02

class BaseUvc {
public:
    void poll(int millisec=osWaitForever);
    int Control(int req, int cs, int index, uint8_t* buf, int size);
    ControlEp* m_ctlEp;
    IsochronousEp* m_isoEp;
    uint32_t report_cc_count[16];  // ConditionCode
    uint32_t report_ps_cc_count[16]; // Packt Status ConditionCode
    // callback
    void onResult(uint16_t frame, uint8_t* buf, int len);
    void setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) );
    class CDummy;
    template<class T> 
    void setOnResult( T* pItem, void (T::*pMethod)(uint16_t, uint8_t*, int) )
    {
        m_pCb = NULL;
        m_pCbItem = (CDummy*) pItem;
        m_pCbMeth = (void (CDummy::*)(uint16_t, uint8_t*, int)) pMethod;
    }
    void clearOnResult();
    CDummy* m_pCbItem;
    void (CDummy::*m_pCbMeth)(uint16_t, uint8_t*, int);
    void (*m_pCb)(uint16_t, uint8_t*, int);
};