⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbcdc.c

📁 超简单AVRUSB软件模似串口(COMx)数据发送、接收。
💻 C
字号:

/* Name: usbcdc.c
 * Project: AVR USB driver for CDC interface on Low-Speed USB
 * Author: Osamu Tamura
 * Creation Date: 2006-05-12
 * Tabsize: 4
 * Copyright: (c) 2006 by Recursion Co., Ltd.
 * License: Proprietary, free under certain conditions. See Documentation.
 *
 * 2006-07-08   removed zero-sized receive block
 * 2006-07-08   adapted to higher baud rate by T.Kitazawa
 *
 */

#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>

#include "usbdrv.h"
#include "usbcdc.h"

#define USE_MODEBUF
/* ------------------------------------------------------------------------- */
/*	---------------------- Type Definition --------------------------------- */
/* ------------------------------------------------------------------------- */
typedef union usbDWord {
    ulong	dword;
    uchar   bytes[4];
} usbDWord_t;


volatile uchar    urptr, uwptr, irptr, iwptr;
uchar    rx_buf[RX_SIZE], tx_buf[TX_SIZE];

uint8_t sendEmptyFrame;

static inline void  uartTxBufAppend(uchar c)
{
uchar   uwnxt;

    uwnxt = (uwptr+1) & TX_MASK;
    if( uwnxt==irptr )
        return;         /* buffer overflow */
    tx_buf[uwptr] = c;
    uwptr = uwnxt;
}

/* The following function returns the amount of bytes available in the TX
 * buffer before we have an overflow.
 */
static inline uchar uartTxBytesFree(void)
{
    return (irptr - uwptr - 1) & TX_MASK;
}

/* The following function sets *ptr to the current read position and returns
 * the number of bytes which can currently be read from this read position.
 */
static inline uchar uartRxBytesAvailable(uchar **ptr)
{
    *ptr = &rx_buf[urptr];
    if(iwptr >= urptr){
        return iwptr - urptr;
    }else{  /* buffer end is between read and write pointer, return continuous range */
        return RX_SIZE - urptr;
    }
}

/* The following function must be called after uartRxBytesAvailable() to
 * remove the bytes from the receiver buffer.
 */
static inline void  uartRxDidReadBytes(uchar numBytes)
{
    urptr = (urptr + numBytes) & RX_MASK;
}


enum {
    SEND_ENCAPSULATED_COMMAND = 0,
    GET_ENCAPSULATED_RESPONSE,
    SET_COMM_FEATURE,
    GET_COMM_FEATURE,
    CLEAR_COMM_FEATURE,
    SET_LINE_CODING = 0x20,
    GET_LINE_CODING,
    SET_CONTROL_LINE_STATE,
    SEND_BREAK
};


