Skip to content

Allow USB descriptor strings to be defined in boards.txt (redux) #1422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 37 additions & 27 deletions app/src/processing/app/helpers/StringReplacer.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,41 +45,51 @@ public static String[] formatAndSplit(String src, Map<String, String> dict,
}

// Split the resulting string in arguments
return quotedSplit(src, '"', false);
return quotedSplit(src, '"');
}

public static String[] quotedSplit(String src, char escapeChar,
boolean acceptEmptyArguments)
// Split a string into a list of space-delimited arguments
//
// Arguments containing spaces can be escaped by quoting with 'quoteChar'.
// Arguments entirely enclosed by 'quoteChar' will have quotes stripped,
// arguments where quoteChar is inside another part of the argument string (ie -DNAME="VALUE PARTS")
// will have the quotes retained.
public static String[] quotedSplit(String src, char quoteChar)
throws Exception {
String quote = "" + escapeChar;
List<String> res = new ArrayList<String>();
String escapedArg = null;
boolean escaping = false;
for (String i : src.split(" ")) {
if (!escaping) {
if (!i.startsWith(quote)) {
if (i.trim().length() != 0 || acceptEmptyArguments)
res.add(i);
continue;
String arg = "";
boolean quoting = false;
boolean quoting_instr = false;

for(char c : src.toCharArray()) {
if(quoting) {
if(c == quoteChar) {
if(quoting_instr)
arg += quoteChar;
res.add(arg);
arg = "";
quoting = false;
} else {
arg += c;
}

escaping = true;
i = i.substring(1);
escapedArg = "";
}

if (!i.endsWith(quote)) {
escapedArg += i + " ";
continue;
else { // not quoting
if(c == ' ') {
res.add(arg);
arg = "";
} else if(c == quoteChar) {
quoting = true;
quoting_instr = arg.length() > 0;
if(quoting_instr)
arg += quoteChar;
} else {
arg += c;
}
}

escapedArg += i.substring(0, i.length() - 1);
if (escapedArg.trim().length() != 0 || acceptEmptyArguments)
res.add(escapedArg);
escaping = false;
}
if (escaping)
throw new Exception("Invalid quoting: no closing '" + escapeChar +

if (quoting)
throw new Exception("Invalid quoting: no closing '" + quoteChar +
"' char found.");
return res.toArray(new String[0]);
}
Expand Down
13 changes: 8 additions & 5 deletions hardware/arduino/avr/boards.txt
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,11 @@ leonardo.build.mcu=atmega32u4
leonardo.build.f_cpu=16000000L
leonardo.build.vid=0x2341
leonardo.build.pid=0x8036
leonardo.build.usb_product="Arduino Leonardo"
leonardo.build.board=AVR_LEONARDO
leonardo.build.core=arduino
leonardo.build.variant=leonardo
leonardo.build.extra_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid}
leonardo.build.extra_flags={build.usb_flags}

##############################################################

Expand All @@ -217,10 +218,11 @@ micro.build.mcu=atmega32u4
micro.build.f_cpu=16000000L
micro.build.vid=0x2341
micro.build.pid=0x8037
micro.build.usb_product=Arduino Micro
micro.build.board=AVR_MICRO
micro.build.core=arduino
micro.build.variant=micro
micro.build.extra_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid}
micro.build.extra_flags={build.usb_flags}

##############################################################

Expand All @@ -246,10 +248,11 @@ esplora.build.mcu=atmega32u4
esplora.build.f_cpu=16000000L
esplora.build.vid=0x2341
esplora.build.pid=0x803c
esplora.build.usb_product=Arduino Esplora
esplora.build.board=AVR_ESPLORA
esplora.build.core=arduino
esplora.build.variant=leonardo
esplora.build.extra_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid}
esplora.build.extra_flags={build.usb_flags}

##############################################################

Expand Down Expand Up @@ -407,15 +410,15 @@ LilyPadUSB.bootloader.extended_fuses=0xce
LilyPadUSB.bootloader.file=caterina-LilyPadUSB/Caterina-LilyPadUSB.hex
LilyPadUSB.bootloader.unlock_bits=0x3F
LilyPadUSB.bootloader.lock_bits=0x2F

LilyPadUSB.build.mcu=atmega32u4
LilyPadUSB.build.f_cpu=8000000L
LilyPadUSB.build.vid=0x1B4F
LilyPadUSB.build.pid=0x9208
LilyPadUSB.build.usb_product=LilyPad USB
LilyPadUSB.build.board=AVR_LILYPAD_USB
LilyPadUSB.build.core=arduino
LilyPadUSB.build.variant=leonardo
LilyPadUSB.build.extra_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid}
LilyPadUSB.build.extra_flags={build.usb_flags}

##############################################################

Expand Down
70 changes: 40 additions & 30 deletions hardware/arduino/avr/cores/arduino/USBCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ volatile u8 RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */
//==================================================================

extern const u16 STRING_LANGUAGE[] PROGMEM;
extern const u16 STRING_IPRODUCT[] PROGMEM;
extern const u16 STRING_IMANUFACTURER[] PROGMEM;
extern const u8 STRING_PRODUCT[] PROGMEM;
extern const u8 STRING_MANUFACTURER[] PROGMEM;
extern const DeviceDescriptor USB_DeviceDescriptor PROGMEM;
extern const DeviceDescriptor USB_DeviceDescriptorA PROGMEM;

Expand All @@ -49,31 +49,24 @@ const u16 STRING_LANGUAGE[2] = {
0x0409 // English
};

const u16 STRING_IPRODUCT[17] = {
(3<<8) | (2+2*16),
#if USB_PID == 0x8036
'A','r','d','u','i','n','o',' ','L','e','o','n','a','r','d','o'
#elif USB_PID == 0x8037
'A','r','d','u','i','n','o',' ','M','i','c','r','o',' ',' ',' '
#elif USB_PID == 0x803C
'A','r','d','u','i','n','o',' ','E','s','p','l','o','r','a',' '
#elif USB_PID == 0x9208
'L','i','l','y','P','a','d','U','S','B',' ',' ',' ',' ',' ',' '
#else
'U','S','B',' ','I','O',' ','B','o','a','r','d',' ',' ',' ',' '
#ifndef USB_PRODUCT
// If no product is provided, use USB IO Board
#define USB_PRODUCT "USB IO Board"
#endif
};

const u16 STRING_IMANUFACTURER[12] = {
(3<<8) | (2+2*11),
const u8 STRING_PRODUCT[] PROGMEM = USB_PRODUCT;

#if USB_VID == 0x2341
'A','r','d','u','i','n','o',' ','L','L','C'
#define USB_MANUFACTURER "Arduino LLC"
#elif USB_VID == 0x1b4f
'S','p','a','r','k','F','u','n',' ',' ',' '
#else
'U','n','k','n','o','w','n',' ',' ',' ',' '
#define USB_MANUFACTURER "SparkFun"
#elif !defined(USB_MANUFACTURER)
// Fall through to unknown if no manufacturer name was provided in a macro
#define USB_MANUFACTURER "Unknown"
#endif
};

const u8 STRING_MANUFACTURER[] PROGMEM = USB_MANUFACTURER;


#ifdef CDC_ENABLED
#define DEVICE_CLASS 0x02
Expand Down Expand Up @@ -416,6 +409,22 @@ int USB_SendControl(u8 flags, const void* d, int len)
return sent;
}

