www.pudn.com > Usb_Project.rar > usb_diag_lib.c


//////////////////////////////////////////////////////////////// 
// File - USB_DIAG_LIB.C 
// 
// Utility functions for communication with USB devices  
// using WinDriver's API. 
//  
// Copyright (c) 2003 - 2004 Jungo Ltd.  http://www.jungo.com 
//  
//////////////////////////////////////////////////////////////// 
 
// use in wizard's device-specific generated code 
#include "c:\windriver/include/wdu_lib.h" 
#include "c:\windriver/include/status_strings.h" 
#include "c:\windriver/include/utils.h" 
#include "c:\windriver/samples/shared/usb_diag_lib.h" 
 
#include  
#include  
#include  
#include  
#include  
 
#ifdef _USE_SPECIFIC_KERNEL_DRIVER_ 
    #undef WD_Open 
    #define WD_Open WD_OpenKernelHandle 
    #if defined(UNIX) 
        #undef WD_FUNCTION 
        #define WD_FUNCTION(wFuncNum,h,pParam,dwSize,fWait) ((ULONG) ioctl((int)(h), wFuncNum, pParam)) 
    #endif 
#endif 
#include "usb_diag_lib.h" 
#include  
#include  
#include  
 
#if !defined(ERR) 
#define ERR printf 
#endif 
 
#define TRANSFER_TIMEOUT 30000 // in msecs 
 
 
static FILE * log_file = NULL; 
static HANDLE _g_hDevice; 
 
typedef struct   
{ 
    DWORD dwListenPipeNum; 
    DWORD dwWritePipeNum; 
    HANDLE hDevice; 
    DWORD dwPacketSize; 
    PVOID pContext; 
    BOOL fStopped; 
    HANDLE hThread; 
    DWORD dwError; 
} USB_LISTEN_PIPE; 
 
static USB_LISTEN_PIPE ListenPipe; 
 
// Function: CloseListening() 
//   Stop listening to USB device pipe 
void CloseListening(USB_LISTEN_PIPE *pListenPipe); 
 
// Function: ListenToPipe() 
//   Start listening to a USB device pipe 
void ListenToPipe(USB_LISTEN_PIPE *pListenPipe); 
 
// Function: pipeType2Str() 
//   Returns a string identifying the pipe type 
// Parameters: 
//   pipeType [in] pipe type 
// Return Value: 
//   String containing the description of the pipe 
char *pipeType2Str(ULONG pipeType) 
{ 
    char *res = "unknown"; 
    switch (pipeType) 
    { 
        case PIPE_TYPE_CONTROL:  
            res = "Control"; 
            break; 
        case PIPE_TYPE_ISOCHRONOUS: 
            res = "Isochronous"; 
            break;           
        case PIPE_TYPE_BULK: 
            res = "Bulk"; 
            break; 
        case PIPE_TYPE_INTERRUPT: 
            res = "Interrupt"; 
            break; 
    } 
    return res; 
} 
 
void PrintTime(unsigned char * str) 
{ 
    char datetime_buf[10]; 
    struct _timeb tstruct; 
     
    /* Display operating system-style date and time. */ 
    _strtime( datetime_buf); 
    printf( "\n %s %s", str, datetime_buf ); 
 
    _ftime( &tstruct ); 
    printf(  ".%3.3u", tstruct.millitm ); 
 
    _strdate( datetime_buf); 
    printf( " Date: %s \n", datetime_buf ); 
 
} 
 
void LogTime(unsigned char * str) 
{ 
    char datetime_buf[10]; 
    struct _timeb tstruct; 
     
    /* Display operating system-style date and time. */ 
    _strtime( datetime_buf); 
    fprintf(log_file, "\n %s %s", str, datetime_buf ); 
 
    _ftime( &tstruct ); 
    fprintf(log_file, ".%3.3u", tstruct.millitm ); 
 
    _strdate( datetime_buf); 
    fprintf(log_file, " Date: %s \n", datetime_buf ); 
     
} 
 
 
/* frame received 
*/ 
unsigned long  recv_frame_buf[16]; 
#define recv_frame_len recv_frame_buf[15] 
 
