Skip to content

Commit

Permalink
Merge pull request #49 from arpruss/abstracted
Browse files Browse the repository at this point in the history
Abstracted branch merge
  • Loading branch information
arpruss committed Jan 15, 2020
2 parents 35b034d + 2bf436e commit e9a9463
Show file tree
Hide file tree
Showing 29 changed files with 1,093 additions and 986 deletions.
2 changes: 2 additions & 0 deletions HIDReports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ REPORT(KeyboardMouseJoystick, HID_MOUSE_REPORT_DESCRIPTOR(), HID_KEYBOARD_REPORT
REPORT(KeyboardMouse, HID_MOUSE_REPORT_DESCRIPTOR(), HID_KEYBOARD_REPORT_DESCRIPTOR());
REPORT(Keyboard, HID_KEYBOARD_REPORT_DESCRIPTOR());
REPORT(Mouse, HID_MOUSE_REPORT_DESCRIPTOR());
REPORT(AbsMouse, HID_ABS_MOUSE_REPORT_DESCRIPTOR());
REPORT(KeyboardJoystick, HID_KEYBOARD_REPORT_DESCRIPTOR(), HID_JOYSTICK_REPORT_DESCRIPTOR());
REPORT(Joystick, HID_JOYSTICK_REPORT_DESCRIPTOR());
REPORT(BootKeyboard, HID_BOOT_KEYBOARD_REPORT_DESCRIPTOR());
REPORT(Consumer, HID_CONSUMER_REPORT_DESCRIPTOR());
37 changes: 0 additions & 37 deletions MinSysex.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
#define STANDARD_ID_RESPONSE_LENGTH 7

#include "usb_midi_device.h"
#include <libmaple/nvic.h>
#include <libmaple/delay.h>
#include <MinSysex.h>
//#include <wirish/wirish.h>
Expand Down Expand Up @@ -129,12 +128,6 @@ volatile int sysexFinger=0;
#define EXC_RETURN 0xFFFFFFF9
#define DEFAULT_CPSR 0x61000000
#define RESET_DELAY 100000
#if 0
static void wait_reset(void) {
delay_us(RESET_DELAY);
nvic_sys_reset();
}
#endif

/* -----------------------------------------------------------------------------dealWithItQuickly()
* Note: at this point we have established that the sysex belongs to us.
Expand All @@ -154,36 +147,6 @@ void dealWithItQuickly(){
}
case USYSEX_REAL_TIME:
break;
#if 0
case LEAFLABS_MMA_VENDOR_1:
if (sysexBuffer[5]==LGL_RESET_CMD) {
uintptr_t target = (uintptr_t)wait_reset | 0x1;
asm volatile("mov r0, %[stack_top] \n\t" // Reset stack
"mov sp, r0 \n\t"
"mov r0, #1 \n\t"
"mov r1, %[target_addr] \n\t"
"mov r2, %[cpsr] \n\t"
"push {r2} \n\t" // Fake xPSR
"push {r1} \n\t" // PC target addr
"push {r0} \n\t" // Fake LR
"push {r0} \n\t" // Fake R12
"push {r0} \n\t" // Fake R3
"push {r0} \n\t" // Fake R2
"push {r0} \n\t" // Fake R1
"push {r0} \n\t" // Fake R0
"mov lr, %[exc_return] \n\t"
"bx lr"
:
: [stack_top] "r" (STACK_TOP),
[target_addr] "r" (target),
[exc_return] "r" (EXC_RETURN),
[cpsr] "r" (DEFAULT_CPSR)
: "r0", "r1", "r2");
/* Can't happen. */
ASSERT_FAULT(0);

}
#endif
default:
break;
}
Expand Down
38 changes: 28 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,37 @@ to inject keyboard data, you should do:
USBHID HID; // create instance of USBHID plugin
HIDKeyboard Keyboard(HID); // create a profile
HID.begin(HID_KEYBOARD);
HID.begin();
```

and then call `Keyboard.print("TextToInject")` to inject keyboard data. Some plugin configurations
may require further initialization code or further code that needs to be called inside the Arduino
`loop()` function.

See the `BootKeyboard`, `midiout` and `x360` example code for this procedure.
See the `BootKeyboard`, `midiout` and `x360` example code for variants on this procedure.

(Additionally, the `USBHID` plugin has a convenience `begin()` method that lets you include an
instance of a `USBCompositeSerial` plugin class, and that creates a composite HID-Serial device.)

However, if you want a USB device using more than one plugin, then you will NOT call the plugin's
`begin()` method.

Note that a single HID plugin can support a device with multiple report profiles including a keyboard, several joysticks,
a mouse, etc.:
```
USBHID HID; // create instance of USBHID plugin
HIDKeyboard Keyboard(HID); // create a profile
HIDJoystick Joystick1(HID); // create a profile
HIDJoystick Joystick2(HID); // create a profile
HIDMouse Mouse(HID); // create a profile
HID.begin();
```

Each of the profiles (e.g., Joystick1) contributes a part of the HID report descriptor to USBHID which automatically stitches
them together and assigns report IDs. However, you can also make a single overarching custom HID report descriptor and include
it in the HID.begin() call. The `softjoystick` example does this.

## Memory limitations

There are 320 bytes of hardware buffer memory available after endpoint 0 is taken into account. The following
Expand Down Expand Up @@ -157,15 +173,21 @@ MIDI.setTXPacketSize(size);
```
The maximum and default packet size is 64. Smaller packet sizes have not been thoroughly tested and may slow things down. In
particular, for HID you should make sure your packet size is sufficient for your largest HID report. The CompositeSerial
device also has a control channel whose 16 byte packet size is not adjustable.
device also has a control channel whose 16 byte packet size is not adjustable. Note that for reasons that I do not currently
understand, CompositeSerial RX packets must be a power of two in size.