char usbDescrConfig[] PROGMEM = {    /* USB configuration descriptor */
    9,          /* sizeof(usbDescrConfig): length of descriptor in bytes */
    USBDESCR_CONFIG,    /* descriptor type */
    USB_CFG_EXTERNAL_CONFIG_DESCRIPTOR_LENGH,
    0,          /* total length of data returned (including inlined descriptors) */
    2,          /* number of interfaces in this configuration */
    1,          /* index of this configuration */
    0,          /* configuration name string index */
#if USB_CFG_IS_SELF_POWERED
    USBATTR_SELFPOWER,  /* attributes */
#else
    USBATTR_BUSPOWER,   /* attributes */
#endif
    USB_CFG_MAX_BUS_POWER/2,            /* max USB current in 2mA units */

    /* interface descriptor follows inline: */
    9,          /* sizeof(usbDescrInterface): length of descriptor in bytes */
    USBDESCR_INTERFACE, /* descriptor type */
    0,          /* index of this interface */
    0,          /* alternate setting for this interface */
    USB_CFG_HAVE_INTRIN_ENDPOINT,   /* endpoints excl 0: number of endpoint descriptors to follow */
    USB_CFG_INTERFACE_CLASS,
    USB_CFG_INTERFACE_SUBCLASS,
    USB_CFG_INTERFACE_PROTOCOL,
    0,          /* string index for interface */

    /* CDC Class-Specific descriptor */
    5,           /* sizeof(usbDescrCDC_HeaderFn): length of descriptor in bytes */
    0x24,        /* descriptor type */
    0,           /* header functional descriptor */
    0x10, 0x01,

    4,           /* sizeof(usbDescrCDC_AcmFn): length of descriptor in bytes */
    0x24,        /* descriptor type */
    2,           /* abstract control management functional descriptor */
    0x02,        /* SET_LINE_CODING,    GET_LINE_CODING, SET_CONTROL_LINE_STATE    */

    5,           /* sizeof(usbDescrCDC_UnionFn): length of descriptor in bytes */
    0x24,        /* descriptor type */
    6,           /* union functional descriptor */
    0,           /* CDC_COMM_INTF_ID */
    1,           /* CDC_DATA_INTF_ID */

    5,           /* sizeof(usbDescrCDC_CallMgtFn): length of descriptor in bytes */
    0x24,        /* descriptor type */
    1,           /* call management functional descriptor */
    3,           /* allow management on data interface, handles call management by itself */
    1,           /* CDC_DATA_INTF_ID */

    /* Endpoint Descriptor */
    7,           /* sizeof(usbDescrEndpoint) */
    USBDESCR_ENDPOINT,  /* descriptor type = endpoint */
    0x83,        /* IN endpoint number 3 */
    0x03,        /* attrib: Interrupt endpoint */
    8, 0,        /* maximum packet size */
    100,         /* in ms */

    /* Interface Descriptor  */
    9,           /* sizeof(usbDescrInterface): length of descriptor in bytes */
    4,           /* descriptor type */
    1,           /* index of this interface */
    0,           /* alternate setting for this interface */
    2,           /* endpoints excl 0: number of endpoint descriptors to follow */
    0x0A,        /* Data Interface Class Codes */
    0,
    0,           /* Data Interface Class Protocol Codes */
    0,           /* string index for interface */

    /* Endpoint Descriptor */
    7,           /* sizeof(usbDescrEndpoint) */
    USBDESCR_ENDPOINT,  /* descriptor type = endpoint */
    0x01,        /* OUT endpoint number 1 */
    0x02,        /* attrib: Bulk endpoint */
#if UART_CFG_HAVE_USART
    6, 0,        /* maximum packet size 8->6 */
#else
    1, 0,        /* maximum packet size */
#endif
    0,           /* in ms */

    /* Endpoint Descriptor */
    7,           /* sizeof(usbDescrEndpoint) */
    USBDESCR_ENDPOINT,  /* descriptor type = endpoint */
    0x81,        /* IN endpoint number 1 */
    0x02,        /* attrib: Bulk endpoint */
    8, 0,        /* maximum packet size */
    0,           /* in ms */
};


#ifndef USE_DCD_REPORTING
#define USE_DCD_REPORTING 0
#endif
/* If this option is defined to 1, the driver will report carrier detect when
 * the serial device is opened. This is useful on some Unix platforms to allow
 * using the /dev/tty* instead of /dev/cu* devices.
 * Setting this option to 0 saves a couple of bytes in flash and RAM memory.
 */

#if USE_DCD_REPORTING
static uchar        intr3Status;    /* used to control interrupt endpoint transmissions */
#endif

#ifndef USE_MODEBUF
static const uchar stopbit = 0;
static const uchar parity  = 0;
static const uchar databit = 8;
static usbDWord_t   baud;
#else
static uchar    modeBuffer[7] = {0x80, 0x25, 0, 0, 0, 0, 8};
/* default: 9600 bps, 8n1 */
#endif

static inline void resetUart(void)
{
    irptr    = 0;
    iwptr    = 0;
    urptr    = 0;
    uwptr    = 0;
}

/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */

uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t    *rq = (void *)data;

    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS)
	{    /* class request type */

        if( rq->bRequest==GET_LINE_CODING || rq->bRequest==SET_LINE_CODING )
		{
            return 0xff;
        /*    GET_LINE_CODING -> usbFunctionRead()    */
        /*    SET_LINE_CODING -> usbFunctionWrite()    */
        }
        if(rq->bRequest == SET_CONTROL_LINE_STATE)
		{
            /* Report serial state (carrier detect). On several Unix platforms,
             * tty devices can only be opened when carrier detect is set.
             */
    	    sendEmptyFrame = 1;
#if USE_DCD_REPORTING
            intr3Status = 2;
#endif
        }
    }

    return 0;
}


/*---------------------------------------------------------------------------*/
/* usbFunctionRead                                                          */
/*---------------------------------------------------------------------------*/

uchar usbFunctionRead( uchar *data, uchar len )
{

#ifndef USE_MODEBUF
    data[0] = baud.bytes[0];
    data[1] = baud.bytes[1];
    data[2] = baud.bytes[2];
    data[3] = baud.bytes[3];
    data[4] = stopbit;
    data[5] = parity;
    data[6] = databit;
#else
    memcpy(data, modeBuffer, 7);
#endif

    return 7;
}


