BlueUSB with USB-> SERIAL (CP210x) GPIO pins working.

Dependencies:   mbed

AutoEvents.cpp

Committer:
tecnosys
Date:
2010-04-23
Revision:
0:a14eaa2e1445

File content as of revision 0:a14eaa2e1445:


/*
Copyright (c) 2010 Peter Barrett

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
CP210
HubStatusChange Hub:0 Port:1 00010101
ResetPort Hub:0 Port:1
HubStatusChange Hub:0 Port:1 00100103
Connect Hub:0 Port:1 full
Class 00 found 10C4:EA60
AddEndpoint D:01 A:01 T:02 P:0040 I:00
LoadDevice 1 FF:00:00
1: Silicon Labs
2: CP2103 USB to UART Bridge Controller

////
CP210
HubStatusChange Hub:0 Port:1 00010101
ResetPort Hub:0 Port:1
HubStatusChange Hub:0 Port:1 00100103
Connect Hub:0 Port:1 full
Class 00 found 10C4:EA60
AddEndpoint D:01 A:00 T:00 P:0040 I:00
AddEndpoint D:01 A:81 T:02 P:0040 I:00
AddEndpoint D:01 A:01 T:02 P:0040 I:00
LoadDevice 1 FF:00:00
1: Silicon Labs
2: CP2103 USB to UART Bridge Controller

///
FTDI
HubStatusChange Hub:0 Port:1 00010101
ResetPort Hub:0 Port:1
HubStatusChange Hub:0 Port:1 00100103
Connect Hub:0 Port:1 full

Class 00 found 0403:6001
AddEndpoint D:01 A:00 T:00 P:0008 I:00
AddEndpoint D:01 A:81 T:02 P:0040 I:00
AddEndpoint D:01 A:02 T:02 P:0040 I:00
LoadDevice 1 FF:FF:FF
1: FTDI
2: FT232R USB UART
//

mouse
HubStatusChange Hub:0 Port:1 00010301
ResetPort Hub:0 Port:1
HubStatusChange Hub:0 Port:1 00100303
Connect Hub:0 Port:1 slow
Class 00 found 046D:C019
AddEndpoint D:01 A:00 T:00 P:0008 I:00
Skipping descriptor 21 (9 bytes)
AddEndpoint D:01 A:81 T:03 P:0005 I:0A
LoadDevice 1 03:01:02
1: Logitech
2: Logitech USB Optical Mouse
Auto Event for 81 00030102


usbhd

HubStatusChange Hub:0 Port:1 00010101
ResetPort Hub:0 Port:1
HubStatusChange Hub:0 Port:1 00100103
Connect Hub:0 Port:1 full
Class 00 found 1E3D:2088
AddEndpoint D:01 A:00 T:00 P:0040 I:00
AddEndpoint D:01 A:01 T:02 P:0040 I:00
AddEndpoint D:01 A:81 T:02 P:0040 I:00
LoadDevice 1 08:06:50
1: V88     
2: V88             
Dumping root dir
_START~1.HTM 256
AUTORUN.INF 256
desktop.ini 256
STARTH~1.HTM 256
html 256
       
some tplink shit usb 54mbit wireless
       
sChange Hub:0 Port:1 00010101
ResetPort Hub:0 Port:1
HubStatusChange Hub:0 Port:1 00100103
Connect Hub:0 Port:1 full
Class 00 found 148F:2573
AddEndpoint D:01 A:00 T:00 P:0040 I:00
AddEndpoint D:01 A:81 T:02 P:0040 I:00
AddEndpoint D:01 A:01 T:02 P:0040 I:00
LoadDevice 1 FF:FF:FF
1: Ralink
2: 54M.USB.......


*/

#include "mbed.h"
#include "USBHost.h"
#include "Utils.h"

//#include "CP2103.h"

/* Config request types */
#define REQTYPE_HOST_TO_DEVICE    0x40
#define REQTYPE_DEVICE_TO_HOST    0xc0

/* Config request codes */
#define CP210X_SPECIFIC        0xFF

/* CP210X_SPECIFIC */
#define GPIO_WRITE              0x37E1
#define GPIO_READ               0x00C2
#define PORT_CONFIG             0x370C
#define WRITE_VID               0x3701
#define WRITE_PID               0x3702
#define WRITE_PRODUCT           0x3703
#define WRITE_SERIAL            0x3704
#define WRITE_POWER             0x3706
#define WRITE_RELEASE           0x3707


