Tim H / Mbed OS UsbKnob

Dependencies:   USBDevice

USBControl.cpp

Committer:
Timmmm
Date:
2016-11-04
Revision:
0:1a3aa2e25db9

File content as of revision 0:1a3aa2e25db9:

#include "USBControl.h"

#include <USBDescriptor.h>

#define DEFAULT_CONFIGURATION (1)

std::vector<uint8_t> MakeStringDescriptor(const char* s)
{
    int len = strlen(s);
    if (len > 126) // TODO: Double check this is the max length.
        len = 126;
        
    std::vector<uint8_t> desc(len*2 + 2);
    
    desc[0] = desc.size();
    desc[1] = STRING_DESCRIPTOR;
    for (int i = 0; i < len; ++i)
        desc[2 + i*2] = s[i];
        
    return desc;
}
                               
USBControl::USBControl(uint16_t vendor_id, uint16_t product_id, uint16_t product_release, const char* product_name, const char* manufacturer_name, const char* guid) : WinUSBDevice(vendor_id, product_id, product_release, guid)
{
    mProductStringDescriptor = MakeStringDescriptor(product_name);
    mManufacturerStringDescriptor = MakeStringDescriptor(manufacturer_name);
}
    
bool USBControl::USBCallback_setConfiguration(uint8_t configuration)
{
    // Called in ISR context. Return false if the configuration is not supported.
    if (configuration != DEFAULT_CONFIGURATION)
        return false;
        
    // Configure endpoints > 0
    addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
    addEndpoint(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
    
    // Start receiving on the OUT endpoint
    readStart(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
        
    return true;
}

bool USBControl::EPINT_OUT_callback()
{
    // TODO: Presumably this is called in an interrupt context, therefore we really need a lock
    // or a lock free ring buffer (better).
    uint32_t bytesRead = 0;
    uint8_t buf[MAX_PACKET_SIZE_EPINT];
    if (readEP(EPINT_OUT, buf, &bytesRead, MAX_PACKET_SIZE_EPINT))
    {
        mReceivedPackets.push_back(std::string((char*)buf, bytesRead));
    }

    // Start reading again.
    readStart(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
    // Return true to say that we have handled it.
    return true;
}

uint8_t* USBControl::stringIproductDesc()
{
    return &mProductStringDescriptor.front();
}

uint8_t* USBControl::stringIinterfaceDesc()
{
    static uint8_t stringIinterfaceDescriptor[] = {
        0x10,                           // bLength
        STRING_DESCRIPTOR,              // bDescriptorType 0x03
        'C',0,'o',0,'n',0,'t',0,'r',0,'o',0,'l',0   // bString iInterface - Control
    };
    return stringIinterfaceDescriptor;
}

uint8_t* USBControl::stringImanufacturerDesc()
{
    return &mManufacturerStringDescriptor.front();
}

#define SENSOR_CLASS (0xFF) // Vendor specific.
#define SENSOR_SUBCLASS (0x00)
#define SENSOR_PROTOCOL (0x00)

#define NUM_ENDPOINTS 2

#define TOTAL_DESCRIPTOR_LENGTH ((1 * CONFIGURATION_DESCRIPTOR_LENGTH) \
                               + (1 * INTERFACE_DESCRIPTOR_LENGTH) \
                               + (NUM_ENDPOINTS * ENDPOINT_DESCRIPTOR_LENGTH))
                               
uint8_t* USBControl::configurationDesc()
{
    static uint8_t configurationDescriptor[] = {
        CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
        CONFIGURATION_DESCRIPTOR,       // bDescriptorType
        LSB(TOTAL_DESCRIPTOR_LENGTH),   // wTotalLength (LSB)
        MSB(TOTAL_DESCRIPTOR_LENGTH),   // wTotalLength (MSB)
        0x01,                           // bNumInterfaces
        DEFAULT_CONFIGURATION,          // bConfigurationValue
        0x00,                           // iConfiguration
        C_RESERVED,                     // bmAttributes (C_RESERVED must be set)
        C_POWER(100),                   // bMaxPower in mA

        INTERFACE_DESCRIPTOR_LENGTH,    // bLength
        INTERFACE_DESCRIPTOR,           // bDescriptorType
        0x00,                           // bInterfaceNumber
        0x00,                           // bAlternateSetting
        NUM_ENDPOINTS,                  // bNumEndpoints
        SENSOR_CLASS,                   // bInterfaceClass
        SENSOR_SUBCLASS,                // bInterfaceSubClass
        SENSOR_PROTOCOL,                // bInterfaceProtocol
        0x00,                           // iInterface

        // IN interrupt endpoint descriptor
        ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
        ENDPOINT_DESCRIPTOR,            // bDescriptorType
        PHY_TO_DESC(EPINT_IN),          // bEndpointAddress
        E_INTERRUPT,                    // bmAttributes
        LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
        MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
        1,                              // bInterval (milliseconds)

        // OUT interrupt endpoint descriptor
        ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
        ENDPOINT_DESCRIPTOR,            // bDescriptorType
        PHY_TO_DESC(EPINT_OUT),         // bEndpointAddress
        E_INTERRUPT,                    // bmAttributes
        LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
        MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
        1,                              // bInterval (milliseconds)
    };
    return configurationDescriptor;
}

bool USBControl::sendData(const std::string& data)
{
    return write(EPINT_IN, (uint8_t*)data.c_str(), data.length(), MAX_PACKET_SIZE_EPINT);
}

bool USBControl::sendData(const uint8_t* data, int len)
{
    return write(EPINT_IN, const_cast<uint8_t*>(data), len, MAX_PACKET_SIZE_EPINT);
}

bool USBControl::sendDataNB(const std::string& data)
{
    return write(EPINT_IN, (uint8_t*)data.c_str(), data.length(), MAX_PACKET_SIZE_EPINT);
}

bool USBControl::sendDataNB(const uint8_t* data, int len)
{
    return write(EPINT_IN, const_cast<uint8_t*>(data), len, MAX_PACKET_SIZE_EPINT);
}

std::string USBControl::receiveData()
{
    while (mReceivedPackets.empty())
        ;
    
    std::string s = mReceivedPackets.front();
    mReceivedPackets.erase(mReceivedPackets.begin());
    return s;
}

std::string USBControl::receiveDataNB()
{
    if (mReceivedPackets.empty())
        return std::string();
        
    std::string s = mReceivedPackets.front();
    mReceivedPackets.erase(mReceivedPackets.begin());
    return s;
}