unsigned long  send_frame_buf[16]; 
#define send_frame_len send_frame_buf[15] 
 
 
// input of command from user 
static char line[256]; 
 
#define BYTES_IN_LINE 16 
#define HEX_CHARS_PER_BYTE 3 
#define HEX_STOP_POS BYTES_IN_LINE*HEX_CHARS_PER_BYTE 
 
// Function: PrintHexBuffer() 
//   Print a buffer in HEX format 
// Parameters: 
//   pBuffer [in] pointer to buffer 
//   dwBytes [in] number of bytes to print 
// Return Value: 
//   None 
void PrintHexBuffer(PVOID pBuffer, DWORD dwBytes) 
{ 
    PBYTE pData = (PBYTE) pBuffer; 
    CHAR pHex[HEX_STOP_POS+1]; 
    CHAR pAscii[BYTES_IN_LINE+1]; 
    DWORD offset; 
    DWORD i; 
     
    if (!dwBytes) 
    { 
        printf("\nNULL\n"); 
        return; 
    } 
    for (offset=0; offset=0x20) ? pData[offset] : '.'); 
    } 
 
    // print the last line. fill with blanks if needed 
    if (offset%BYTES_IN_LINE) 
    { 
        for (i=(offset%BYTES_IN_LINE)*HEX_CHARS_PER_BYTE; ihThread) 
        return; 
 
    printf("Stop listening to pipe\n"); 
    pListenPipe->fStopped = TRUE; 
 
    WDU_HaltTransfer(pListenPipe->hDevice, pListenPipe->dwListenPipeNum); 
 
    ThreadWait(pListenPipe->hThread); 
    pListenPipe->hThread = NULL; 
} 
 
 
void OpenLogFile(const char * fname) 
{ 
    char datetime_buf[10]; 
     
    if(log_file == NULL) 
    { 
        log_file = fopen( fname, "a"); 
 
        if(log_file == NULL) 
        { 
            printf("Open log file fail\n"); 
        } 
        else 
        { 
            _strdate( datetime_buf); 
            fprintf(log_file,  "-------------- Date: %s ", datetime_buf ); 
 
            _strtime( datetime_buf); 
            fprintf(log_file,  "Time: %s -------------\n", datetime_buf ); 
        } 
    } 
} 
 
void CloseLogFile(void) 
{ 
    if(log_file != NULL) 
    { 
        fclose(log_file);     
        log_file = NULL; 
    } 
} 
 
// Function: PrintHexBuffer() 
//   Print a buffer in HEX format 
// Parameters: 
//   pBuffer [in] pointer to buffer 
//   dwBytes [in] number of bytes to print 
// Return Value: 
//   None 
void LogHexBuffer(PVOID pBuffer, DWORD dwBytes) 
{ 
    PBYTE pData = (PBYTE) pBuffer; 
    CHAR pHex[HEX_STOP_POS+1]; 
    CHAR pAscii[BYTES_IN_LINE+1]; 
    DWORD offset; 
    DWORD i; 
     
    if (!dwBytes) 
    { 
        fprintf(log_file, "\nNULL\n"); 
        return; 
    } 
    for (offset=0; offset=0x20) ? pData[offset] : '.'); 
    } 
 
    // print the last line. fill with blanks if needed 
    if (offset%BYTES_IN_LINE) 
    { 
        for (i=(offset%BYTES_IN_LINE)*HEX_CHARS_PER_BYTE; idwWritePipeNum, 0, 0,  
            send_ptr, (send_frame_len>16) ? 16 : send_frame_len, &dwBytesTransferred, SetupPacket, TRANSFER_TIMEOUT); 
 
        if(dwBytesTransferred <= 16) 
        { 
            send_frame_len -= dwBytesTransferred; 
        } 
        else 
        { 
            //impossible 
            send_frame_len = 0; 
        } 
 
        if(frame_finished) 
        { 
            frame_finished = 0; 
 
            /* Display operating system-style date and time. */ 
            LogTime("TX Time:"); 
        } 
         
        if(dwError) 
        { 
            // 
            if(log_file)  
            { 
                fprintf(log_file, "PipeSend error code %X\n", dwError); 
            } 
            printf("PipeSend error code %X\n", dwError); 
 
            break; 
        } 
        else 
        { 
            LogHexBuffer(send_ptr, dwBytesTransferred); 
        } 
 
        send_ptr += dwBytesTransferred; 
 
        totalTransferred += dwBytesTransferred; 
 
        if(dwBytesTransferred != 16) 
        { 
            frame_finished = 1; 
        } 
         
    } 
     
    return totalTransferred; 
     
} 
 