Note that in the above, RX and TX are from the point of view of the MCU, not the host (i.e., RX corresponds to USB Out and TX
Note also that in the above, RX and TX are from the point of view of the MCU, not the host (i.e., RX corresponds to USB Out and TX
to USB In).

## Endpoint limitations

There is one bidirectional endpoint 0 that all endpoints share, and the hardware allows for seven more in each direction.
Each plugin contributes the following count towards the maximum of seven:
There is one bidirectional endpoint 0 that all endpoints share, and the hardware allows for seven more in each direction,
but there are some complications in that the same endpoint number when used in different directions must have some
of the same parameters. The USBComposite library takes care of these complications when allocating endpoints, but if you
have too many plugins, you USBComposite.begin() will return `false` to indicate that you've used up too many.

This is pretty complicated, but a rule of thumb for having enough endpoints is to make sure that when you add up the
following contributions for the plugins you use, your total is at most seven.

* USB Serial: 2 (= 2 TX, 1 RX)

Expand All @@ -177,10 +199,6 @@ Each plugin contributes the following count towards the maximum of seven:

* XBox360 Controller: 1 per controller (= 1 TX, 1 RX)

* XBox360 Wireless Controller: 1 per controller (= 1 TX, 1 RX)

* USB Audio: 1 (= 1 TX or 1 RX depending on mode)

* USB Multi Serial: 2 per port (= 2 TX, 1 RX)

When combining plugins, make sure the contribution does not exceed 7.
45 changes: 7 additions & 38 deletions USBComposite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ static char* putSerialNumber(char* out, int nibbles, uint32 id) {
return out;
}

const char* getDeviceIDString() {
char* getDeviceIDString() {
static char string[80/4+1];
char* p = string;

Expand All @@ -41,11 +41,8 @@ USBCompositeDevice::USBCompositeDevice(void) {
numParts = 0;
setManufacturerString(NULL);
setProductString(NULL);
setSerialString(DEFAULT_SERIAL_STRING);
iManufacturer[0] = 0;
iProduct[0] = 0;
iSerialNumber[0] = 0;
}
setSerialString(NULL);
}

void USBCompositeDevice::setVendorId(uint16 _vendorId) {
if (_vendorId != 0)
Expand All @@ -61,43 +58,16 @@ void USBCompositeDevice::setProductId(uint16 _productId) {
productId = DEFAULT_PRODUCT_ID;
}

void setString(uint8* out, const usb_descriptor_string* defaultDescriptor, const char* s, uint32 maxLength) {
if (s == NULL) {
uint8 n = defaultDescriptor->bLength;
uint8 m = USB_DESCRIPTOR_STRING_LEN(maxLength);
if (n > m)
n = m;
memcpy(out, defaultDescriptor, n);
out[0] = n;
}
else {
uint32 n = strlen(s);
if (n > maxLength)
n = maxLength;
out[0] = (uint8)USB_DESCRIPTOR_STRING_LEN(n);
out[1] = USB_DESCRIPTOR_TYPE_STRING;
for (uint32 i=0; i<n; i++) {
out[2 + 2*i] = (uint8)s[i];
out[2 + 1 + 2*i] = 0;
}
}
}

void USBCompositeDevice::setManufacturerString(const char* s) {
setString(iManufacturer, &usb_generic_default_iManufacturer, s, USB_MAX_MANUFACTURER_LENGTH);
iManufacturer = s;
}

void USBCompositeDevice::setProductString(const char* s) {
setString(iProduct, &usb_generic_default_iProduct, s, USB_MAX_PRODUCT_LENGTH);
iProduct = s;
}

void USBCompositeDevice::setSerialString(const char* s) {
if (s == NULL)
haveSerialNumber = false;
else {
haveSerialNumber = true;
setString(iSerialNumber, NULL, s, USB_MAX_SERIAL_NUMBER_LENGTH);
}
iSerialNumber = s;
}

bool USBCompositeDevice::begin() {
Expand All @@ -107,8 +77,7 @@ bool USBCompositeDevice::begin() {
if (init[i] != NULL && !init[i](plugin[i]))
return false;
}
usb_generic_set_info(vendorId, productId, iManufacturer[0] ? iManufacturer : NULL, iProduct[0] ? iProduct : NULL,
haveSerialNumber ? iSerialNumber : NULL);
usb_generic_set_info(vendorId, productId, iManufacturer, iProduct, iSerialNumber);
if (! usb_generic_set_parts(parts, numParts))
return false;
usb_generic_enable();
Expand Down
18 changes: 6 additions & 12 deletions USBComposite.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,11 @@
#include "usb_generic.h"
//#include <libmaple/usb.h>

#define USB_MAX_PRODUCT_LENGTH 32
#define USB_MAX_MANUFACTURER_LENGTH 32
#define USB_MAX_SERIAL_NUMBER_LENGTH 20

#define USB_COMPOSITE_MAX_PARTS 6

// You could use this for a serial number, but you'll be revealing the device ID to the host,
// and hence burning it for cryptographic purposes.
const char* getDeviceIDString();

#define USB_COMPOSITE_MAX_PARTS 6
char* getDeviceIDString();

class USBCompositeDevice;

Expand All @@ -26,18 +21,17 @@ typedef void(*USBPartStopper)(void*);

class USBCompositeDevice {
private:
bool enabled = false;
bool haveSerialNumber = false;
uint8_t iManufacturer[USB_DESCRIPTOR_STRING_LEN(USB_MAX_MANUFACTURER_LENGTH)];
uint8_t iProduct[USB_DESCRIPTOR_STRING_LEN(USB_MAX_PRODUCT_LENGTH)];
uint8_t iSerialNumber[USB_DESCRIPTOR_STRING_LEN(USB_MAX_SERIAL_NUMBER_LENGTH)];
const char* iManufacturer = NULL;
const char* iProduct = NULL;
const char* iSerialNumber = NULL;
uint16 vendorId;
uint16 productId;
USBCompositePart* parts[USB_COMPOSITE_MAX_PARTS];
USBPartInitializer init[USB_COMPOSITE_MAX_PARTS];
USBPartStopper stop[USB_COMPOSITE_MAX_PARTS];
void* plugin[USB_COMPOSITE_MAX_PARTS];
uint32 numParts;
bool enabled = false;
public:
USBCompositeDevice(void);
void setVendorId(uint16 vendor=0);
Expand Down
Loading

0 comments on commit e9a9463

Please sign in to comment.