mirror of
https://github.com/mik3y/usb-serial-for-android.git
synced 2026-08-24 22:55:34 +00:00
support multi-port CDC devices
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
|
||||
|
||||
/* Copyright (c) 2011, Peter Barrett
|
||||
**
|
||||
** Permission to use, copy, modify, and/or distribute this software for
|
||||
** any purpose with or without fee is hereby granted, provided that the
|
||||
** above copyright notice and this permission notice appear in all copies.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
** SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "USBCore.h" // kai:added
|
||||
#include "USBAPI.h"
|
||||
#include <avr/wdt.h>
|
||||
#include <util/atomic.h>
|
||||
|
||||
#if defined(USBCON)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 dwDTERate;
|
||||
u8 bCharFormat;
|
||||
u8 bParityType;
|
||||
u8 bDataBits;
|
||||
u8 lineState;
|
||||
} LineInfo;
|
||||
|
||||
static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };
|
||||
static volatile int32_t breakValue = -1;
|
||||
|
||||
static u8 wdtcsr_save;
|
||||
|
||||
#define WEAK __attribute__ ((weak))
|
||||
|
||||
extern const CDCDescriptor _cdcInterface PROGMEM;
|
||||
const CDCDescriptor _cdcInterface =
|
||||
{
|
||||
D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1),
|
||||
|
||||
// CDC communication interface
|
||||
D_INTERFACE(CDC_ACM_INTERFACE,3,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), // kai
|
||||
D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd)
|
||||
D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not)
|
||||
D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported
|
||||
D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0
|
||||
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40),
|
||||
|
||||
// CDC data interface
|
||||
//D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0), // kai:removed
|
||||
D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0),
|
||||
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0)
|
||||
};
|
||||
|
||||
bool isLUFAbootloader()
|
||||
{
|
||||
return pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE;
|
||||
}
|
||||
|
||||
int CDC_GetInterface(u8* interfaceNum)
|
||||
{
|
||||
interfaceNum[0] += 1; // kai
|
||||
return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface));
|
||||
}
|
||||
|
||||
bool CDC_Setup(USBSetup& setup)
|
||||
{
|
||||
u8 r = setup.bRequest;
|
||||
u8 requestType = setup.bmRequestType;
|
||||
|
||||
if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
|
||||
{
|
||||
if (CDC_GET_LINE_CODING == r)
|
||||
{
|
||||
USB_SendControl(0,(void*)&_usbLineInfo,7);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
|
||||
{
|
||||
if (CDC_SEND_BREAK == r)
|
||||
{
|
||||
breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL;
|
||||
}
|
||||
|
||||
if (CDC_SET_LINE_CODING == r)
|
||||
{
|
||||
USB_RecvControl((void*)&_usbLineInfo,7);
|
||||
}
|
||||
|
||||
if (CDC_SET_CONTROL_LINE_STATE == r)
|
||||
{
|
||||
_usbLineInfo.lineState = setup.wValueL;
|
||||
|
||||
// auto-reset into the bootloader is triggered when the port, already
|
||||
// open at 1200 bps, is closed. this is the signal to start the watchdog
|
||||
// with a relatively long period so it can finish housekeeping tasks
|
||||
// like servicing endpoints before the sketch ends
|
||||
|
||||
uint16_t magic_key_pos = MAGIC_KEY_POS;
|
||||
|
||||
// If we don't use the new RAMEND directly, check manually if we have a newer bootloader.
|
||||
// This is used to keep compatible with the old leonardo bootloaders.
|
||||
// You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check.
|
||||
#if MAGIC_KEY_POS != (RAMEND-1)
|
||||
// For future boards save the key in the inproblematic RAMEND
|
||||
// Which is reserved for the main() return value (which will never return)
|
||||
if (isLUFAbootloader()) {
|
||||
// horray, we got a new bootloader!
|
||||
magic_key_pos = (RAMEND-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
// We check DTR state to determine if host port is open (bit 0 of lineState).
|
||||
if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0)
|
||||
{
|
||||
#if MAGIC_KEY_POS != (RAMEND-1)
|
||||
// Backup ram value if its not a newer bootloader and it hasn't already been saved.
|
||||
// This should avoid memory corruption at least a bit, not fully
|
||||
if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) {
|
||||
*(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos;
|
||||
}
|
||||
#endif
|
||||
// Store boot key
|
||||
*(uint16_t *)magic_key_pos = MAGIC_KEY;
|
||||
// Save the watchdog state in case the reset is aborted.
|
||||
wdtcsr_save = WDTCSR;
|
||||
wdt_enable(WDTO_120MS);
|
||||
}
|
||||
else if (*(uint16_t *)magic_key_pos == MAGIC_KEY)
|
||||
{
|
||||
// Most OSs do some intermediate steps when configuring ports and DTR can
|
||||
// twiggle more than once before stabilizing.
|
||||
// To avoid spurious resets we set the watchdog to 120ms and eventually
|
||||
// cancel if DTR goes back high.
|
||||
// Cancellation is only done if an auto-reset was started, which is
|
||||
// indicated by the magic key having been set.
|
||||
|
||||
wdt_reset();
|
||||
// Restore the watchdog state in case the sketch was using it.
|
||||
WDTCSR |= (1<<WDCE) | (1<<WDE);
|
||||
WDTCSR = wdtcsr_save;
|
||||
#if MAGIC_KEY_POS != (RAMEND-1)
|
||||
// Restore backed up (old bootloader) magic key data
|
||||
if (magic_key_pos != (RAMEND-1)) {
|
||||
*(uint16_t *)magic_key_pos = *(uint16_t *)(RAMEND-1);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// Clean up RAMEND key
|
||||
*(uint16_t *)magic_key_pos = 0x0000;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Serial_::begin(unsigned long /* baud_count */)
|
||||
{
|
||||
peek_buffer = -1;
|
||||
}
|
||||
|
||||
void Serial_::begin(unsigned long /* baud_count */, byte /* config */)
|
||||
{
|
||||
peek_buffer = -1;
|
||||
}
|
||||
|
||||
void Serial_::end(void)
|
||||
{
|
||||
}
|
||||
|
||||
int Serial_::available(void)
|
||||
{
|
||||
if (peek_buffer >= 0) {
|
||||
return 1 + USB_Available(CDC_RX);
|
||||
}
|
||||
return USB_Available(CDC_RX);
|
||||
}
|
||||
|
||||
int Serial_::peek(void)
|
||||
{
|
||||
if (peek_buffer < 0)
|
||||
peek_buffer = USB_Recv(CDC_RX);
|
||||
return peek_buffer;
|
||||
}
|
||||
|
||||
int Serial_::read(void)
|
||||
{
|
||||
if (peek_buffer >= 0) {
|
||||
int c = peek_buffer;
|
||||
peek_buffer = -1;
|
||||
return c;
|
||||
}
|
||||
return USB_Recv(CDC_RX);
|
||||
}
|
||||
|
||||
int Serial_::availableForWrite(void)
|
||||
{
|
||||
return USB_SendSpace(CDC_TX);
|
||||
}
|
||||
|
||||
void Serial_::flush(void)
|
||||
{
|
||||
USB_Flush(CDC_TX);
|
||||
}
|
||||
|
||||
size_t Serial_::write(uint8_t c)
|
||||
{
|
||||
return write(&c, 1);
|
||||
}
|
||||
|
||||
size_t Serial_::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
/* only try to send bytes if the high-level CDC connection itself
|
||||
is open (not just the pipe) - the OS should set lineState when the port
|
||||
is opened and clear lineState when the port is closed.
|
||||
bytes sent before the user opens the connection or after
|
||||
the connection is closed are lost - just like with a UART. */
|
||||
|
||||
// TODO - ZE - check behavior on different OSes and test what happens if an
|
||||
// open connection isn't broken cleanly (cable is yanked out, host dies
|
||||
// or locks up, or host virtual serial port hangs)
|
||||
if (_usbLineInfo.lineState > 0) {
|
||||
int r = USB_Send(CDC_TX,buffer,size);
|
||||
if (r > 0) {
|
||||
return r;
|
||||
} else {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This operator is a convenient way for a sketch to check whether the
|
||||
// port has actually been configured and opened by the host (as opposed
|
||||
// to just being connected to the host). It can be used, for example, in
|
||||
// setup() before printing to ensure that an application on the host is
|
||||
// actually ready to receive and display the data.
|
||||
// We add a short delay before returning to fix a bug observed by Federico
|
||||
// where the port is configured (lineState != 0) but not quite opened.
|
||||
Serial_::operator bool() {
|
||||
bool result = false;
|
||||
if (_usbLineInfo.lineState > 0)
|
||||
result = true;
|
||||
delay(10);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned long Serial_::baud() {
|
||||
// Disable interrupts while reading a multi-byte value
|
||||
uint32_t baudrate;
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
baudrate = _usbLineInfo.dwDTERate;
|
||||
}
|
||||
return baudrate;
|
||||
}
|
||||
|
||||
uint8_t Serial_::stopbits() {
|
||||
return _usbLineInfo.bCharFormat;
|
||||
}
|
||||
|
||||
uint8_t Serial_::paritytype() {
|
||||
return _usbLineInfo.bParityType;
|
||||
}
|
||||
|
||||
uint8_t Serial_::numbits() {
|
||||
return _usbLineInfo.bDataBits;
|
||||
}
|
||||
|
||||
bool Serial_::dtr() {
|
||||
return _usbLineInfo.lineState & 0x1;
|
||||
}
|
||||
|
||||
bool Serial_::rts() {
|
||||
return _usbLineInfo.lineState & 0x2;
|
||||
}
|
||||
|
||||
int32_t Serial_::readBreak() {
|
||||
int32_t ret;
|
||||
// Disable IRQs while reading and clearing breakValue to make
|
||||
// sure we don't overwrite a value just set by the ISR.
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
ret = breakValue;
|
||||
breakValue = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Serial_ Serial;
|
||||
|
||||
#endif /* if defined(USBCON) */
|
||||
@@ -0,0 +1,8 @@
|
||||
## castrated CDC test (single interface with 3 endpoints)
|
||||
|
||||
As mentioned [here](https://arduino.stackexchange.com/a/31695/62145), Arduino functions can be _overwritten_ by copying complete files into the own project.
|
||||
|
||||
This is used to create a castrated CDC device with a single interface containing 3 endpoints.
|
||||
|
||||
The modifications have been done against Arduino 1.8.10, for changes see comments containing `kai`.
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
|
||||
// Copyright (c) 2010, Peter Barrett
|
||||
/*
|
||||
** Permission to use, copy, modify, and/or distribute this software for
|
||||
** any purpose with or without fee is hereby granted, provided that the
|
||||
** above copyright notice and this permission notice appear in all copies.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
** SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __USBCORE_H__
|
||||
#define __USBCORE_H__
|
||||
|
||||
#include "USBAPI.h"
|
||||
|
||||
// Standard requests
|
||||
#define GET_STATUS 0
|
||||
#define CLEAR_FEATURE 1
|
||||
#define SET_FEATURE 3
|
||||
#define SET_ADDRESS 5
|
||||
#define GET_DESCRIPTOR 6
|
||||
#define SET_DESCRIPTOR 7
|
||||
#define GET_CONFIGURATION 8
|
||||
#define SET_CONFIGURATION 9
|
||||
#define GET_INTERFACE 10
|
||||
#define SET_INTERFACE 11
|
||||
|
||||
|
||||
// bmRequestType
|
||||
#define REQUEST_HOSTTODEVICE 0x00
|
||||
#define REQUEST_DEVICETOHOST 0x80
|
||||
#define REQUEST_DIRECTION 0x80
|
||||
|
||||
#define REQUEST_STANDARD 0x00
|
||||
#define REQUEST_CLASS 0x20
|
||||
#define REQUEST_VENDOR 0x40
|
||||
#define REQUEST_TYPE 0x60
|
||||
|
||||
#define REQUEST_DEVICE 0x00
|
||||
#define REQUEST_INTERFACE 0x01
|
||||
#define REQUEST_ENDPOINT 0x02
|
||||
#define REQUEST_OTHER 0x03
|
||||
#define REQUEST_RECIPIENT 0x03
|
||||
|
||||
#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_CLASS | REQUEST_INTERFACE)
|
||||
#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE)
|
||||
#define REQUEST_DEVICETOHOST_STANDARD_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE)
|
||||
|
||||
// Class requests
|
||||
|
||||
#define CDC_SET_LINE_CODING 0x20
|
||||
#define CDC_GET_LINE_CODING 0x21
|
||||
#define CDC_SET_CONTROL_LINE_STATE 0x22
|
||||
#define CDC_SEND_BREAK 0x23
|
||||
|
||||
#define MSC_RESET 0xFF
|
||||
#define MSC_GET_MAX_LUN 0xFE
|
||||
|
||||
// Descriptors
|
||||
|
||||
#define USB_DEVICE_DESC_SIZE 18
|
||||
#define USB_CONFIGUARTION_DESC_SIZE 9
|
||||
#define USB_INTERFACE_DESC_SIZE 9
|
||||
#define USB_ENDPOINT_DESC_SIZE 7
|
||||
|
||||
#define USB_DEVICE_DESCRIPTOR_TYPE 1
|
||||
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 2
|
||||
#define USB_STRING_DESCRIPTOR_TYPE 3
|
||||
#define USB_INTERFACE_DESCRIPTOR_TYPE 4
|
||||
#define USB_ENDPOINT_DESCRIPTOR_TYPE 5
|
||||
|
||||
// usb_20.pdf Table 9.6 Standard Feature Selectors
|
||||
#define DEVICE_REMOTE_WAKEUP 1
|
||||
#define ENDPOINT_HALT 2
|
||||
#define TEST_MODE 3
|
||||
|
||||
// usb_20.pdf Figure 9-4. Information Returned by a GetStatus() Request to a Device
|
||||
#define FEATURE_SELFPOWERED_ENABLED (1 << 0)
|
||||
#define FEATURE_REMOTE_WAKEUP_ENABLED (1 << 1)
|
||||
|
||||
#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02
|
||||
#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03
|
||||
#define USB_DEVICE_CLASS_STORAGE 0x08
|
||||
#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF
|
||||
|
||||
#define USB_CONFIG_POWERED_MASK 0x40
|
||||
#define USB_CONFIG_BUS_POWERED 0x80
|
||||
#define USB_CONFIG_SELF_POWERED 0xC0
|
||||
#define USB_CONFIG_REMOTE_WAKEUP 0x20
|
||||
|
||||
// bMaxPower in Configuration Descriptor
|
||||
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
|
||||
|
||||
// bEndpointAddress in Endpoint Descriptor
|
||||
#define USB_ENDPOINT_DIRECTION_MASK 0x80
|
||||
#define USB_ENDPOINT_OUT(addr) (lowByte((addr) | 0x00))
|
||||
#define USB_ENDPOINT_IN(addr) (lowByte((addr) | 0x80))
|
||||
|
||||
#define USB_ENDPOINT_TYPE_MASK 0x03
|
||||
#define USB_ENDPOINT_TYPE_CONTROL 0x00
|
||||
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01
|
||||
#define USB_ENDPOINT_TYPE_BULK 0x02
|
||||
#define USB_ENDPOINT_TYPE_INTERRUPT 0x03
|
||||
|
||||
#define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF)
|
||||
|
||||
#define CDC_V1_10 0x0110
|
||||
#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02
|
||||
|
||||
#define CDC_CALL_MANAGEMENT 0x01
|
||||
#define CDC_ABSTRACT_CONTROL_MODEL 0x02
|
||||
#define CDC_HEADER 0x00
|
||||
#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02
|
||||
#define CDC_UNION 0x06
|
||||
#define CDC_CS_INTERFACE 0x24
|
||||
#define CDC_CS_ENDPOINT 0x25
|
||||
#define CDC_DATA_INTERFACE_CLASS 0x0A
|
||||
|
||||
#define MSC_SUBCLASS_SCSI 0x06
|
||||
#define MSC_PROTOCOL_BULK_ONLY 0x50
|
||||
|
||||
#ifndef USB_VERSION
|
||||
#define USB_VERSION 0x200
|
||||
#endif
|
||||
|
||||
// Device
|
||||
typedef struct {
|
||||
u8 len; // 18
|
||||
u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE
|
||||
u16 usbVersion; // 0x200 or 0x210
|
||||
u8 deviceClass;
|
||||
u8 deviceSubClass;
|
||||
u8 deviceProtocol;
|
||||
u8 packetSize0; // Packet 0
|
||||
u16 idVendor;
|
||||
u16 idProduct;
|
||||
u16 deviceVersion; // 0x100
|
||||
u8 iManufacturer;
|
||||
u8 iProduct;
|
||||
u8 iSerialNumber;
|
||||
u8 bNumConfigurations;
|
||||
} DeviceDescriptor;
|
||||
|
||||
// Config
|
||||
typedef struct {
|
||||
u8 len; // 9
|
||||
u8 dtype; // 2
|
||||
u16 clen; // total length
|
||||
u8 numInterfaces;
|
||||
u8 config;
|
||||
u8 iconfig;
|
||||
u8 attributes;
|
||||
u8 maxPower;
|
||||
} ConfigDescriptor;
|
||||
|
||||
// String
|
||||
|
||||
// Interface
|
||||
typedef struct
|
||||
{
|
||||
u8 len; // 9
|
||||
u8 dtype; // 4
|
||||
u8 number;
|
||||
u8 alternate;
|
||||
u8 numEndpoints;
|
||||
u8 interfaceClass;
|
||||
u8 interfaceSubClass;
|
||||
u8 protocol;
|
||||
u8 iInterface;
|
||||
} InterfaceDescriptor;
|
||||
|
||||
// Endpoint
|
||||
typedef struct
|
||||
{
|
||||
u8 len; // 7
|
||||
u8 dtype; // 5
|
||||
u8 addr;
|
||||
u8 attr;
|
||||
u16 packetSize;
|
||||
u8 interval;
|
||||
} EndpointDescriptor;
|
||||
|
||||
// Interface Association Descriptor
|
||||
// Used to bind 2 interfaces together in CDC compostite device
|
||||
typedef struct
|
||||
{
|
||||
u8 len; // 8
|
||||
u8 dtype; // 11
|
||||
u8 firstInterface;
|
||||
u8 interfaceCount;
|
||||
u8 functionClass;
|
||||
u8 funtionSubClass;
|
||||
u8 functionProtocol;
|
||||
u8 iInterface;
|
||||
} IADDescriptor;
|
||||
|
||||
// CDC CS interface descriptor
|
||||
typedef struct
|
||||
{
|
||||
u8 len; // 5
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype;
|
||||
u8 d0;
|
||||
u8 d1;
|
||||
} CDCCSInterfaceDescriptor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 len; // 4
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype;
|
||||
u8 d0;
|
||||
} CDCCSInterfaceDescriptor4;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 len;
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype; // 1
|
||||
u8 bmCapabilities;
|
||||
u8 bDataInterface;
|
||||
} CMFunctionalDescriptor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 len;
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype; // 1
|
||||
u8 bmCapabilities;
|
||||
} ACMFunctionalDescriptor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// IAD
|
||||
IADDescriptor iad; // Only needed on compound device
|
||||
|
||||
// Control
|
||||
InterfaceDescriptor cif; //
|
||||
CDCCSInterfaceDescriptor header;
|
||||
CMFunctionalDescriptor callManagement; // Call Management
|
||||
ACMFunctionalDescriptor controlManagement; // ACM
|
||||
CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION
|
||||
EndpointDescriptor cifin;
|
||||
|
||||
// Data
|
||||
//InterfaceDescriptor dif; // kai:removed
|
||||
EndpointDescriptor in;
|
||||
EndpointDescriptor out;
|
||||
} CDCDescriptor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
InterfaceDescriptor msc;
|
||||
EndpointDescriptor in;
|
||||
EndpointDescriptor out;
|
||||
} MSCDescriptor;
|
||||
|
||||
|
||||
#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \
|
||||
{ 18, 1, USB_VERSION, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs }
|
||||
|
||||
#define D_CONFIG(_totalLength,_interfaces) \
|
||||
{ 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, USB_CONFIG_POWER_MA(500) }
|
||||
|
||||
#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \
|
||||
{ 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 }
|
||||
|
||||
#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \
|
||||
{ 7, 5, _addr,_attr,_packetSize, _interval }
|
||||
|
||||
#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \
|
||||
{ 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 }
|
||||
|
||||
#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 }
|
||||
#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 }
|
||||
|
||||
// Bootloader related fields
|
||||
// Old Caterina bootloader places the MAGIC key into unsafe RAM locations (it can be rewritten
|
||||
// by the running sketch before to actual reboot).
|
||||
// Newer bootloaders, recognizable by the LUFA "signature" at the end of the flash, can handle both
|
||||
// the usafe and the safe location.
|
||||
#ifndef MAGIC_KEY
|
||||
#define MAGIC_KEY 0x7777
|
||||
#endif
|
||||
|
||||
#ifndef MAGIC_KEY_POS
|
||||
#define MAGIC_KEY_POS 0x0800
|
||||
#endif
|
||||
|
||||
#ifndef NEW_LUFA_SIGNATURE
|
||||
#define NEW_LUFA_SIGNATURE 0xDCFB
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
bridge USB-serial to hardware-serial
|
||||
|
||||
for Arduinos based on ATmega32u4 (Leonardo and compatible Pro Micro, Micro)
|
||||
hardware serial is configured with baud-rate, databits, stopbits, parity as send over USB
|
||||
|
||||
see https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino
|
||||
-> CDC.cpp|HardwareSerial.cpp for serial implementation details
|
||||
|
||||
this sketch is mainly for demonstration / test of CDC communication
|
||||
performance as real usb-serial bridge would be inacceptable as each byte is send in separate USB packet
|
||||
*/
|
||||
|
||||
uint32_t baud = 9600;
|
||||
uint8_t databits = 8;
|
||||
uint8_t stopbits = 1;
|
||||
uint8_t parity = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(baud); // USB
|
||||
Serial1.begin(baud, SERIAL_8N1);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// show USB connected state
|
||||
if (Serial) TXLED1;
|
||||
else TXLED0;
|
||||
|
||||
// configure hardware serial
|
||||
if (Serial.baud() != baud ||
|
||||
Serial.numbits() != databits ||
|
||||
Serial.stopbits() != stopbits ||
|
||||
Serial.paritytype() != parity) {
|
||||
baud = Serial.baud();
|
||||
databits = Serial.numbits();
|
||||
stopbits = Serial.stopbits();
|
||||
parity = Serial.paritytype();
|
||||
uint8_t config = 0; // ucsrc register
|
||||
switch (databits) {
|
||||
case 5: break;
|
||||
case 6: config |= 2; break;
|
||||
case 7: config |= 4; break;
|
||||
case 8: config |= 6; break;
|
||||
default: config |= 6;
|
||||
}
|
||||
switch (stopbits) {
|
||||
case 2: config |= 8;
|
||||
// 1.5 stopbits not supported
|
||||
}
|
||||
switch (parity) {
|
||||
case 1: config |= 0x30; break; // odd
|
||||
case 2: config |= 0x20; break; // even
|
||||
// mark, space not supported
|
||||
}
|
||||
Serial1.end();
|
||||
Serial1.begin(baud, config);
|
||||
}
|
||||
|
||||
// bridge
|
||||
if (Serial.available() > 0)
|
||||
Serial1.write(Serial.read());
|
||||
if (Serial1.available() > 0)
|
||||
Serial.write(Serial1.read());
|
||||
}
|
||||
Reference in New Issue
Block a user