extern int RF_USB_recv_frame(unsigned char * frame, unsigned int flen); 
 
 
int RF_USB_send_frame(unsigned char * frame, unsigned int flen) 
{ 
    int rc = 0; 
 
    if(_g_hDevice == NULL) 
    { 
        return -1; 
    } 
 
    if(!frame) 
    { 
        return -1; 
    } 
 
    if(flen > (sizeof(send_frame_buf)-sizeof(long))) 
    { 
        return -1; 
    } 
 
    memcpy(((unsigned char *)&send_frame_buf[0]), frame, flen); 
    send_frame_len = flen; 
     
    if(ListenPipe.hDevice) 
    { 
        WDU_HaltTransfer(ListenPipe.hDevice, ListenPipe.dwListenPipeNum); 
    } 
     
    return rc; 
     
} 
 
typedef int (* RF_USB_RTS_FUNC)(void); 
 
RF_USB_RTS_FUNC RF_USB_RTS; 
 
// Function: PipeHandlerThread() 
//   Callback function, which listens to a pipe continuously when there is data  
//   available in the pipe 
// Parameters: 
//   pParam [in] contains the relevant pipe information 
// Return Value: 
//   None 
void DLLCALLCONV PipeHandlerThread(void * pParam) 
{ 
    static DWORD dwErrorLast; 
    DWORD dwError; 
    USB_LISTEN_PIPE *pListenPipe = (USB_LISTEN_PIPE*) pParam; 
    PVOID buf = malloc(pListenPipe->dwPacketSize); 
         
    DWORD frame_finished = 1; 
    DWORD dwBytesTransferred; 
 
    int rc; 
 
    for (;;) 
    { 
 
        if(send_frame_len) 
        { 
            PipeSend(pParam); 
 
            recv_frame_len = 0; 
        } 
         
        dwError = WDU_Transfer(pListenPipe->hDevice, pListenPipe->dwListenPipeNum, 
            TRUE, 0, buf, pListenPipe->dwPacketSize,  
            &dwBytesTransferred, NULL, TRANSFER_TIMEOUT); 
         
        if (pListenPipe->fStopped) 
        { 
            if(log_file)  
            { 
                fprintf(log_file, "Stoped\n"); 
            } 
            printf("Stoped\n"); 
            break; 
        } 
 
        if (dwError) 
        { 
            if(dwError == WD_IRP_CANCELED) 
            { 
                continue; 
            } 
            if(dwError == WD_TIME_OUT_EXPIRED) 
            { 
            } 
            else if(dwError == WD_DEVICE_NOT_FOUND) 
            { 
            } 
            else if(dwErrorLast != dwError) 
            { 
                if(log_file)  
                { 
                    fprintf(log_file, "PipeHandlerThread error code %X\n", dwError); 
                } 
                printf("PipeHandlerThread error code %X\n", dwError); 
            } 
            pListenPipe->dwError = dwError; 
        } 
        else 
        { 
            if((dwBytesTransferred == 0) && (recv_frame_len == 0)) 
            { 
                if(RF_USB_RTS) 
                { 
                    RF_USB_RTS(); 
                } 
                continue; 
            } 
             
            if(frame_finished) 
            { 
                frame_finished = 0; 
 
                /* Display operating system-style date and time. */ 
 
                LogTime("RX Time:"); 
            } 
 
            LogHexBuffer(buf, dwBytesTransferred);; 
//            PrintHexBuffer(buf, dwBytesTransferred); 
 
            if((recv_frame_len + dwBytesTransferred) > (sizeof(recv_frame_buf)-sizeof(long))) 
            { 
                recv_frame_len = 0; 
            } 
 
            memcpy(((unsigned char *)&recv_frame_buf[0])+recv_frame_len, buf, dwBytesTransferred); 
                 
            recv_frame_len += dwBytesTransferred; 
 
            if(dwBytesTransferred != 16) 
            { 
                rc = RF_USB_recv_frame((unsigned char *)&recv_frame_buf[0], recv_frame_len); 
 
                if(rc != 0) 
                { 
                    printf("CRC ERROR\n"); 
                } 
                 
                recv_frame_len = 0; 
                frame_finished = 1; 
            } 
        } 
 
        //flush file 
        fflush(log_file); 
         
    } 
    free(buf); 
} 
 
 
// Function: ListenToPipe() 
//   Start listening to a USB device pipe 
// Parameters: 
//   pListenPipe [in] pipe to listen to 
// Return Value: 
//   None 
void ListenToPipe(USB_LISTEN_PIPE *pListenPipe) 
{ 
    // start the running thread 
    pListenPipe->fStopped = FALSE; 
    printf("Start listening to pipe\n"); 
 
    pListenPipe->dwError = ThreadStart(&pListenPipe->hThread,  
        PipeHandlerThread, (PVOID) pListenPipe); 
} 
 