/* CP210X_IFC_ENABLE */
#define UART_ENABLE        0x0001
#define UART_DISABLE        0x0000

#define CP210X_IFC_ENABLE    0x00

#define CP210X_GPIO0    (1<<0)
#define CP210X_GPIO1    (1<<1)
#define CP210X_GPIO2    (1<<2)
#define CP210X_GPIO3    (1<<3)

struct cp210x_port_state_t {
  uint16_t mode;
  uint16_t low_power;
  uint16_t latch;
} ;//cp210x_get_config

struct cp210x_port_config_t {
  struct cp210x_port_state_t reset; /**< Port state applied on after reset. */
  struct cp210x_port_state_t suspend; /**< Port state applied on suspend. */
  unsigned char enhanced_fxn; /**< Enable/disable enhanced port functions. */
} ;//__attribute__ ((packed));


typedef struct
{
    char *device_name;
    uint8_t input; /**< Mask of GPIOs to be configured as inputs. */
    uint8_t output; /**< Mask of GPIOs to be configured as outputs. */
    uint8_t hi; /**< Mask of GPIOs to be set. */
    uint8_t lo; /**< Mask of GPIOs to be cleared. */
    uint8_t toggle; /**< Mask of GPIOs to be toggled. */
    int dump; /**< Dump structures. */
}
config_t;


static const char *pin_names[] =
{
    "RI", "DCD", "DTR", "DSR", "TXD", "RXD", "RTS", "CTS",
    "GPIO_0", "GPIO_1", "GPIO_2", "GPIO_3",
    "reserved", "reserved", "SUSPEND", "/SUSPEND"
};

static const char *fxn_names[] =
{
    "GPIO_0_TXLED",
    "GPIO_1_RXLED",
    "GPIO_2_RS485",
    "reserved",
    "WEAKPULLUP_RESET",
    "WEAKPULLUP_SUSPEND",
    "SERIAL_DYNAMIC_SUSPEND",
    "GPIO_DYNAMIC_SUSPEND"
};

#define AUTOEVT(_class,_subclass,_protocol) (((_class) << 16) | ((_subclass) << 8) | _protocol)
#define AUTO_KEYBOARD AUTOEVT(CLASS_HID,1,1)
#define AUTO_MOUSE AUTOEVT(CLASS_HID,1,2)

u8 auto_mouse[4];       // buttons,dx,dy,scroll
u8 auto_keyboard[8];    // modifiers,reserved,keycode1..keycode6
u8 auto_joystick[4];    // x,y,buttons,throttle

void AutoEventCallback(int device, int endpoint, int status, u8* data, int len, void* userData)
{
    int evt = (int)userData;
    switch (evt)
    {
        case AUTO_KEYBOARD:
            printf("AUTO_KEYBOARD ");
            break;
        case AUTO_MOUSE:
            printf("AUTO_MOUSE ");
            break;
        default:
            printf("HUH ");
    }
    printfBytes("data",data,len);
    USBInterruptTransfer(device,endpoint,data,len,AutoEventCallback,userData);
}

//  Establish transfers for interrupt events
void AddAutoEvent(int device, InterfaceDescriptor* id, EndpointDescriptor* ed)
{
    if ((ed->bmAttributes & 3) != ENDPOINT_INTERRUPT || !(ed->bEndpointAddress & 0x80))
        return;
    
    // Make automatic interrupt enpoints for known devices
    u32 evt = AUTOEVT(id->bInterfaceClass,id->bInterfaceSubClass,id->bInterfaceProtocol);
    u8* dst = 0;
    int len;
    switch (evt)
    {
        case AUTO_MOUSE:
            dst = auto_mouse;
            len = sizeof(auto_mouse);
            break;
        case AUTO_KEYBOARD:
            dst = auto_keyboard;
            len = sizeof(auto_keyboard);
            break;
        default:
            printf("Interrupt endpoint %02X %08X\n",ed->bEndpointAddress,evt);
            break;
    }
    if (dst)
    {
        printf("Auto Event for %02X %08X\n",ed->bEndpointAddress,evt);
        USBInterruptTransfer(device,ed->bEndpointAddress,dst,len,AutoEventCallback,(void*)evt);
    }
}

void PrintString(int device, int i)
{
    u8 buffer[256];
    int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,i,buffer,255);
    if (le < 0)
         return;
    char* dst = (char*)buffer;
    for (int j = 2; j < le; j += 2)
        *dst++ = buffer[j];
    *dst = 0;
    printf("%d:%s\n",i,(const char*)buffer);
 }
 