// Send a USB descriptor string. The string is stored in PROGMEM as a
// plain ASCII string but is sent out as UTF-16 with the correct 2-byte
// prefix
static bool USB_SendStringDescriptor(const u8*string_P, u8 string_len) {
SendControl(2 + string_len * 2);
SendControl(3);
for(u8 i = 0; i < string_len; i++) {
bool r = SendControl(pgm_read_byte(&string_P[i]));
r &= SendControl(0); // high byte
if(!r) {
return false;
}
}
return true;
}

// Does not timeout or cross fifo boundaries
// Will only work for transfers <= 64 bytes
// TODO
Expand Down Expand Up @@ -476,7 +485,6 @@ bool SendDescriptor(Setup& setup)
return HID_GetDescriptor(t);
#endif

u8 desc_length = 0;
const u8* desc_addr = 0;
if (USB_DEVICE_DESCRIPTOR_TYPE == t)
{
Expand All @@ -486,20 +494,22 @@ bool SendDescriptor(Setup& setup)
}
else if (USB_STRING_DESCRIPTOR_TYPE == t)
{
if (setup.wValueL == 0)
if (setup.wValueL == 0) {
desc_addr = (const u8*)&STRING_LANGUAGE;
else if (setup.wValueL == IPRODUCT)
desc_addr = (const u8*)&STRING_IPRODUCT;
else if (setup.wValueL == IMANUFACTURER)
desc_addr = (const u8*)&STRING_IMANUFACTURER;
}
else if (setup.wValueL == IPRODUCT) {
return USB_SendStringDescriptor(STRING_PRODUCT, strlen(USB_PRODUCT));
}
else if (setup.wValueL == IMANUFACTURER) {
return USB_SendStringDescriptor(STRING_MANUFACTURER, strlen(USB_MANUFACTURER));
}
else
return false;
}

if (desc_addr == 0)
return false;
if (desc_length == 0)
desc_length = pgm_read_byte(desc_addr);
u8 desc_length = pgm_read_byte(desc_addr);

USB_SendControl(TRANSFER_PGM,desc_addr,desc_length);
return true;
Expand Down
6 changes: 6 additions & 0 deletions hardware/arduino/avr/platform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,9 @@ tools.avrdude.bootloader.params.verbose=-v -v -v -v
tools.avrdude.bootloader.params.quiet=-q -q
tools.avrdude.bootloader.pattern="{cmd.path}" "-C{config.path}" {bootloader.verbose} -p{build.mcu} -c{protocol} {program.extra_params} "-Uflash:w:{runtime.ide.path}/hardware/arduino/avr/bootloaders/{bootloader.file}:i" -Ulock:w:{bootloader.lock_bits}:m


# USB Default Flags
# Default blank usb manufacturer will be filled it at compile time
# - from numeric vendor ID, set to Unknown otherwise
build.usb_manufacturer=
build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} -DUSB_MANUFACTURER={build.usb_manufacturer} -DUSB_PRODUCT={build.usb_product}