// Function: ListenToPipe() 
//   Start listening to a USB device pipe 
// Parameters: 
//   pListenPipe [in] pipe to listen to 
// Return Value: 
//   None 
void Start_ListenToPipe(DWORD PipeNum) 
{ 
    HANDLE hDevice = _g_hDevice; 
    WDU_DEVICE *pDevice; 
    USB_LISTEN_PIPE *pListenPipe = & ListenPipe; 
 
    DWORD dwError; 
    WDU_ALTERNATE_SETTING *pAltSet; 
    WDU_PIPE_INFO *pPipes; 
 
    BYTE i=0; 
 
    if(hDevice == NULL) 
    { 
        //no device found 
        return; 
    } 
 
    if(ListenPipe.hDevice != NULL) 
    { 
        //already started 
        return; 
    } 
         
    dwError = WDU_GetDeviceInfo(hDevice, &pDevice); 
    if (dwError) 
    { 
        ERR("ReadWritePipesMenu: WDU_GetDeviceInfo() failed: error 0x%lx (\"%s\")\n", 
            dwError, Stat2Str(dwError)); 
        return; 
    } 
 
    pAltSet = pDevice->pActiveInterface->pActiveAltSetting; 
    pPipes = pAltSet->pPipes; 
 
    // search for the pipe 
    if (PipeNum) 
    { 
        for (i=0; iDescriptor.bNumEndpoints; i++) 
            if (pPipes[i].dwNumber==PipeNum) 
                break; 
        if (i >= pAltSet->Descriptor.bNumEndpoints) 
        { 
            printf("The pipe number 0x%lx does not exist.\n", PipeNum); 
            return; 
        } 
    } 
 
 
    BZERO(ListenPipe); 
     
    ListenPipe.dwListenPipeNum = PipeNum; 
    ListenPipe.dwWritePipeNum = PipeNum & (~0x80); 
     
    ListenPipe.hDevice = hDevice; 
    ListenPipe.dwPacketSize = pPipes[i].dwMaximumPacketSize; 
     
    // start the running thread 
    pListenPipe->fStopped = FALSE; 
    printf("Start listening to pipe\n"); 
 
    recv_frame_len = 0; 
    send_frame_len = 0; 
    pListenPipe->dwError = ThreadStart(&pListenPipe->hThread,  
        PipeHandlerThread, (PVOID) pListenPipe); 
     
} 
 
void Stop_ListenToPipe(DWORD PipeNum) 
{ 
    USB_LISTEN_PIPE *pListenPipe = & ListenPipe; 
 
    if(ListenPipe.hDevice) 
    { 
        CloseListening(pListenPipe); 
 
        ListenPipe.hDevice = NULL; 
    }     
} 
 
// Function: GetHexChar(void) 
//   Get next character from user 
// Parameters: 
//   None 
// Return Value: 
//   Character received 
int GetHexChar(void) 
{ 
    int ch; 
 
    ch = getchar(); 
 
    if (!isxdigit(ch)) 
        return -1; 
 
    if (isdigit(ch)) 
        return ch - '0'; 
    else 
        return toupper(ch) - 'A' + 10; 
} 
 
// Function: GetHexBuffer() 
//   Get hex buffer from user 
// Parameters: 
//   pBuffer [in] pointer to buffer 
//   dwBytes [in] length of buffer 
// Return Value: 
//   Size of buffer received 
DWORD GetHexBuffer(PVOID pBuffer, DWORD dwBytes) 
{ 
    DWORD i; 
    PBYTE pData = (PBYTE)pBuffer; 
    int res; 
    int ch; 
 
    for (i=0; iDescriptor.bNumEndpoints) 
    { 
        printf("  no pipes are defined for this device other than the default pipe (number 0).\n"); 
        return; 
    } 
    for (p=0; pDescriptor.bNumEndpoints; p++) 
    { 
        pPipe = &pAltSet->pPipes[p]; 
 
        printf("  pipe num. 0x%lx: packet size %ld, type %s, dir %s, interval %ld (ms)\n", 
            pPipe->dwNumber, 
            pPipe->dwMaximumPacketSize, 
            pipeType2Str(pPipe->type), 
            pPipe->direction==WDU_DIR_IN ? "In" : pPipe->direction==WDU_DIR_OUT ? "Out" : "In & Out", 
            pPipe->dwInterval); 
    } 
} 
 
static void PrintEndpoints(WDU_ALTERNATE_SETTING *pAltSet) 
{ 
    BYTE endp; 
    WDU_ENDPOINT_DESCRIPTOR *pEndp; 
 
    for (endp=0; endpDescriptor.bNumEndpoints; endp++) 
    { 
        pEndp = &pAltSet->pEndpointDescriptors[endp]; 
        printf("    end-point address: 0x%02x, attributes: 0x%x, max packet %d, Interval: %d\n", 
            pEndp->bEndpointAddress, 
            pEndp->bmAttributes, 
            pEndp->wMaxPacketSize, 
            pEndp->bInterval); 
    } 
} 
 