//  Walk descriptors and create endpoints for a given device
int StartAutoEvent(int device, int configuration, int interfaceNumber)
{
    u8 buffer[255];
    int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,255);
    if (err < 0)
        return err;

    int len = buffer[2] | (buffer[3] << 8);
    u8* d = buffer;
    u8* end = d + len;
    while (d < end)
    {
        if (d[1] == DESCRIPTOR_TYPE_INTERFACE)
        {
            InterfaceDescriptor* id = (InterfaceDescriptor*)d;
            if (id->bInterfaceNumber == interfaceNumber)
            {
                 d += d[0];
                while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE)
                {
                    if (d[1] == DESCRIPTOR_TYPE_ENDPOINT)
                        AddAutoEvent(device,id,(EndpointDescriptor*)d);
                    d += d[0];
                }
            }
        }
        d += d[0];
    }
    return 0;
}



//  Implemented in main.cpp
int OnDiskInsert(int device);

//  Implemented in TestShell.cpp
int OnBluetoothInsert(int device);

static int cp210x_set_config(int device, u8 request,
        unsigned int *data, int size)
{
/*
        result = usb_control_msg(serial->dev,
                usb_sndctrlpipe(serial->dev, 0),
                request, REQTYPE_HOST_TO_DEVICE, 0x0000,
                0, buf, size, 300);
    */            
                
    return  USBControlTransfer(device,
         REQTYPE_HOST_TO_DEVICE, request, 0x0000, 0,
         (u8*)data, sizeof(*data),0);

     
}


void
print_bits8( const uint8_t value )
{
    int i = 7;
    printf("b");
    do
    {
        printf("%c", value & (1<<i) ? '1' : '0');
    }
    while( i-- );
}

void
print_bits16( const uint16_t value )
{
    int i = 15;
    printf("b");
    do
    {
        printf("%c", value & (1<<i) ? '1' : '0');
    }
    while( i-- );
}
 
 
int cp210x_get_port_config(int device,struct cp210x_port_config_t *data)
{
    int result;

    /* Issue the request, attempting to read 'size' bytes */
    //result = cp2103_usb_control_msg(
    //    CP210X_SPECIFIC, REQTYPE_DEVICE_TO_HOST, PORT_CONFIG, 0,
    //    data, sizeof(*data));

    result = USBControlTransfer(device,
         REQTYPE_DEVICE_TO_HOST, CP210X_SPECIFIC, PORT_CONFIG, 0,
         (u8*)data, sizeof(*data),0);

    if (result != sizeof(*data)) {
        printf("Unable to get port_config, result = %d", result);
        return -1;
    }

    printf("reset: mode = 0x%04X, low_power = 0x%04X, latch = 0x%04X"
        " - supend: mode = 0x%04X, low_power = 0x%04X, latch = 0x%04X"
        " - enhanced_fxn: 0x%02X",
        data->reset.mode, data->reset.low_power, data->reset.latch,
        data->suspend.mode, data->suspend.low_power,
        data->suspend.latch, data->enhanced_fxn
        );

    return 0;
}

int cp210x_set_port_config(int device,struct cp210x_port_config_t *data)
{
    int result;

    printf("reset: mode = 0x%04X, low_power = 0x%04X, latch = 0x%04X"
        " - supend: mode = 0x%04X, low_power = 0x%04X, latch = 0x%04X"
        " - enhanced_fxn: 0x%02X",
        data->reset.mode, data->reset.low_power, data->reset.latch,
        data->suspend.mode, data->suspend.low_power,
        data->suspend.latch, data->enhanced_fxn
        );

    /* Issue the request, attempting to read 'size' bytes */
//    result = cp2103_usb_control_msg(
//        CP210X_SPECIFIC, REQTYPE_HOST_TO_DEVICE, PORT_CONFIG, 0,
//        data, sizeof(*data));

    result = USBControlTransfer(device,
         REQTYPE_HOST_TO_DEVICE, CP210X_SPECIFIC, PORT_CONFIG, 0,
         (u8*)data, sizeof(*data),0);



    if (result != sizeof(*data)) {
        printf("Unable to set port_config, result = %d", result);
        return -1;
    }

    return 0;
}

static int cp210x_set_config_single(int device,
        u8 request, unsigned int data)
{
    return cp210x_set_config(device, request, &data, 2);
}

