/* CDC Arduino Library by Ihsan Kehribar (kehribar.me) and Digistump LLC (digistump.com) - all changes made under the same license as V-USB */ #include "DigiCDC.h" #include #include #include #include #include uchar sendEmptyFrame; static uchar intr3Status; /* used to control interrupt endpoint transmissions */ DigiCDCDevice::DigiCDCDevice(void){} void DigiCDCDevice::delay(long milli) { unsigned long last = millis(); while (milli > 0) { unsigned long now = millis(); milli -= now - last; last = now; refresh(); } } void DigiCDCDevice::flush(){ cli(); RingBuffer_InitBuffer(&rxBuf,rxBuf_Data,sizeof(rxBuf_Data)); sei(); } void DigiCDCDevice::begin(){ usbBegin(); DigiCDCDevice::delay(500);//delay to allow enumeration and such } size_t DigiCDCDevice::write(uint8_t c) { if(RingBuffer_IsFull(&txBuf)) { refresh(); return 0; } else { RingBuffer_Insert(&txBuf,c); DigiCDCDevice::delay(5); //gives 4.2-4.7ms per character for usb transfer at low speed return 1; } } int DigiCDCDevice::available() { refresh(); return RingBuffer_GetCount(&rxBuf); } int DigiCDCDevice::read() { if(RingBuffer_IsEmpty(&rxBuf)) { refresh(); return 0; } else { refresh(); return RingBuffer_Remove(&rxBuf); } } int DigiCDCDevice::peek() { if(RingBuffer_IsEmpty(&rxBuf)) { return 0; } else { return RingBuffer_Peek(&rxBuf); } refresh(); } void DigiCDCDevice::task(void) { refresh(); } void DigiCDCDevice::refresh(void) { _delay_ms(1); usbPollWrapper(); } void DigiCDCDevice::end(void) { // drive both USB pins low to disconnect usbDeviceDisconnect(); cli(); RingBuffer_InitBuffer(&rxBuf,rxBuf_Data,sizeof(rxBuf_Data)); sei(); } DigiCDCDevice::operator bool() { refresh(); return true; } void DigiCDCDevice::usbBegin() { cli(); PORTB &= ~(_BV(USB_CFG_DMINUS_BIT) | _BV(USB_CFG_DPLUS_BIT)); usbDeviceDisconnect(); _delay_ms(250); usbDeviceConnect(); usbInit(); RingBuffer_InitBuffer(&txBuf,txBuf_Data,sizeof(txBuf_Data)); RingBuffer_InitBuffer(&rxBuf,rxBuf_Data,sizeof(rxBuf_Data)); intr3Status = 0; sendEmptyFrame = 0; sei(); } void DigiCDCDevice::usbPollWrapper() { usbPoll(); while((!(RingBuffer_IsEmpty(&txBuf)))&&(index<9)) { tmp[index++] = RingBuffer_Remove(&txBuf); } if(usbInterruptIsReady()) { if(sendEmptyFrame) { usbSetInterrupt(tmp,0); sendEmptyFrame = 0; } else if(index>0) { usbSetInterrupt(tmp,index); usbEnableAllRequests(); sendEmptyFrame = 1; index = 0; } } /* We need to report rx and tx carrier after open attempt */ if(intr3Status != 0 && usbInterruptIsReady3()){ static uchar serialStateNotification[10] = {0xa1, 0x20, 0, 0, 0, 0, 2, 0, 3, 0}; if(intr3Status == 2){ usbSetInterrupt3(serialStateNotification, 8); }else{ usbSetInterrupt3(serialStateNotification+8, 2); } intr3Status--; } } #ifdef __cplusplus extern "C"{ #endif 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 }; static const PROGMEM char configDescrCDC[] = { /* USB configuration descriptor */ 9, /* sizeof(usbDescrConfig): length of descriptor in bytes */ USBDESCR_CONFIG, /* descriptor type */ 67, 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 (1 << 7) | USBATTR_SELFPOWER, /* attributes */ #else (1 << 7), /* 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 */ 0x80|USB_CFG_EP3_NUMBER, /* IN endpoint number 3 */ 0x03, /* attrib: Interrupt endpoint */ 8, 0, /* maximum packet size */ USB_CFG_INTR_POLL_INTERVAL, /* in ms */ /* Interface Descriptor */ 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ USBDESCR_INTERFACE, /* 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 */ HW_CDC_BULK_OUT_SIZE, 0, /* maximum packet size */ 0, /* in ms */ /* Endpoint Descriptor */ 7, /* sizeof(usbDescrEndpoint) */ USBDESCR_ENDPOINT, /* descriptor type = endpoint */ 0x81, /* IN endpoint number 1 */ 0x02, /* attrib: Bulk endpoint */ HW_CDC_BULK_IN_SIZE, 0, /* maximum packet size */ 0, /* in ms */ }; uchar usbFunctionDescriptor(usbRequest_t *rq) { if(rq->wValue.bytes[1] == USBDESCR_DEVICE){ usbMsgPtr = (uchar *)usbDescriptorDevice; return usbDescriptorDevice[0]; }else{ /* must be config descriptor */ usbMsgPtr = (uchar *)configDescrCDC; return sizeof(configDescrCDC); } } /* ------------------------------------------------------------------------- */ /* ----------------------------- USB interface ----------------------------- */ /* ------------------------------------------------------------------------- */ uchar usbFunctionSetup(uchar data[8]) { usbRequest_t *rq = (usbRequest_t*)((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. */ if( intr3Status==0 ) intr3Status = 2; } /* Prepare bulk-in endpoint to respond to early termination */ if((rq->bmRequestType & USBRQ_DIR_MASK) == USBRQ_DIR_HOST_TO_DEVICE) sendEmptyFrame = 1; } return 0; } /*---------------------------------------------------------------------------*/ /* usbFunctionRead */ /*---------------------------------------------------------------------------*/ uchar usbFunctionRead( uchar *data, uchar len ) { // data[0] = 0; // data[1] = 0; // data[2] = 0; // data[3] = 0; // data[4] = 0; // data[5] = 0; // data[6] = 8; return 7; } /*---------------------------------------------------------------------------*/ /* usbFunctionWrite */ /*---------------------------------------------------------------------------*/ uchar usbFunctionWrite( uchar *data, uchar len ) { // baud.bytes[0] = data[0]; // baud.bytes[1] = data[1]; return 1; } void usbFunctionWriteOut( uchar *data, uchar len ) { uint8_t qw = 0; for(qw=0;qw= HW_CDC_BULK_OUT_SIZE) { usbDisableAllRequests(); } } #ifdef __cplusplus } // extern "C" #endif DigiCDCDevice SerialUSB;