// Function: PrintDeviceConfigurations() 
//   Prints the device's configurations information 
// Parameters: 
//   hDevice [in] handle to the USB device 
// Return Value: 
//   None 
void PrintDeviceConfigurations(HANDLE hDevice) 
{ 
    DWORD dwError; 
    WDU_DEVICE *pDevice = NULL; 
    DWORD ifc, alt; 
    UINT32 iConf; 
 
    WDU_CONFIGURATION *pConf; 
    WDU_INTERFACE *pInterface; 
    WDU_ALTERNATE_SETTING *pAltSet; 
 
    dwError = WDU_GetDeviceInfo(hDevice, &pDevice); 
    if (dwError) 
    { 
        ERR("PrintDeviceConfigurations: WDU_GetDeviceInfo failed: error 0x%lx (\"%s\")\n", 
            dwError, Stat2Str(dwError)); 
        goto Exit; 
    } 
 
    printf("This device has %d configurations:\n", pDevice->Descriptor.bNumConfigurations); 
    for (iConf=0; iConfDescriptor.bNumConfigurations; iConf++) 
    { 
        printf("  %d. configuration value %d (has %ld interfaces)\n",  
            iConf, pDevice->pConfigs[iConf].Descriptor.bConfigurationValue, 
            pDevice->pConfigs[iConf].dwNumInterfaces); 
    } 
    iConf = 0; 
    if (pDevice->Descriptor.bNumConfigurations>1) 
    { 
        printf("Please enter the configuration index to display (dec - zero based): "); 
        fgets(line, sizeof(line), stdin); 
        sscanf(line, "%d", &iConf); 
        if (iConf >= pDevice->Descriptor.bNumConfigurations) 
        { 
            printf("ERROR: invalid configuration index, valid values are 0-%d\n", 
                pDevice->Descriptor.bNumConfigurations); 
            goto Exit; 
        } 
    } 
    pConf = &pDevice->pConfigs[iConf]; 
 
    printf("The configuration indexed %d has %ld interface(s):\n", 
        iConf, pConf->dwNumInterfaces); 
 
    for (ifc=0; ifcdwNumInterfaces; ifc++) 
    { 
        pInterface = &pConf->pInterfaces[ifc]; 
        printf("interface no. %d:\n",  
            pInterface->pAlternateSettings[0].Descriptor.bInterfaceNumber); 
        for (alt=0; altdwNumAltSettings; alt++) 
        { 
            pAltSet = &pInterface->pAlternateSettings[alt]; 
 
            printf("  alternate: %d, endpoints: %d, class: 0x%x, subclass: 0x%x, protocol: 0x%x\n", 
                pAltSet->Descriptor.bAlternateSetting, 
                pAltSet->Descriptor.bNumEndpoints, 
                pAltSet->Descriptor.bInterfaceClass, 
                pAltSet->Descriptor.bInterfaceSubClass, 
                pAltSet->Descriptor.bInterfaceProtocol); 
 
            PrintEndpoints(pAltSet); 
        } 
        printf("\n"); 
    } 
    printf("\n"); 
 
Exit: 
    if (pDevice) 
        WDU_PutDeviceInfo(pDevice); 
} 
 