static int cp210x_read_gpio(int device, int offset)
{
    int result;
    u8 *data;
    /* Issue the request, attempting to read 'size' bytes */
    //result = cp210x_control_msg(serial,
    //    CP210X_SPECIFIC, REQTYPE_DEVICE_TO_HOST, GPIO_READ,
    //    0, data, sizeof(*data));

    result = USBControlTransfer(device,
         REQTYPE_DEVICE_TO_HOST, CP210X_SPECIFIC, GPIO_READ, 0,
         (u8*)data, sizeof(*data),0);


    if (result != sizeof(*data)) {
        printf("%s: Unable to read gpio latch, ");
        return -1;
    }

    printf("\n\rread latch value = 0x%02X", *data);
print_bits8(*data);
    return 0;// data & (1<<(offset & 0x0F));
}

static int cp210x_write_gpio(int device, const u8 mask,
        const u8 value)
{
    
    int result;

    printf("writing to latch mask = 0x%02X, value = 0x%02X", mask, value);

    //result = cp210x_control_msg(serial,
    //    CP210X_SPECIFIC, REQTYPE_HOST_TO_DEVICE, GPIO_WRITE,
    //    (value << 8) | mask, NULL, 0);

    u8 val = (value << 8)| mask ;
    result = USBControlTransfer(device,
         REQTYPE_HOST_TO_DEVICE, CP210X_SPECIFIC, GPIO_WRITE,  
         (value << 8)| mask,
         0, NULL,0);

    if (result < 0) {
        printf( "%s: Unable to write into gpio latch, ");
        return -1;
    }

    return 0;
}

static void cp210x_gpio_set(int device,
    unsigned offset, int value)
{
    (void)cp210x_write_gpio(device,
        (1<<(offset & 0x0F)), value ? 0xFF : 0x00);
}
static int cp210x_gpio_input_mask(int device, u8 mask)
{
    struct cp210x_port_config_t config = {};
    int result;

    mask &= 0x0F;

    /* configure masked gpio as open-drain and set masked latch bits */
    result = cp210x_get_port_config(device, &config);
    if (result == 0) {
        config.reset.mode &= ~(((u16)mask)<<8);
        config.reset.latch |=  ((u16)mask)<<8;
        config.suspend.mode &= ~(((u16)mask)<<8);
        config.suspend.latch |= ((u16)mask)<<8;
        result = cp210x_set_port_config(device, &config);
    }
    return result;
}

static int cp210x_gpio_output_mask(int device, u8 mask)
{
    struct cp210x_port_config_t config = {};
    int result;

    mask &= 0x0F;

    /* configure masked gpio as push-pull */
    result = cp210x_get_port_config(device, &config);
    if (result == 0) {
        config.reset.mode |= ((u16)mask)<<8;
        config.suspend.mode |= ((u16)mask)<<8;
        result = cp210x_set_port_config(device, &config);
    }
    return result;
}


void
dump_port_config( const struct cp210x_port_config_t config )
{
    int i;
    printf("--- Dump of port configuration --- \n\r");
    printf("Raw data:\n\r");
    printf("reset.mode        = 0x%04X ", config.reset.mode);
    print_bits16(config.reset.mode); printf("\n\r");
    printf("reset.low_power   = 0x%04X ", config.reset.low_power);
    print_bits16(config.reset.low_power); printf("\n\r");
    printf("reset.latch       = 0x%04X ", config.reset.latch);
    print_bits16(config.reset.latch); printf("\n\r");
    printf("suspend.mode      = 0x%04X ", config.suspend.mode);
    print_bits16(config.suspend.mode); printf("\n\r");
    printf("suspend.low_power = 0x%04X ", config.suspend.low_power);
    print_bits16(config.suspend.low_power); printf("\n\r");
    printf("suspend.latch     = 0x%04X ", config.suspend.latch);
    print_bits16(config.suspend.latch); printf("\n\r");
    printf("enhanced_fxn      = 0x%02X ", config.enhanced_fxn);
    print_bits8(config.enhanced_fxn); printf("\n\r");
    printf("\n\r");
    printf("Configuration applied on after reset / suspend (mode, low_power, latch):\n\r");
    for ( i=0; i<16; i++ )
    {
        printf("%-20s %s   %s/%s %c/%c %c/%c\n\r",
            pin_names[i],
            ((config.reset.mode & (1<<i)) == 0 && (config.reset.latch & (1<<i))) ? "IN " : "OUT",
            (config.reset.mode & (1<<i)) ? " Push-Pull" : "Open-Drain",
            (config.suspend.mode & (1<<i)) ? "Push-Pull " : "Open-Drain",
            (config.reset.low_power & (1<<i)) ? '1' : '0',
            (config.suspend.low_power & (1<<i)) ? '1' : '0',
            (config.reset.latch & (1<<i)) ? '1' : '0',
            (config.suspend.latch & (1<<i)) ? '1' : '0');
    }
    printf("\n\r");
    printf("Enhanced functions:\n\r");
    for ( i=0; i<8; i++ )
    {
        printf("%-24s %s\n\r",
            fxn_names[i],
            (config.enhanced_fxn & (1<<i)) ? "ENABLED" : "DISABLED");
    }
    printf("--- End of Dump --- \n\r");
    printf("\n\r");
}




