Making USB bMaxPower value dynamic w/ Arduino 1.0.1

Hi all,

I originally posted this into Programming Questions but the only response was 'how many people would have Leonardos do you think?". Well, since its also an Arduino Core question as well as a request to see if I've done this properly, I'll post it in here.

I've been playing with what is ostensibly a Leonardo clone - the Freetronics LeoStick. I've compiled the new Arduino 1.0.1 Caterina bootloader and using the new 1.0.1 USBCore.cpp/.h files etc.
The current USB_CONFIG_POWER_MA Macro used as part of the D_CONFIG macro called out of USBCore.cpp is hardcoded at 500ma.
This can cause errors to appear when plugging the device into many Keyboard based USB Ports or Hubs. I'm lead to believe particularly on MacOSX ?

So I've tried to hack in, unfortunately (I hate modifying core code :frowning: ) the ability to alter this in a sketch, so you can set it in the setup() function. Is this the best way to do this?
This works, and allows you to set any arbitrary integer value to be used for the negotiation of the sketch comport.

Edit USBCore.cpp . At line 47 Add the line

int usbMaxPower = 500;

Edit USBCore.h. Edit the D_CONFIG and set line 284 to be:

#define D_CONFIG(_totalLength,_interfaces) \
   { 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED, USB_CONFIG_POWER_MA(usbMaxPower) }

By default, it will now negotiate 500ma. However in your sketch, at the top, define
"extern int usbMaxPower" Then you can do in setup(), before calling any USB descriptors (i.e, one of the first things)
"usbMaxPower = 100;"

Test script - the Example Leonardo KeyboardSerial Sketch with the above additions.:

/*
// Comments Snipped
created 21 Oct 2011
 modified 27 Mar 2012
 by Tom Igoe
 
This example code is in the public domain.
*/
extern int usbMaxPower; // Import usbMaxPower from USBCore.cpp

void setup() {
  // Set USB MaxPower to be 150
  usbMaxPower = 150; 
  // open the serial port:
  Serial.begin(9600);
  // initialize control over the keyboard:
  Keyboard.begin();
  // Print usbMaxPower int to Serial to check during setup
  Serial.print("usbma ");
  Serial.println(usbMaxPower);
}

void loop() {
  // check for incoming serial data:
  if (Serial.available() > 0) {
    // read incoming serial data:
    char inChar = Serial.read();
    
    // Print usbMaxPower int to Serial to check
    Serial.print("usbma ");
    Serial.println(usbMaxPower);

    // Type the next ASCII value from what you received:
    Keyboard.write(inChar+1);
  }  
}

Voila! Script defineable usbMaxPower values... albeit very klunky and involving hacks to the USBCore.cpp/USBCore.h - which I was trying to avoid.

Is this the best way to accomplish this for now with 1.0.1 ? What is the long term plans around the USB Descriptors ?

Adrian

Is setup too late? I assume, by the time setup is called, the USB controller has already fetched the descriptor.

It seems to work fine in practice - From what I can determine it doesn't call it until something needs it - so in the example sketch the first thing is Serial. - as long as its place before that it works otherwise it'll default back to the old 500ma . I confirmed this using USBDeviceView on Win7 x64.

The CDC USB Decsriptors are set via the Bootloader - and they are hard coded to 100ma. So the above effects only a Sketches USB usage from what I can tell.

Doing this is a bad idea, though.
The reason is that, once you have negotiated on the bus, that value is fixed. You can't change your mind later, because the user may have plugged in other devices, enough so there's no more power to draw. Thus, the amount of power you want to draw AT MOST should be value you negotiate, and this is known a priori because you (presumably) know how much each component of your circuit draws.
The headers should test whether the device power macro is already set, and if so, not re-define it -- use your value. That value should be constant.

Is int the correct data-type?

jwatte:
Doing this is a bad idea, though.
The reason is that, once you have negotiated on the bus, that value is fixed. You can't change your mind later, because the user may have plugged in other devices, enough so there's no more power to draw. Thus, the amount of power you want to draw AT MOST should be value you negotiate, and this is known a priori because you (presumably) know how much each component of your circuit draws.
The headers should test whether the device power macro is already set, and if so, not re-define it -- use your value. That value should be constant.

yes, you dont want to change it mid-script, you do want to be able to adjust it per script. If you plug a leonardo into a Mac keyboard at the moment, it produces an annoying error. If you intend to use the Leo as a HID Keyboard device for example (i.e, just the AVR running), then you might just want to set it to 100ma for that script to avoid Errors when plugged into a keyboard on the host - such as when made into a 'workstation locking dongle' or a PS3 controller.

[quote author=Coding Badly link=topic=108193.msg812481#msg812481 date=1338530815]

Is int the correct data-type?

[/quote] the current macro simply uses 500 as the value - so not sure...

The 32u4 chips present a few scenarios where there will be few if any external devices attached as they can be quite complex HID devices in their own right :slight_smile:

If you want your solution to be considered for the core you will have to use the correct data-type. It will also require a "wrapper function" to perform validation.

I confirmed this using USBDeviceView on Win7 x64.

What about Mac and Linux? Do you have a way to test?

Aside: The link in your signature does not work for me.

Ok - I'll go away and research the correct type and stick a wrapper around it. I was originally more seeking guidance if its the right track at least.. but yeah I'll go do more work on it...

Ok - I'll go away and research the correct type and stick a wrapper around it.

I didn't mean to pressure you into doing work you didn't want to do. As it is now, the code is useful (thank you). I just know that the hurdle for core modifications is very high; essentially you have to have something solid and ready-to-merge and there has to be a recognizable demand. Bear in mind that, even if you do everything I suggest, there is still an unknown possibility that the modification will never be included.

I was originally more seeking guidance if its the right track at least..

It passes a basic "smell test" (as in, it doesn't stink). Like @jwatte, I have concerns. Unfortunately, in this case, I suffer from 3rd Order Ignorance: Lack of Process so I can't offer more than "I have concerns".

Thanks - appreciate the clarifications. I'll have a look at the submission requirements, and go through and test on what I can. I agree its inelegant - but since I know that Leonardo clones like Freetronics LeoSticks are ideal for use as a Keyboard/Controller HID given its size - I don't know if '500ma' and the resultant errors on low power hubs/keyboards etc is the best solution either.

I dont think it should be dynamic or set without care - but it should be at least adjustable...