// Function: ReadWritePipesMenu() 
//   Displays menu to read/write from the device's pipes 
// Parameters: 
//   hDevice [in] handle to the USB device 
// Return Value: 
//   None 
void ReadWritePipesMenu(HANDLE hDevice) 
{ 
    DWORD dwError; 
    WDU_DEVICE *pDevice; 
    WDU_ALTERNATE_SETTING *pAltSet; 
    WDU_PIPE_INFO *pPipes; 
    BYTE  SetupPacket[8]; 
    DWORD cmd, dwPipeNum, dwSize, dwBytesTransferred; 
    BYTE i=0; 
    VOID *pBuffer; 
    USB_LISTEN_PIPE listenPipe; 
    int c; 
 
    dwError = WDU_GetDeviceInfo(hDevice, &pDevice); 
    if (dwError) 
    { 
        ERR("ReadWritePipesMenu: WDU_GetDeviceInfo() failed: error 0x%lx (\"%s\")\n", 
            dwError, Stat2Str(dwError)); 
        return; 
    } 
 
    pAltSet = pDevice->pActiveInterface->pActiveAltSetting; 
    pPipes = pAltSet->pPipes; 
 
    PrintPipesInfo(pAltSet); 
 
    do { 
        printf("\n"); 
        printf("Read/Write from/to device's pipes\n"); 
        printf("---------------------\n"); 
        printf("1.  Read from pipe\n"); 
        printf("2.  Write to pipe\n"); 
        printf("3.  Listen to pipe (contiguous read)\n"); 
        printf("99. Main menu\n"); 
        printf("Enter option: "); 
        cmd = 0; 
        fgets(line, sizeof(line), stdin); 
        sscanf(line, "%ld", &cmd); 
 
        if (cmd==99) 
            break; 
        if (cmd<1 || cmd>3) 
            continue; 
 
        printf("Please enter the pipe number (hex): 0x"); 
        fgets(line, sizeof(line), stdin); 
        dwPipeNum=0; 
        sscanf(line, "%lx", &dwPipeNum); 
 
        // search for the pipe 
        if (dwPipeNum) 
        { 
            for (i=0; iDescriptor.bNumEndpoints; i++) 
                if (pPipes[i].dwNumber==dwPipeNum) 
                    break; 
            if (i >= pAltSet->Descriptor.bNumEndpoints) 
            { 
                printf("The pipe number 0x%lx does not exist, please try again.\n", dwPipeNum); 
                continue; 
            } 
        } 
 
        switch (cmd) 
        { 
        case 1: 
        case 2: 
            if (!dwPipeNum || pPipes[i].type==PIPE_TYPE_CONTROL) 
            { 
                printf("Please enter setup packet (hex - 8 bytes): "); 
                GetHexBuffer((PVOID) SetupPacket, 8); 
            } 
            printf("Please enter the size of the buffer (dec):  "); 
            fgets(line, sizeof(line), stdin); 
            sscanf(line, "%ld", &dwSize); 
            pBuffer = malloc(dwSize); 
            if (!pBuffer) 
            { 
                ERR("cannot alloc memory\n"); 
                break; 
            } 
 
            if (cmd==2) 
            { 
                printf("Please enter the input buffer (hex): "); 
                GetHexBuffer(pBuffer, dwSize); 
            } 
            dwError = WDU_Transfer(hDevice, dwPipeNum? pPipes[i].dwNumber : 0, cmd==1, 0, pBuffer,  
                dwSize, &dwBytesTransferred, SetupPacket, TRANSFER_TIMEOUT); 
            if (dwError) 
                ERR("ReadWritePipesMenu: WDU_Transfer() failed: error 0x%lx (\"%s\")\n", 
                    dwError, Stat2Str(dwError)); 
            else 
            { 
                printf("Transferred %ld bytes\n", dwBytesTransferred); 
                if (cmd==1) 
                    PrintHexBuffer(pBuffer, dwBytesTransferred); 
            } 
            free(pBuffer); 
            break; 
 
        case 3: 
            if (!dwPipeNum || pPipes[i].type==PIPE_TYPE_CONTROL) 
            { 
                printf("Cannot listen to control pipes.\n"); 
                break; 
            } 
            BZERO(listenPipe); 
            listenPipe.dwListenPipeNum = dwPipeNum; 
            listenPipe.hDevice = hDevice; 
            listenPipe.dwPacketSize = pPipes[i].dwMaximumPacketSize; 
 
            printf("Press  to start listening. While listening, press  to stop\n\n"); 
            getchar(); 
            ListenToPipe(&listenPipe); 
            if (listenPipe.dwError) 
            { 
                ERR("ReadWritePipesMenu: error listening to pipe 0x%lx: error 0x%lx (\"%s\")\n", 
                    dwPipeNum, listenPipe.dwError, Stat2Str(listenPipe.dwError)); 
                break; 
            } 
 
            while ((c=getchar())!=10) {}   // ESC code 
            CloseListening(&listenPipe); 
            if (listenPipe.dwError) 
                ERR("ReadWritePipesMenu: WDU_Transfer failed: error 0x%lx (\"%s\")\n", 
                    listenPipe.dwError, Stat2Str(listenPipe.dwError)); 
            break; 
        } 
    } while (1); 
 
    if (pDevice) 
        WDU_PutDeviceInfo(pDevice); 
}