int OnCP210xInsert(int device)
{
    printf("CP210x inserted of %d\n",device);

    struct cp210x_port_config_t *data;

       int result;
       u16 *tes;

   result = cp210x_get_port_config( device,data);



   
    
   // for (i = 0; i <  sizeof(*data); i++)
     //   data[i] = le32_to_cpu(data[i]);

    printf("reset: mode = 0x%04X, low_power = 0x%04X, latch = 0x%04X"
        " - supend: mode = 0x%04X, low_power = 0x%04X, latch = 0x%04X"
        " - enhanced_fxn: 0x%02X --------------------------------------------------",
        data->reset.mode, data->reset.low_power, data->reset.latch,
        data->suspend.mode, data->suspend.low_power,
        data->suspend.latch, data->enhanced_fxn
        );
printf(" HERE \n\r");

dump_port_config(*data);

 //   if (cp210x_set_config_single(device, CP210X_IFC_ENABLE, UART_ENABLE)) {
  //      printf(" Unable to enable UART\n");
        
  //  }
  cp210x_gpio_output_mask(device,0xf);
  cp210x_read_gpio(device,0);cp210x_read_gpio(device,1);cp210x_read_gpio(device,2);cp210x_read_gpio(device,3);

  cp210x_gpio_set(device,0,0xff);
   cp210x_gpio_set(device,1,0x0);
   
  cp210x_gpio_set(device,2,0xff);
   cp210x_gpio_set(device,3,0x0);
   
 // cp210x_gpio_set(device,2,0xff);
  // cp210x_gpio_set(device,3,0xf);
   
  cp210x_read_gpio(device,0);cp210x_read_gpio(device,1);cp210x_read_gpio(device,2);cp210x_read_gpio(device,3);
  
printf(" HERE2 \n\r");
   result = cp210x_get_port_config( device,data);
dump_port_config(*data);
    return 0;
}


int OnFTDIInsert(int device);   

void OnLoadDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc)
{
    printf("LoadDevice %d %02X:%02X:%02X\n",device,interfaceDesc->bInterfaceClass,interfaceDesc->bInterfaceSubClass,interfaceDesc->bInterfaceProtocol);
    char s[128];
    for (int i = 1; i < 3; i++)
    {
        if (GetString(device,i,s,sizeof(s)) < 0)
            break;
        printf("%d: %s\n",i,s);
    }
    
    switch (interfaceDesc->bInterfaceClass)
    {
        case CLASS_MASS_STORAGE:
            if (interfaceDesc->bInterfaceSubClass == 0x06 && interfaceDesc->bInterfaceProtocol == 0x50)
                OnDiskInsert(device);    // it's SCSI!
            break;
        case CLASS_WIRELESS_CONTROLLER:
            if (interfaceDesc->bInterfaceSubClass == 0x01 && interfaceDesc->bInterfaceProtocol == 0x01)
                OnBluetoothInsert(device);    // it's bluetooth!
            break;
        case CLASS_VENDOR_SPECIFIC:
            //Silicon Labs CP210x
            if (interfaceDesc->bInterfaceSubClass == 0x00 && interfaceDesc->bInterfaceProtocol == 0x00) {
                OnCP210xInsert(device);  
                
                }
            //FTDI Serial
            if (interfaceDesc->bInterfaceSubClass == 0xFF && interfaceDesc->bInterfaceProtocol == 0xFF)
                OnFTDIInsert(device);   
            break;
        default:
            StartAutoEvent(device,1,0);
            break;
    }
}