/*---------------------------------------------------------------------------*/
/* usbFunctionWrite                                                          */
/*---------------------------------------------------------------------------*/

uchar usbFunctionWrite( uchar *data, uchar len )
{

#ifndef USE_MODEBUF
    /*   SET_LINE_CODING    */
    baud.bytes[0] = data[0];
    baud.bytes[1] = data[1];
    baud.bytes[2] = data[2];
    baud.bytes[3] = data[3];

    //resetUart();
#else
    usbTxPacketCnt1 = 1;    /* enforce DATA0 token for next transfer */
    //iwptr = urptr;
    //irptr = uwptr;
    sendEmptyFrame = 1;
    memcpy(modeBuffer, data, 7);
#endif

    return 1;
}


void usbFunctionWriteOut( uchar *data, uchar len )
{
    /*    usb -> rs232c:  transmit char    */
    usbDisableAllRequests();
    for( ; len; len-- ) 
	{
        uartTxBufAppend(*data++);
    }
}


static void hardwareInit(void)
{
uchar    i, j;

    /* activate pull-ups except on USB lines */
    USB_CFG_IOPORT   = (uchar)~((1<<USB_CFG_DMINUS_BIT)|(1<<USB_CFG_DPLUS_BIT));
    /* all pins input except USB (-> USB reset) */
#ifdef USB_CFG_PULLUP_IOPORT    /* use usbDeviceConnect()/usbDeviceDisconnect() if available */
    USBDDR    = 0;    /* we do RESET by deactivating pullup */
    usbDeviceDisconnect();
#else
    USBDDR    = (1<<USB_CFG_DMINUS_BIT)|(1<<USB_CFG_DPLUS_BIT);
#endif

    j = 0;
    while(--j){          /* USB Reset by device only required on Watchdog Reset */
        i = 0;
        while(--i);      /* delay >10ms for USB reset */
    }
#ifdef USB_CFG_PULLUP_IOPORT
    usbDeviceConnect();
#else
    USBDDR    = 0;      /*  remove USB reset condition */
#endif

#ifndef USE_MODEBUF
    /*    USART configuration    */
    baud.dword  = UART_DEFAULT_BPS;
#endif
    resetUart();
}

void usbcdc_poll()
{
        uchar bytesRead, *data;

        usbPoll();

        /*    usb -> rs232c:  ready to receive?    */
        if( usbAllRequestsAreDisabled() && uartTxBytesFree()>=8 )
		{
            usbEnableAllRequests();
        }
        /*    rs232c -> usb:  transmit char        */
        if( usbInterruptIsReady() ) 
		{
	     	bytesRead = uartRxBytesAvailable(&data);
            /* We limit the transaction size to 7 instead of 8 to indicate that
             * this is the last transaction in the transfer. Otherwise the host
             * would try to read more transactions which we would answer with NAK
             * instead of a terminating zero sized block.
             */
            if(bytesRead >= 8) 
			{
                bytesRead = 8;
            }
	    	if (bytesRead > 0) 
			{
            	usbSetInterrupt(data, bytesRead);
            	uartRxDidReadBytes(bytesRead);
            } 
			else if (sendEmptyFrame) 
			{
            	usbSetInterrupt(0, 0);
	    	}
	    	sendEmptyFrame = bytesRead;
        }
#if USE_DCD_REPORTING
        /* We need to report rx and tx carrier after open attempt */
        if(usbInterruptIsReady3() && intr3Status != 0){
            static const uchar serialStateNotification[8] = {0xa1, 0x20, 0, 0, 0, 0, 2, 0};
	    static const uchar serialStateData[2] = {3, 0};
            if(intr3Status == 2){
                usbSetInterrupt3(serialStateNotification, 8);
            }else{
                usbSetInterrupt3(serialStateData, 2);
            }
            intr3Status--;
        }
#endif
}

void usbcdc_putc(char data) 
{
	uint8_t next = (iwptr+1) & RX_MASK;
	while (next == urptr) 
	{
		usbcdc_poll();
	}
	rx_buf[iwptr] = data;
	iwptr = next;
}

char usbcdc_getc(void) 
{
	char ch;
	uint8_t next = (irptr+1) & TX_MASK;
	
	while (irptr == uwptr) 
	{
		wdt_reset();
		usbcdc_poll();
	}
	ch = tx_buf[irptr];
	irptr = next;
	return ch;
}

void usbcdc_init()
{
    hardwareInit();
    usbInit();
    sendEmptyFrame = 1;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -