From 4c2d5e19cdc07ba5809faa69f0cd0e6b0b77be35 Mon Sep 17 00:00:00 2001 From: arpruss Date: Sat, 10 Apr 2021 11:27:35 -0500 Subject: [PATCH 1/4] USBComposite library updates: MIDI sysex support; bug fixes --- STM32F1/libraries/USBComposite/USBMIDI.cpp | 99 ++++++++++++++++++- STM32F1/libraries/USBComposite/USBMIDI.h | 12 ++- .../libraries/USBComposite/library.properties | 2 +- .../USBComposite/scripts/midi_table.py | 20 ++-- .../libraries/USBComposite/scripts/send.py | 53 +++++----- .../USBComposite/scripts/showhids.py | 6 +- STM32F1/libraries/USBComposite/usb_generic.c | 5 +- STM32F1/libraries/USBComposite/usb_hid.c | 14 ++- STM32F1/libraries/USBComposite/usb_scsi.c | 4 +- 9 files changed, 160 insertions(+), 55 deletions(-) diff --git a/STM32F1/libraries/USBComposite/USBMIDI.cpp b/STM32F1/libraries/USBComposite/USBMIDI.cpp index 94f793394..dfdb5586b 100644 --- a/STM32F1/libraries/USBComposite/USBMIDI.cpp +++ b/STM32F1/libraries/USBComposite/USBMIDI.cpp @@ -180,6 +180,26 @@ void USBMIDI::dispatchPacket(uint32 p) e.i=p; switch (e.p.cin) { + case CIN_SYSEX: + handleSysExData(e.p.midi0); + handleSysExData(e.p.midi1); + handleSysExData(e.p.midi2); + break; + case CIN_SYSEX_ENDS_IN_1: + handleSysExData(e.p.midi0); + handleSysExEnd(); + break; + case CIN_SYSEX_ENDS_IN_2: + handleSysExData(e.p.midi0); + handleSysExData(e.p.midi1); + handleSysExEnd(); + break; + case CIN_SYSEX_ENDS_IN_3: + handleSysExData(e.p.midi0); + handleSysExData(e.p.midi1); + handleSysExData(e.p.midi2); + handleSysExEnd(); + break; case CIN_3BYTE_SYS_COMMON: if (e.p.midi0 == MIDIv1_SONG_POSITION_PTR) { handleSongPosition(((uint16)e.p.midi2)<<7|((uint16)e.p.midi1)); @@ -261,7 +281,6 @@ void USBMIDI::poll(void) static union EVENT_t outPacket; // since we only use one at a time no point in reallocating it -// Send Midi NOTE OFF message to a given channel, with note 0-127 and velocity 0-127 void USBMIDI::sendNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) { outPacket.p.cable=DEFAULT_MIDI_CABLE; @@ -270,9 +289,8 @@ void USBMIDI::sendNoteOff(unsigned int channel, unsigned int note, unsigned int outPacket.p.midi1=note; outPacket.p.midi2=velocity; writePacket(outPacket.i); - -} +} // Send Midi NOTE ON message to a given channel, with note 0-127 and velocity 0-127 void USBMIDI::sendNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) @@ -438,6 +456,79 @@ void USBMIDI::sendReset(void) writePacket(outPacket.i); } +void USBMIDI::sendSysex(uint8_t b0, uint8_t b1, uint8_t b2) +{ + outPacket.p.cable = DEFAULT_MIDI_CABLE; + outPacket.p.cin = CIN_SYSEX_ENDS_IN_3; + outPacket.p.midi0 = b0; + outPacket.p.midi1 = b1; + outPacket.p.midi2 = b2; + writePacket(outPacket.i); +} + +void USBMIDI::sendSysexEndsIn1(uint8_t b0) +{ + outPacket.p.cable = DEFAULT_MIDI_CABLE; + outPacket.p.cin = CIN_SYSEX_ENDS_IN_1; + outPacket.p.midi0 = b0; + outPacket.p.midi1 = 0; + outPacket.p.midi2 = 0; + writePacket(outPacket.i); +} + +void USBMIDI::sendSysexEndsIn2(uint8_t b0, uint8_t b1) +{ + outPacket.p.cable = DEFAULT_MIDI_CABLE; + outPacket.p.cin = CIN_SYSEX_ENDS_IN_2; + outPacket.p.midi0 = b0; + outPacket.p.midi1 = b1; + outPacket.p.midi2 = 0; + writePacket(outPacket.i); +} + +void USBMIDI::sendSysexEndsIn3(uint8_t b0, uint8_t b1, uint8_t b2) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_SYSEX_ENDS_IN_3; + outPacket.p.midi0= b0; + outPacket.p.midi1= b1; + outPacket.p.midi2= b2; + writePacket(outPacket.i); +} + +void USBMIDI::sendSysexPayload(uint8_t *payload, uint32 length) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + if (length == 1) + { + sendSysexEndsIn3(MIDIv1_SYSEX_START, payload[0], MIDIv1_SYSEX_END); + return; + } + + sendSysex(MIDIv1_SYSEX_START, payload[0], payload[1]); + + unsigned int offset = 2; + for (; offset < length - 2; offset += 3) + { + sendSysex(payload[offset], payload[offset + 1], payload[offset + 2]); + } + + unsigned int remaining = length - offset; + if (remaining == 0) + { + sendSysexEndsIn1(MIDIv1_SYSEX_END); + } + else if (remaining == 1) + { + sendSysexEndsIn2(payload[offset], MIDIv1_SYSEX_END); + } + else + { + sendSysexEndsIn3(payload[offset], payload[offset + 1], MIDIv1_SYSEX_END); + } +} + + const uint32 midiNoteFrequency_10ths[128] = { 82, 87, 92, 97, 103, 109, 116, 122, 130, 138, 146, 154, 164, 173, 184, 194, 206, 218, 231, 245, 260, 275, 291, 309, 327, 346, 367, 389, 412, 437, 462, 490, @@ -468,4 +559,6 @@ void USBMIDI::handleContinue(void) {} void USBMIDI::handleStop(void) {} void USBMIDI::handleActiveSense(void) {} void USBMIDI::handleReset(void) {} +void USBMIDI::handleSysExData(unsigned char) {} +void USBMIDI::handleSysExEnd(void) {} #pragma GCC diagnostic pop diff --git a/STM32F1/libraries/USBComposite/USBMIDI.h b/STM32F1/libraries/USBComposite/USBMIDI.h index 16ede42df..215b58d59 100644 --- a/STM32F1/libraries/USBComposite/USBMIDI.h +++ b/STM32F1/libraries/USBComposite/USBMIDI.h @@ -170,7 +170,13 @@ class USBMIDI { void sendStop(void); void sendActiveSense(void); void sendReset(void); - + void sendSysex(uint8_t b0, uint8_t b1, uint8_t b2); + void sendSysexEndsIn1(uint8_t b0); + void sendSysexEndsIn2(uint8_t b0, uint8_t b1); + void sendSysexEndsIn3(uint8_t b0, uint8_t b1, uint8_t b2); + void sendSysexPayload(uint8_t *payload, uint32 length); + + // Overload these in a subclass to get MIDI messages when they come in virtual void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity); virtual void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity); @@ -188,7 +194,9 @@ class USBMIDI { virtual void handleStop(void); virtual void handleActiveSense(void); virtual void handleReset(void); - + virtual void handleSysExData(unsigned char data); + virtual void handleSysExEnd(void); + }; extern const uint32 midiNoteFrequency_10ths[128]; diff --git a/STM32F1/libraries/USBComposite/library.properties b/STM32F1/libraries/USBComposite/library.properties index 9fdf11758..932d6289f 100644 --- a/STM32F1/libraries/USBComposite/library.properties +++ b/STM32F1/libraries/USBComposite/library.properties @@ -1,5 +1,5 @@ name=USBComposite for STM32F1 -version=0.99 +version=1.00 author=Various email=arpruss@gmail.com sentence=USB HID / MIDI / mass storage / Audio library for STM32F1 diff --git a/STM32F1/libraries/USBComposite/scripts/midi_table.py b/STM32F1/libraries/USBComposite/scripts/midi_table.py index 9e6ca180c..9e40d3678 100644 --- a/STM32F1/libraries/USBComposite/scripts/midi_table.py +++ b/STM32F1/libraries/USBComposite/scripts/midi_table.py @@ -1,11 +1,11 @@ -from math import * - -def freq(m): - return 27.5 * 2**((m-21)/12.) - -print("static constexpr uint32 midiNoteFrequency_10ths[128] = {", end='') -for i in range(128): - if not i % 16: - print("\n ",end='') - print("%d, " % int(floor(freq(i)*10 + 0.5)), end='') +from math import * + +def freq(m): + return 27.5 * 2**((m-21)/12.) + +print("static constexpr uint32 midiNoteFrequency_10ths[128] = {", end='') +for i in range(128): + if not i % 16: + print("\n ",end='') + print("%d, " % int(floor(freq(i)*10 + 0.5)), end='') print("};") \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/scripts/send.py b/STM32F1/libraries/USBComposite/scripts/send.py index 9cdc9934b..c1ec87db9 100644 --- a/STM32F1/libraries/USBComposite/scripts/send.py +++ b/STM32F1/libraries/USBComposite/scripts/send.py @@ -1,29 +1,26 @@ -from pywinusb import hid -from time import sleep - -SIZE=1 -REPORT_ID=20 - -def sample_handler(data): - print("Raw data: {0}".format(data)) - -device = hid.HidDeviceFilter(vendor_id = 0x1EAF, product_id = 0x0004).get_devices()[0] -print(device) -device.open() -device.set_raw_data_handler(sample_handler) - -n = 0 -while True: - """ - print("sending") - out_report=device.find_output_reports()[0] - buffer=[i for i in range(SIZE+1)] - buffer[0]=REPORT_ID # report id - buffer[-1] = n - out_report.set_raw_data(buffer) - if out_report.send(): - n = (n+1)&0xFF -""" - sleep(0.5) - #sleep(0.005) +from pywinusb import hid +from time import sleep + +SIZE=128 +REPORT_ID=0 + +def sample_handler(data): + print("Raw data: {0}".format(data)) + +device = hid.HidDeviceFilter(vendor_id = 0x1EAF).get_devices()[0] +print(device) +device.open() +device.set_raw_data_handler(sample_handler) + +n = 0 +while True: + print("sending") + out_report=device.find_output_reports()[0] + buffer=[i for i in range(SIZE+1)] + buffer[0]=REPORT_ID # report id + buffer[-1] = n + out_report.set_raw_data(buffer) + if out_report.send(): + n = (n+1)&0xFF + sleep(2) \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/scripts/showhids.py b/STM32F1/libraries/USBComposite/scripts/showhids.py index a9ffe9bb7..5b71d819b 100644 --- a/STM32F1/libraries/USBComposite/scripts/showhids.py +++ b/STM32F1/libraries/USBComposite/scripts/showhids.py @@ -1,3 +1,3 @@ -from pywinusb import hid - -hid.core.show_hids() +from pywinusb import hid + +hid.core.show_hids() diff --git a/STM32F1/libraries/USBComposite/usb_generic.c b/STM32F1/libraries/USBComposite/usb_generic.c index b947e2721..96b617c9c 100644 --- a/STM32F1/libraries/USBComposite/usb_generic.c +++ b/STM32F1/libraries/USBComposite/usb_generic.c @@ -516,8 +516,9 @@ static uint8* control_data_tx(uint16 length) { return NULL; } - if (control_tx_done && pInformation->USBwLengths.w <= wOffset + pInformation->Ctrl_Info.PacketSize) + if (control_tx_done && pInformation->USBwLengths.w <= wOffset + pInformation->Ctrl_Info.PacketSize) { *control_tx_done = USB_CONTROL_DONE; // this may be a bit premature, but it's our best try + } if (control_tx_buffer == NULL) return NULL; @@ -603,8 +604,6 @@ void usb_generic_control_tx_chunk_setup(struct usb_chunk* chunk) { control_data_chunk_tx(0); } - - static uint8* control_data_rx(uint16 length) { unsigned wOffset = pInformation->Ctrl_Info.Usb_wOffset; diff --git a/STM32F1/libraries/USBComposite/usb_hid.c b/STM32F1/libraries/USBComposite/usb_hid.c index 83fd7d432..37746831c 100644 --- a/STM32F1/libraries/USBComposite/usb_hid.c +++ b/STM32F1/libraries/USBComposite/usb_hid.c @@ -48,7 +48,8 @@ uint16 GetEPTxAddr(uint8 /*bEpNum*/); #include #include -static uint32 ProtocolValue = 0; +static uint8 IdleValue = 1; +static uint8 ProtocolValue = 0; static uint32 txEPSize = 64; static volatile int8 transmitting; static struct usb_chunk* reportDescriptorChunks = NULL; @@ -258,6 +259,7 @@ void usb_hid_clear_buffers(uint8 type) { static void usb_hid_clear(void) { ProtocolValue = 0; + IdleValue = 1; usb_hid_clear_buffers(HID_REPORT_TYPE_OUTPUT); usb_hid_clear_buffers(HID_REPORT_TYPE_FEATURE); } @@ -371,9 +373,8 @@ static RESULT hidUSBDataSetup(uint8 request, uint8 interface, uint8 requestType, } else { -// buffer->state = HID_BUFFER_EMPTY; + buffer->state = HID_BUFFER_EMPTY; usb_generic_control_rx_setup(buffer->buffer, buffer->bufferSize, &(buffer->state)); - buffer->state = HID_BUFFER_UNREAD; } return USB_SUCCESS; } @@ -410,6 +411,10 @@ static RESULT hidUSBDataSetup(uint8 request, uint8 interface, uint8 requestType, case GET_PROTOCOL: usb_generic_control_tx_setup(&ProtocolValue, 1, NULL); return USB_SUCCESS; + + case GET_IDLE: + usb_generic_control_tx_setup(&IdleValue, 1, NULL); + return USB_SUCCESS; } } @@ -425,6 +430,9 @@ static RESULT hidUSBNoDataSetup(uint8 request, uint8 interface, uint8 requestTyp case SET_PROTOCOL: ProtocolValue = wValue0; return USB_SUCCESS; + case SET_IDLE: + IdleValue = wValue0; + return USB_SUCCESS; } } return USB_UNSUPPORT; diff --git a/STM32F1/libraries/USBComposite/usb_scsi.c b/STM32F1/libraries/USBComposite/usb_scsi.c index b595a2e51..7b42647ed 100644 --- a/STM32F1/libraries/USBComposite/usb_scsi.c +++ b/STM32F1/libraries/USBComposite/usb_scsi.c @@ -274,10 +274,10 @@ void scsi_read_memory(uint8_t lun, uint32_t startSector, uint32_t numSectors) { usb_mass_sil_write(SCSI_dataBuffer, MAX_BULK_PACKET_SIZE); } else { + usb_mass_sil_write(SCSI_dataBuffer + SCSI_blockOffset, MAX_BULK_PACKET_SIZE); + SCSI_blockReadCount -= MAX_BULK_PACKET_SIZE; SCSI_blockOffset += MAX_BULK_PACKET_SIZE; - - usb_mass_sil_write(SCSI_dataBuffer + SCSI_blockOffset, MAX_BULK_PACKET_SIZE); } offset += MAX_BULK_PACKET_SIZE; From 606e291507b5fa1a6cf89f5c78119c1790e1c50a Mon Sep 17 00:00:00 2001 From: arpruss Date: Wed, 2 Feb 2022 21:27:24 -0600 Subject: [PATCH 2/4] USB Composite 1.06 merge --- STM32F1/libraries/USBComposite/HIDReports.cpp | 1 + STM32F1/libraries/USBComposite/Keyboard.cpp | 15 +- STM32F1/libraries/USBComposite/README.md | 3 +- .../libraries/USBComposite/USBComposite.cpp | 2 +- .../USBComposite/USBCompositeSerial.cpp | 7 + STM32F1/libraries/USBComposite/USBHID.cpp | 1 + STM32F1/libraries/USBComposite/USBHID.h | 231 +++++++++++++++++- STM32F1/libraries/USBComposite/USBMIDI.cpp | 9 +- STM32F1/libraries/USBComposite/USBMIDI.h | 4 +- .../USBComposite/USBMultiXBox360.cpp | 8 + STM32F1/libraries/USBComposite/USBXBox360.h | 29 ++- .../libraries/USBComposite/USBXBox360W.cpp | 9 + STM32F1/libraries/USBComposite/branchlog.sh | 1 + .../MidiPotentiometer/MidiPotentiometer.ino | 39 +++ .../NintendoSwitch/NintendoSwitch.ino | 31 +++ .../libraries/USBComposite/library.properties | 2 +- .../USBComposite/usb_composite_serial.c | 8 +- STM32F1/libraries/USBComposite/usb_hid.c | 78 +++++- STM32F1/libraries/USBComposite/usb_hid.h | 3 + 19 files changed, 434 insertions(+), 47 deletions(-) create mode 100644 STM32F1/libraries/USBComposite/branchlog.sh create mode 100644 STM32F1/libraries/USBComposite/examples/MidiPotentiometer/MidiPotentiometer.ino create mode 100755 STM32F1/libraries/USBComposite/examples/NintendoSwitch/NintendoSwitch.ino diff --git a/STM32F1/libraries/USBComposite/HIDReports.cpp b/STM32F1/libraries/USBComposite/HIDReports.cpp index 84c8e9573..75f4662b3 100644 --- a/STM32F1/libraries/USBComposite/HIDReports.cpp +++ b/STM32F1/libraries/USBComposite/HIDReports.cpp @@ -15,3 +15,4 @@ REPORT(Joystick, HID_JOYSTICK_REPORT_DESCRIPTOR()); REPORT(BootKeyboard, HID_BOOT_KEYBOARD_REPORT_DESCRIPTOR()); REPORT(Consumer, HID_CONSUMER_REPORT_DESCRIPTOR()); REPORT(Digitizer, HID_DIGITIZER_REPORT_DESCRIPTOR()); +REPORT(SwitchController, HID_SWITCH_CONTROLLER_REPORT_DESCRIPTOR()); diff --git a/STM32F1/libraries/USBComposite/Keyboard.cpp b/STM32F1/libraries/USBComposite/Keyboard.cpp index 39da26740..5d17c32c7 100644 --- a/STM32F1/libraries/USBComposite/Keyboard.cpp +++ b/STM32F1/libraries/USBComposite/Keyboard.cpp @@ -150,8 +150,13 @@ void HIDKeyboard::end(void) { // shift -> 0x02 // modifiers: 128 --> bit shift -uint8_t HIDKeyboard::getKeyCode(uint8_t k, uint8_t* modifiersP) +uint8_t HIDKeyboard::getKeyCode(uint16_t k, uint8_t* modifiersP) { + if (k & 0x8000u) { + // backwards compatibility in case a caller has passed a signed 8-bit value + k &= 0xFFu; + } + *modifiersP = 0; if (adjustForHostCapsLock && (getLEDs() & 0x02)) { // capslock is down on host OS, so host will reverse @@ -169,8 +174,8 @@ uint8_t HIDKeyboard::getKeyCode(uint8_t k, uint8_t* modifiersP) } return k; } - if (k >= 0x88) { // non-printing key, Arduino format - return k - 0x88; + if (k >= KEY_HID_OFFSET) { // non-printing key, Arduino format + return k - KEY_HID_OFFSET; } else { // shift key *modifiersP = 1<<(k-0x80); @@ -178,7 +183,7 @@ uint8_t HIDKeyboard::getKeyCode(uint8_t k, uint8_t* modifiersP) } } -size_t HIDKeyboard::press(uint8_t k) { +size_t HIDKeyboard::press(uint16_t k) { uint8_t modifiers; k = getKeyCode(k, &modifiers); @@ -212,7 +217,7 @@ size_t HIDKeyboard::press(uint8_t k) { // release() takes the specified key out of the persistent key report and // sends the report. This tells the OS the key is no longer pressed and that // it shouldn't be repeated any more. -size_t HIDKeyboard::release(uint8_t k) +size_t HIDKeyboard::release(uint16_t k) { uint8_t modifiers; k = getKeyCode(k, &modifiers); diff --git a/STM32F1/libraries/USBComposite/README.md b/STM32F1/libraries/USBComposite/README.md index e906e1f44..ab512354e 100644 --- a/STM32F1/libraries/USBComposite/README.md +++ b/STM32F1/libraries/USBComposite/README.md @@ -66,7 +66,7 @@ while(!USBComposite); ``` Finally, there are a number of classes that implement particular protocols for the `USBHID` class plugin. -These are: +These include: ``` HIDMouse HIDKeyboard @@ -74,6 +74,7 @@ HIDJoystick HIDAbsMouse HIDConsumer HIDRaw +HIDSwitchController ``` And you can customize with more. Moreover, the `USBHID` plugin itself allows for compositing multiple HID profiles, e.g., Mouse / Keyboard / three joysticks. Each of these has at least diff --git a/STM32F1/libraries/USBComposite/USBComposite.cpp b/STM32F1/libraries/USBComposite/USBComposite.cpp index 574323d7b..8d772f450 100644 --- a/STM32F1/libraries/USBComposite/USBComposite.cpp +++ b/STM32F1/libraries/USBComposite/USBComposite.cpp @@ -71,7 +71,7 @@ void USBCompositeDevice::setSerialString(const char* s) { } bool USBCompositeDevice::begin() { - if (enabled) + if (enabled) return true; for (uint32 i = 0 ; i < numParts ; i++) { if (init[i] != NULL && !init[i](plugin[i])) diff --git a/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp b/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp index 08349a79c..a2cf443d3 100644 --- a/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp +++ b/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "usb_composite_serial.h" @@ -239,6 +240,12 @@ static void rxHook(unsigned hook, void *ignored) { } // Got the magic sequence -> reset, presumably into the bootloader. + // Write 0x424C to backup register 0x0A to tell the bootloader to wait + bkp_init(); + bkp_enable_writes(); + bkp_write(0x0a,0x424c); + bkp_disable_writes(); + // Return address is wait_reset, but we must set the thumb bit. uintptr_t target = (uintptr_t)wait_reset | 0x1; asm volatile("mov r0, %[stack_top] \n\t" // Reset stack diff --git a/STM32F1/libraries/USBComposite/USBHID.cpp b/STM32F1/libraries/USBComposite/USBHID.cpp index db239bf28..d350c0256 100644 --- a/STM32F1/libraries/USBComposite/USBHID.cpp +++ b/STM32F1/libraries/USBComposite/USBHID.cpp @@ -245,6 +245,7 @@ void HIDReporter::registerProfile(bool always) { else { reportChunks[0].data = reportDescriptor.descriptor; reportChunks[0].dataLength = reportIDOffset; + reportID = reportDescriptor.descriptor[reportIDOffset]; reportChunks[1].data = &(reportID); reportChunks[1].dataLength = 1; reportChunks[2].data = reportDescriptor.descriptor+reportIDOffset+1; diff --git a/STM32F1/libraries/USBComposite/USBHID.h b/STM32F1/libraries/USBComposite/USBHID.h index baa87cb34..34091a981 100644 --- a/STM32F1/libraries/USBComposite/USBHID.h +++ b/STM32F1/libraries/USBComposite/USBHID.h @@ -204,11 +204,11 @@ 0x95, HID_KEYBOARD_ROLLOVER, /* REPORT_COUNT (6) */ \ 0x75, 0x08, /* REPORT_SIZE (8) */ \ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ - 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ \ + 0x26, 0xDD, 0x00, /* LOGICAL_MAXIMUM (261) */ \ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \ \ 0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */ \ - 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ \ + 0x29, 0xDD, /* USAGE_MAXIMUM (Keypad Hexadecimal) */ \ 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ \ \ 0x05, 0x08, /* USAGE_PAGE (LEDs) */ \ @@ -302,6 +302,53 @@ MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ 0xC0 +#define HID_SWITCH_CONTROLLER_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ \ + 0x09, 0x05, /* Usage (Joystick) */ \ + 0xA1, 0x01, /* Collection (Application) */ \ + /* buttons */ \ + 0x15, 0x00, /* Logical Minimum (0) */ \ + 0x25, 0x01, /* Logical Maximum (1) */ \ + 0x35, 0x00, /* Physical Minimum (0) */ \ + 0x45, 0x01, /* Physical Maximum (1) */ \ + 0x75, 0x01, /* Report Size (1) */ \ + 0x95, 0x0e, /* Report Count (16) */ \ + 0x05, 0x09, /* Usage Page (9) */ \ + 0x19, 0x01, /* Usage Minimum (1) */ \ + 0x29, 0x0e, /* Usage Maximum (16) */ \ + 0x81, 0x02, /* Input (Data,Var,Abs) */ \ + 0x95, 0x02, \ + 0x81, 0x01, \ + /* HAT Switch */ \ + 0x05, 0x01, /* Usage Page (1) */ \ + 0x25, 0x07, /* Logical Maximum (7) */ \ + 0x46, 315&0xFF,315>>8, /* Physical Maximum (315) */ \ + 0x75, 0x04, /* Report Size (4) */ \ + 0x95, 0x01, /* Report Count (1) */ \ + 0x65, 20, /* Unit (20) */ \ + 0x09, 57, /* Usage (57) */ \ + 0x81, 66, /* Input (66) */ \ + /* additional nibble here for Switch Pro Controller? */ \ + 0x65, 0, /* Unit (0) */ \ + 0x95, 0x01, /* Report Count (1) */ \ + 0x81, 1, /* Input (1) */ \ + /* sticks */ \ + 0x26, 255 & 0xFF, 255 >> 8, /* Logical Maximum (255) */ \ + 0x46, 255 & 0xFF, 255 >> 8, /* Physical Maximum (255) */ \ + 0x09, 48, /* Usage (48) */ \ + 0x09, 49, /* Usage (49) */ \ + 0x09, 50, /* Usage (50) */ \ + 0x09, 53, /* Usage (53) */ \ + 0x75, 0x08, /* Report Size (8) */ \ + 0x95, 0x04, /* Report Count (4) */ \ + 0x81, 0x02, /* Input (Data,Var,Abs) */ \ + 0x75, 0x08, /* Report Size (8) */ \ + 0x95, 0x01, /* Report Count (1) */ \ + 0x81, 0x01, /* Input (1) */ \ + __VA_ARGS__ \ + 0xC0, /* End Collection */ + + #define RAWHID_USAGE_PAGE 0xFFC0 // recommended: 0xFF00 to 0xFFFF #define RAWHID_USAGE 0x0C00 // recommended: 0x0100 to 0xFFFF @@ -344,6 +391,7 @@ extern const HIDReportDescriptor* hidReportBootKeyboard; extern const HIDReportDescriptor* hidReportAbsMouse; extern const HIDReportDescriptor* hidReportDigitizer; extern const HIDReportDescriptor* hidReportConsumer; +extern const HIDReportDescriptor* hidReportSwitchController; #define HID_MOUSE hidReportMouse #define HID_KEYBOARD hidReportKeyboard @@ -364,7 +412,7 @@ class USBHID { // baseChunk holds any explicitly specified report descriptor that // overrides any report descriptors from the chain of registered profiles struct usb_chunk baseChunk = { 0, 0, 0 }; - HIDReporter* profiles; + HIDReporter* profiles = nullptr; public: static bool init(USBHID* me); // add a report to the list ; if always is false, then it only works if autoRegister is true @@ -420,6 +468,12 @@ class HIDReporter { public: void sendReport(); + uint8_t* getReport() { + return reportBuffer; + } + uint16_t getReportSize() { + return bufferSize; + } // if you use this init function, the buffer starts with a reportID, even if the reportID is zero, // and bufferSize includes the reportID; if reportID is zero, sendReport() will skip the initial // reportID byte @@ -528,13 +582,24 @@ class HIDConsumer : public HIDReporter { ConsumerReport_t report; public: enum { - BRIGHTNESS_UP = 0x6F, - BRIGHTNESS_DOWN = 0x70, - VOLUME_UP = 0xE9, + BRIGHTNESS_UP = 0x6F, + BRIGHTNESS_DOWN = 0x70, + NEXT_TRACK = 0xB5, + PREVIOUS_TRACK = 0xB6, + PLAY_OR_PAUSE = 0xCD, + VOLUME_UP = 0xE9, VOLUME_DOWN = 0xEA, - MUTE = 0xE2, - PLAY_OR_PAUSE = 0xCD - // see pages 75ff of http://www.usb.org/developers/hidpage/Hut1_12v2.pdf + REWIND = 0xB4, + FAST_FORWARD = 0xB3, + MUTE = 0xE2, + MENU = 0x40, + MENU_PICK = 0x41, + MENU_UP = 0x42, + MENU_DOWN = 0x43, + MENU_LEFT = 0x44, + MENU_RIGHT = 0x45, + MENU_ESCAPE = 0x46, + // see pages 117 of https://www.usb.org/sites/default/files/hut1_22.pdf }; HIDConsumer(USBHID& HID, uint8_t reportID=HID_CONSUMER_REPORT_ID) : HIDReporter(HID, hidReportConsumer, (uint8_t*)&report, sizeof(report), reportID) { report.button = 0; @@ -554,6 +619,10 @@ class HIDConsumer : public HIDReporter { #define KEY_RIGHT_ALT 0x86 #define KEY_RIGHT_GUI 0x87 +#define KEY_HID_OFFSET 0x88 + +// The following definitions takes their value from the document at https://www.usb.org/sites/default/files/hut1_22.pdf, starting p82 +// However, their value are augmented by KEY_HID_OFFSET (for example, KEY_F12 real value is 0x45) #define KEY_UP_ARROW 0xDA #define KEY_DOWN_ARROW 0xD9 #define KEY_LEFT_ARROW 0xD8 @@ -597,7 +666,7 @@ class HIDKeyboard : public Print, public HIDReporter { uint8_t leds[HID_BUFFER_ALLOCATE_SIZE(1,1)]; HIDBuffer_t ledData; uint8_t reportID; - uint8_t getKeyCode(uint8_t k, uint8_t* modifiersP); + uint8_t getKeyCode(uint16_t k, uint8_t* modifiersP); bool adjustForHostCapsLock = true; public: @@ -615,8 +684,8 @@ class HIDKeyboard : public Print, public HIDReporter { return leds[reportID != 0 ? 1 : 0]; } virtual size_t write(uint8_t k); - virtual size_t press(uint8_t k); - virtual size_t release(uint8_t k); + virtual size_t press(uint16_t k); + virtual size_t release(uint16_t k); virtual void releaseAll(void); }; @@ -655,6 +724,9 @@ class HIDJoystick : public HIDReporter { void begin(void); void end(void); void button(uint8_t button, bool val); + void buttons(uint32_t b) { + joyReport.buttons = b; + } void X(uint16_t val); void Y(uint16_t val); void position(uint16_t x, uint16_t y); @@ -677,6 +749,137 @@ class HIDJoystick : public HIDReporter { } }; +typedef struct { + uint16_t buttons; + uint8_t dpad; + uint8_t leftX; + uint8_t leftY; + uint8_t rightX; + uint8_t rightY; + uint8_t pad; +} __packed SwitchControllerReport_t; + +class HIDSwitchController : public HIDReporter { +protected: + SwitchControllerReport_t report; + bool manualReport = false; + +public: + const int32_t AXIS_MAX = 255; + const int32_t AXIS_NEUTRAL = 128; + const int32_t AXIS_MIN = 0; + + enum { + DPAD_TOP = 0, + DPAD_TOPRIGHT = 1, + DPAD_RIGHT = 2, + DPAD_BOTRIGHT = 3, + DPAD_BOTTOM = 4, + DPAD_BOTLEFT = 5, + DPAD_LEFT = 6, + DPAD_TOPLEFT = 7, + DPAD_NEUTRAL = 8, + }; + + enum { + BUTTON_Y = 0, + BUTTON_B = 1, + BUTTON_A = 2, + BUTTON_X = 3, + BUTTON_L = 4, + BUTTON_R = 5, + BUTTON_ZL = 6, + BUTTON_ZR = 7, + BUTTON_MINUS = 8, + BUTTON_PLUS = 9, + BUTTON_LEFT_CLICK = 10, + BUTTON_RIGHT_CLICK = 11, + BUTTON_HOME = 12, + BUTTON_CAPTURE = 13, + BUTTON_EXTRA1 = 14, + BUTTON_EXTRA2 = 15, + }; + + void setManualReportMode(bool m) { + manualReport = m; + } + bool getManualReportMode() { + return manualReport; + } + void safeSendReport() { + if (!manualReport) + sendReport(); + } + void send() { + sendReport(); + } + + + void button(uint8_t b, bool val) { + uint16_t mask = ((uint16_t)1 << b); + + if (val) { + report.buttons |= mask; + } else { + report.buttons &= ~mask; + } + safeSendReport(); + } + + void buttons(uint16_t b) { + report.buttons = b & 0x3FFF; + safeSendReport(); + } + + void dpad(uint8_t value) { + report.dpad = value & 0xF; + safeSendReport(); + } + + void X(uint8_t v) { + report.leftX = v; + safeSendReport(); + } + + void Y(uint8_t v) { + report.leftY = v; + safeSendReport(); + } + + void XRight(uint8_t v) { + report.rightX = v; + safeSendReport(); + } + + void YRight(uint8_t v) { + report.rightY = v; + safeSendReport(); + } + + void begin() { + USBComposite.setVendorId(0x0F0D); + USBComposite.setProductId(0x00c1); + USBComposite.setProductString("HORIPAD S"); + USBComposite.setManufacturerString("Omega Centauri Software"); + HID.begin(hidReportSwitchController); + } + + void end() { + HID.end(); + } + + HIDSwitchController(USBHID& HID) + : HIDReporter(HID, (uint8_t*)&report, sizeof(report)) { + report.buttons = 0; + report.dpad = DPAD_NEUTRAL; + report.leftX = AXIS_NEUTRAL; + report.leftY = AXIS_NEUTRAL; + report.rightX = AXIS_NEUTRAL; + report.rightY = AXIS_NEUTRAL; + report.pad = 0; + } +}; + templateclass HIDRaw : public HIDReporter { private: uint8_t txBuffer[txSize]; @@ -698,5 +901,7 @@ templateclass HIDRaw : public HIDReporter { } }; + + #endif - \ No newline at end of file + diff --git a/STM32F1/libraries/USBComposite/USBMIDI.cpp b/STM32F1/libraries/USBComposite/USBMIDI.cpp index dfdb5586b..d08bfd732 100644 --- a/STM32F1/libraries/USBComposite/USBMIDI.cpp +++ b/STM32F1/libraries/USBComposite/USBMIDI.cpp @@ -176,7 +176,6 @@ union EVENT_t { void USBMIDI::dispatchPacket(uint32 p) { union EVENT_t e; - e.i=p; switch (e.p.cin) { @@ -236,7 +235,7 @@ void USBMIDI::dispatchPacket(uint32 p) break; case CIN_PITCH_WHEEL: - handlePitchChange(((uint16)e.p.midi2)<<7|((uint16)e.p.midi1)); + handlePitchChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), ((uint16)e.p.midi2)<<7|((uint16)e.p.midi1)); break; case CIN_1BYTE: switch (e.p.midi0) { @@ -356,11 +355,11 @@ void USBMIDI::sendAfterTouch(unsigned int channel, unsigned int velocity) } // Send a Midi PITCH CHANGE message, with a 14-bit pitch (always for all channels) -void USBMIDI::sendPitchChange(unsigned int pitch) +void USBMIDI::sendPitchChange(unsigned int channel, unsigned int pitch) { outPacket.p.cable=DEFAULT_MIDI_CABLE; outPacket.p.cin=CIN_PITCH_WHEEL; - outPacket.p.midi0=MIDIv1_PITCH_WHEEL; + outPacket.p.midi0=MIDIv1_PITCH_WHEEL |(channel & 0x0f); outPacket.p.midi1= (uint8) pitch & 0x07F; outPacket.p.midi2= (uint8) (pitch>>7) & 0x7f; writePacket(outPacket.i); @@ -549,7 +548,7 @@ void USBMIDI::handleVelocityChange(unsigned int channel, unsigned int note, unsi void USBMIDI::handleControlChange(unsigned int channel, unsigned int controller, unsigned int value) {} void USBMIDI::handleProgramChange(unsigned int channel, unsigned int program) {} void USBMIDI::handleAfterTouch(unsigned int channel, unsigned int velocity) {} -void USBMIDI::handlePitchChange(unsigned int pitch) {} +void USBMIDI::handlePitchChange(unsigned int channel, unsigned int pitch) {} void USBMIDI::handleSongPosition(unsigned int position) {} void USBMIDI::handleSongSelect(unsigned int song) {} void USBMIDI::handleTuneRequest(void) {} diff --git a/STM32F1/libraries/USBComposite/USBMIDI.h b/STM32F1/libraries/USBComposite/USBMIDI.h index 215b58d59..2c990bdf2 100644 --- a/STM32F1/libraries/USBComposite/USBMIDI.h +++ b/STM32F1/libraries/USBComposite/USBMIDI.h @@ -160,7 +160,7 @@ class USBMIDI { void sendControlChange(unsigned int channel, unsigned int controller, unsigned int value); void sendProgramChange(unsigned int channel, unsigned int program); void sendAfterTouch(unsigned int channel, unsigned int velocity); - void sendPitchChange(unsigned int pitch); + void sendPitchChange(unsigned int channel, unsigned int pitch); void sendSongPosition(unsigned int position); void sendSongSelect(unsigned int song); void sendTuneRequest(void); @@ -184,7 +184,7 @@ class USBMIDI { virtual void handleControlChange(unsigned int channel, unsigned int controller, unsigned int value); virtual void handleProgramChange(unsigned int channel, unsigned int program); virtual void handleAfterTouch(unsigned int channel, unsigned int velocity); - virtual void handlePitchChange(unsigned int pitch); + virtual void handlePitchChange(unsigned int channel, unsigned int pitch); virtual void handleSongPosition(unsigned int position); virtual void handleSongSelect(unsigned int song); virtual void handleTuneRequest(void); diff --git a/STM32F1/libraries/USBComposite/USBMultiXBox360.cpp b/STM32F1/libraries/USBComposite/USBMultiXBox360.cpp index 8a96d4684..9d9665966 100644 --- a/STM32F1/libraries/USBComposite/USBMultiXBox360.cpp +++ b/STM32F1/libraries/USBComposite/USBMultiXBox360.cpp @@ -21,6 +21,14 @@ void USBXBox360Controller::send(void){ sendData((uint8*)&report, sizeof(report)); } +uint16_t USBXBox360Controller::getReportSize(void){ + return sizeof(report); +} + +uint8_t* USBXBox360Controller::getReport(void){ + return (uint8_t*)&report; +} + void USBXBox360Controller::setRumbleCallback(void (*callback)(uint8 left, uint8 right)) { x360_set_rumble_callback(controller,callback); } diff --git a/STM32F1/libraries/USBComposite/USBXBox360.h b/STM32F1/libraries/USBComposite/USBXBox360.h index ae793dd49..13d7506f7 100644 --- a/STM32F1/libraries/USBComposite/USBXBox360.h +++ b/STM32F1/libraries/USBComposite/USBXBox360.h @@ -70,6 +70,8 @@ class USBXBox360WController : public USBXBox360Reporter { return connected; } void send(void); + uint8* getReport(void); + uint16_t getReportSize(void); void stop(void); void button(uint8_t button, bool val); void buttons(uint16_t b); @@ -92,12 +94,15 @@ templateclass USBXBox360W { private: bool enabled = false; uint8 buffers[USB_X360_BUFFER_SIZE_PER_CONTROLLER * numControllers]; + uint16 vendorId; + uint16 productId; public: static bool init(USBXBox360W* me) { x360w_initialize_controller_data(numControllers, me->buffers); - USBComposite.setVendorId(0x045e); - USBComposite.setProductId(0x0719); + USBComposite.setVendorId(me->vendorId); + USBComposite.setProductId(me->productId); + return true; }; @@ -124,7 +129,7 @@ templateclass USBXBox360W { USBXBox360WController controllers[numControllers]; - USBXBox360W() { + USBXBox360W(uint16 _vendorId=0x045e, uint16 _productId=0x0719) : vendorId(_vendorId), productId(_productId) { for (uint8 i=0;iclass USBMultiXBox360 { private: bool enabled = false; uint8 buffers[USB_X360_BUFFER_SIZE_PER_CONTROLLER * numControllers]; + uint16 vendorId; + uint16 productId; public: static bool init(USBMultiXBox360* me) { usb_multi_x360_initialize_controller_data(numControllers, me->buffers); - USBComposite.setVendorId(0x045e); - USBComposite.setProductId(0x028e); + USBComposite.setVendorId(me->vendorId); + USBComposite.setProductId(me->productId); return true; }; @@ -204,7 +213,7 @@ templateclass USBMultiXBox360 { USBXBox360Controller controllers[numControllers]; - USBMultiXBox360() { + USBMultiXBox360(uint16 _vendorId=0x045e, uint16 _productId=0x028e) : vendorId(_vendorId), productId(_productId) { for (uint8 i=0;ibuffers); - USBComposite.setVendorId(0x045e); - USBComposite.setProductId(0x028e); + USBComposite.setVendorId(me->vendorId); + USBComposite.setProductId(me->productId); return true; }; @@ -243,7 +254,7 @@ class USBXBox360 : public USBXBox360Controller { } }; - USBXBox360() : USBXBox360Controller(0) { + USBXBox360(uint16 _vendorId=0x045e, uint16 _productId=0x028e) : USBXBox360Controller(0), vendorId(_vendorId), productId(_productId) { } }; diff --git a/STM32F1/libraries/USBComposite/USBXBox360W.cpp b/STM32F1/libraries/USBComposite/USBXBox360W.cpp index ce40ed74d..b5fbb2912 100644 --- a/STM32F1/libraries/USBComposite/USBXBox360W.cpp +++ b/STM32F1/libraries/USBComposite/USBXBox360W.cpp @@ -27,6 +27,15 @@ void USBXBox360WController::send(void){ sendData(&report, sizeof(report)); } +uint16_t USBXBox360WController::getReportSize(void){ + return sizeof(report); +} + +uint8_t* USBXBox360WController::getReport(void){ + return (uint8_t*)&report; +} + + const uint8 startup[] = {0x00,0x0F,0x00,0xF0,0xF0,0xCC,0x42,0xAF,0x3C,0x60,0xAC,0x24,0xFB,0x50,0x00,0x05,0x13,0xE7,0x20,0x1D,0x30,0x03,0x40,0x01,0x50,0x01,0xFF,0xFF,0xFF }; bool USBXBox360WController::connect(bool state) { diff --git a/STM32F1/libraries/USBComposite/branchlog.sh b/STM32F1/libraries/USBComposite/branchlog.sh new file mode 100644 index 000000000..3647c45e8 --- /dev/null +++ b/STM32F1/libraries/USBComposite/branchlog.sh @@ -0,0 +1 @@ +svn log https://github.com/arpruss/USBComposite_stm32f1/branches/abstracted diff --git a/STM32F1/libraries/USBComposite/examples/MidiPotentiometer/MidiPotentiometer.ino b/STM32F1/libraries/USBComposite/examples/MidiPotentiometer/MidiPotentiometer.ino new file mode 100644 index 000000000..4e2abd047 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/MidiPotentiometer/MidiPotentiometer.ino @@ -0,0 +1,39 @@ +#include + +USBMIDI midi; +const uint8 pot_pin = 6; +const uint8 threshold = 1; + +const unsigned int midi_channel = + 1; // this might show up as channel 1 depending on start index +const unsigned int cc_command = 0; // bank select command + +unsigned int old_value = 0; +unsigned int new_value = 0; + +void setup() { + + // product id taken from library example + USBComposite.setProductId(0x0031); + pinMode(pot_pin, INPUT); + midi.begin(); + delay(1000); +} + +void loop() { + + int temp = analogRead(pot_pin); // a value between 0-4095 + new_value = temp / 32; // convert to a value between 0-127 + + // If difference between new_value and old_value is grater than threshold + if ((new_value > old_value && new_value - old_value > threshold) || + (new_value < old_value && old_value - new_value > threshold)) { + + midi.sendControlChange(midi_channel, cc_command, new_value); + + // Update old_value + old_value = new_value; + } + // Wait 50ms before reading the pin again + delay(50); +} diff --git a/STM32F1/libraries/USBComposite/examples/NintendoSwitch/NintendoSwitch.ino b/STM32F1/libraries/USBComposite/examples/NintendoSwitch/NintendoSwitch.ino new file mode 100755 index 000000000..97b387751 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/NintendoSwitch/NintendoSwitch.ino @@ -0,0 +1,31 @@ +#include + +USBHID HID; +HIDSwitchController controller(HID); + +void setup() { + controller.begin(); + while (!USBComposite); + delay(1000); +} + +void loop() { + controller.X(16); + controller.send(); + delay(300); + controller.X(255-16); + controller.send(); + delay(300); + controller.X(128); + controller.send(); + delay(300); + /* + for (int i=0; i<=0; i++) { + controller.button(i,true); + controller.sendReport(); + delay(100); + controller.button(i,false); + controller.sendReport(); + delay(100); + } */ +} diff --git a/STM32F1/libraries/USBComposite/library.properties b/STM32F1/libraries/USBComposite/library.properties index 932d6289f..387790bb2 100644 --- a/STM32F1/libraries/USBComposite/library.properties +++ b/STM32F1/libraries/USBComposite/library.properties @@ -1,5 +1,5 @@ name=USBComposite for STM32F1 -version=1.00 +version=1.06 author=Various email=arpruss@gmail.com sentence=USB HID / MIDI / mass storage / Audio library for STM32F1 diff --git a/STM32F1/libraries/USBComposite/usb_composite_serial.c b/STM32F1/libraries/USBComposite/usb_composite_serial.c index 59f9b449e..9f679bcfd 100644 --- a/STM32F1/libraries/USBComposite/usb_composite_serial.c +++ b/STM32F1/libraries/USBComposite/usb_composite_serial.c @@ -377,7 +377,7 @@ uint32 composite_cdcacm_peek(uint8* buf, uint32 len) { unsigned i; uint32 tail = vcom_rx_tail; - uint32 rx_unread = (vcom_rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + uint32 rx_unread = (vcom_rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; if (len > rx_unread) { len = rx_unread; @@ -395,10 +395,10 @@ uint32 composite_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len) { unsigned i; uint32 tail = (vcom_rx_tail + offset) & CDC_SERIAL_RX_BUFFER_SIZE_MASK ; - uint32 rx_unread = (vcom_rx_head - tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + uint32 rx_unread = (vcom_rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; - if (len > rx_unread) { - len = rx_unread; + if (len + offset > rx_unread) { + len = rx_unread - offset; } for (i = 0; i < len; i++) { diff --git a/STM32F1/libraries/USBComposite/usb_hid.c b/STM32F1/libraries/USBComposite/usb_hid.c index 37746831c..b89ff6ac2 100644 --- a/STM32F1/libraries/USBComposite/usb_hid.c +++ b/STM32F1/libraries/USBComposite/usb_hid.c @@ -48,22 +48,27 @@ uint16 GetEPTxAddr(uint8 /*bEpNum*/); #include #include +static uint8 numEndpoints = 1; static uint8 IdleValue = 1; static uint8 ProtocolValue = 0; static uint32 txEPSize = 64; +static uint32 rxEPSize = 64; static volatile int8 transmitting; static struct usb_chunk* reportDescriptorChunks = NULL; static void hidDataTxCb(void); +static void hidDataRxCb(void); static void hidUSBReset(void); static void usb_hid_clear(void); static RESULT hidUSBDataSetup(uint8 request, uint8 interface, uint8 requestType, uint8 wValue0, uint8 wValue1, uint16 wIndex, uint16 wLength); static RESULT hidUSBNoDataSetup(uint8 request, uint8 interface, uint8 requestType, uint8 wValue0, uint8 wValue1, uint16 wIndex); +static USBHIDOutputEndpointReceiver rxReceiver = NULL; +static void* rxReceiverExtra = NULL; static volatile HIDBuffer_t hidBuffers[MAX_HID_BUFFERS] = {{ 0 }}; +static volatile uint8* hidBufferRx = NULL; #define HID_INTERFACE_OFFSET 0x00 -#define NUM_HID_ENDPOINTS 1 #define HID_INTERFACE_NUMBER (HID_INTERFACE_OFFSET+usbHIDPart.startInterface) /* @@ -75,12 +80,16 @@ static volatile HIDBuffer_t hidBuffers[MAX_HID_BUFFERS] = {{ 0 }}; #define USB_HID_TX_ENDPOINT_INFO (&hidEndpoints[HID_ENDPOINT_TX]) #define USB_HID_TX_ENDP (hidEndpoints[HID_ENDPOINT_TX].address) +#define HID_ENDPOINT_RX 1 +#define USB_HID_RX_ENDPOINT_INFO (&hidEndpoints[HID_ENDPOINT_RX]) +#define USB_HID_RX_ENDP (hidEndpoints[HID_ENDPOINT_RX].address) typedef struct { //HID usb_descriptor_interface HID_Interface; HIDDescriptor HID_Descriptor; usb_descriptor_endpoint HIDDataInEndpoint; + usb_descriptor_endpoint HIDDataOutEndpoint; } __packed hid_part_config; static const hid_part_config hidPartConfigData = { @@ -89,7 +98,7 @@ static const hid_part_config hidPartConfigData = { .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, .bInterfaceNumber = HID_INTERFACE_OFFSET, // PATCH .bAlternateSetting = 0x00, - .bNumEndpoints = NUM_HID_ENDPOINTS, + .bNumEndpoints = 1, // PATCH .bInterfaceClass = USB_INTERFACE_CLASS_HID, .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_HID, .bInterfaceProtocol = 0x00, /* Common AT Commands */ @@ -113,20 +122,37 @@ static const hid_part_config hidPartConfigData = { .bmAttributes = USB_EP_TYPE_INTERRUPT, .wMaxPacketSize = 64, //PATCH .bInterval = 0x0A, - } + }, + .HIDDataOutEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = USB_DESCRIPTOR_ENDPOINT_OUT | 0, // PATCH: USB_HID_RX_ENDP + .bmAttributes = USB_EP_TYPE_INTERRUPT, + .wMaxPacketSize = 64, //PATCH + .bInterval = 0x0A, + }, }; +#define SIZE_hidPartConfigData_ONE_ENDPOINT (sizeof(hidPartConfigData)-sizeof(hidPartConfigData.HIDDataOutEndpoint)) +#define SIZE_hidPartConfigData_TWO_ENDPOINTS (sizeof(hidPartConfigData)) + static ONE_DESCRIPTOR HID_Hid_Descriptor = { (uint8*)&hidPartConfigData.HID_Descriptor, sizeof(hidPartConfigData.HID_Descriptor) }; -static USBEndpointInfo hidEndpoints[1] = { +static USBEndpointInfo hidEndpoints[2] = { { .callback = hidDataTxCb, .pmaSize = 64, .type = USB_GENERIC_ENDPOINT_TYPE_INTERRUPT, .tx = 1, + }, + { + .callback = hidDataRxCb, + .pmaSize = 64, + .type = USB_GENERIC_ENDPOINT_TYPE_INTERRUPT, + .tx = 0, } }; @@ -141,20 +167,24 @@ void usb_hid_setTXEPSize(uint32_t size) { #define OUT_16(s,v) *(uint16_t*)&OUT_BYTE(s,v) // OK on Cortex which can handle unaligned writes static void getHIDPartDescriptor(uint8* out) { - memcpy(out, &hidPartConfigData, sizeof(hid_part_config)); + memcpy(out, &hidPartConfigData, numEndpoints > 1 ? SIZE_hidPartConfigData_TWO_ENDPOINTS : SIZE_hidPartConfigData_ONE_ENDPOINT); // patch to reflect where the part goes in the descriptor OUT_BYTE(hidPartConfigData, HID_Interface.bInterfaceNumber) += usbHIDPart.startInterface; + OUT_BYTE(hidPartConfigData, HID_Interface.bNumEndpoints) = numEndpoints; OUT_BYTE(hidPartConfigData, HIDDataInEndpoint.bEndpointAddress) += USB_HID_TX_ENDP; uint16 size = usb_generic_chunks_length(reportDescriptorChunks); OUT_BYTE(hidPartConfigData, HID_Descriptor.descLenL) = (uint8)size; OUT_BYTE(hidPartConfigData, HID_Descriptor.descLenH) = (uint8)(size>>8); OUT_16(hidPartConfigData, HIDDataInEndpoint.wMaxPacketSize) = txEPSize; + OUT_16(hidPartConfigData, HIDDataOutEndpoint.wMaxPacketSize) = rxEPSize; + if (numEndpoints > 1) + OUT_BYTE(hidPartConfigData, HIDDataOutEndpoint.bEndpointAddress) += USB_HID_RX_ENDP; } USBCompositePart usbHIDPart = { .numInterfaces = 1, .numEndpoints = sizeof(hidEndpoints)/sizeof(*hidEndpoints), - .descriptorSize = sizeof(hid_part_config), + .descriptorSize = SIZE_hidPartConfigData_ONE_ENDPOINT, .getPartDescriptor = getHIDPartDescriptor, .usbInit = NULL, .usbReset = hidUSBReset, @@ -166,6 +196,25 @@ USBCompositePart usbHIDPart = { .endpoints = hidEndpoints }; +void usb_hid_setDedicatedRXEndpoint(void* buffer, uint16_t size, USBHIDOutputEndpointReceiver receiver, void* extra) { + if (buffer != NULL) { + numEndpoints = 2; + usbHIDPart.descriptorSize = SIZE_hidPartConfigData_TWO_ENDPOINTS; + hidEndpoints[1].pmaSize = size; + rxEPSize = size; + hidBufferRx = buffer; + rxReceiver = receiver; + rxReceiverExtra = extra; + } + else { + numEndpoints = 1; + usbHIDPart.descriptorSize = SIZE_hidPartConfigData_ONE_ENDPOINT; + hidBufferRx = NULL; + rxReceiver = NULL; + rxReceiverExtra = NULL; + } +} + #define HID_TX_BUFFER_SIZE 256 // must be power of 2 #define HID_TX_BUFFER_SIZE_MASK (HID_TX_BUFFER_SIZE-1) @@ -346,6 +395,23 @@ static void hidDataTxCb(void) hidBufferTx, HID_TX_BUFFER_SIZE, hid_tx_head, &hid_tx_tail, &transmitting); } +static void hidDataRxCb(void) +{ + USBEndpointInfo* ep = USB_HID_RX_ENDPOINT_INFO; + + if (hidBufferRx != NULL) { + uint32 didRead = usb_generic_read_to_buffer(ep, hidBufferRx, rxEPSize); + + if (didRead > 0) { + if (rxReceiver != NULL) + rxReceiver(rxReceiverExtra, hidBufferRx, didRead); + } + } + + usb_generic_enable_rx(ep); +} + + static void hidUSBReset(void) { /* Reset the RX/TX state */ diff --git a/STM32F1/libraries/USBComposite/usb_hid.h b/STM32F1/libraries/USBComposite/usb_hid.h index 092a7c964..f933b430f 100644 --- a/STM32F1/libraries/USBComposite/usb_hid.h +++ b/STM32F1/libraries/USBComposite/usb_hid.h @@ -51,6 +51,8 @@ extern USBCompositePart usbHIDPart; +typedef void (*USBHIDOutputEndpointReceiver)(void* extra, volatile void* buffer, uint16_t size); + typedef struct HIDBuffer_t { volatile uint8_t* buffer; // use HID_BUFFER_ALLOCATE_SIZE() to calculate amount of memory to allocate uint16_t bufferSize; // this should match HID_BUFFER_SIZE @@ -79,6 +81,7 @@ uint16_t usb_hid_get_data(uint8_t type, uint8_t reportID, uint8_t* out, uint8_t void usb_hid_set_feature(uint8_t reportID, uint8_t* data); void usb_hid_setTXEPSize(uint32_t size); uint32 usb_hid_get_pending(void); +void usb_hid_setDedicatedRXEndpoint(void* buffer, uint16_t size, USBHIDOutputEndpointReceiver receiver, void* extra); /* * HID Requests From dc35dd525d0fb9aee81b1f81a6abedbf8c4bbcf8 Mon Sep 17 00:00:00 2001 From: arpruss Date: Wed, 2 Feb 2022 21:27:53 -0600 Subject: [PATCH 3/4] Delete unneeded file --- STM32F1/libraries/USBComposite/branchlog.sh | 1 - 1 file changed, 1 deletion(-) delete mode 100644 STM32F1/libraries/USBComposite/branchlog.sh diff --git a/STM32F1/libraries/USBComposite/branchlog.sh b/STM32F1/libraries/USBComposite/branchlog.sh deleted file mode 100644 index 3647c45e8..000000000 --- a/STM32F1/libraries/USBComposite/branchlog.sh +++ /dev/null @@ -1 +0,0 @@ -svn log https://github.com/arpruss/USBComposite_stm32f1/branches/abstracted From 3f57bae85b2391537ea82995cba5e138305f1fc4 Mon Sep 17 00:00:00 2001 From: arpruss Date: Wed, 4 Jan 2023 11:09:44 -0600 Subject: [PATCH 4/4] update USBComposite to 1.0.7 --- STM32F1/libraries/USBComposite/Keyboard.cpp | 3 +- STM32F1/libraries/USBComposite/USBHID.h | 40 ++++- .../USBComposite/examples/mass/image.h | 2 +- .../USBComposite/examples/mass/mass.ino | 139 +++++++++--------- .../libraries/USBComposite/library.properties | 2 +- STM32F1/libraries/USBComposite/usb_hid.c | 21 ++- STM32F1/libraries/USBComposite/usb_hid.h | 3 +- 7 files changed, 131 insertions(+), 79 deletions(-) diff --git a/STM32F1/libraries/USBComposite/Keyboard.cpp b/STM32F1/libraries/USBComposite/Keyboard.cpp index 5d17c32c7..16b70b01f 100644 --- a/STM32F1/libraries/USBComposite/Keyboard.cpp +++ b/STM32F1/libraries/USBComposite/Keyboard.cpp @@ -179,7 +179,8 @@ uint8_t HIDKeyboard::getKeyCode(uint16_t k, uint8_t* modifiersP) } else { // shift key *modifiersP = 1<<(k-0x80); - return 0; + + return k-0x80+0xE0; } } diff --git a/STM32F1/libraries/USBComposite/USBHID.h b/STM32F1/libraries/USBComposite/USBHID.h index 34091a981..9de64757a 100644 --- a/STM32F1/libraries/USBComposite/USBHID.h +++ b/STM32F1/libraries/USBComposite/USBHID.h @@ -408,7 +408,7 @@ class USBHID { bool autoRegister = true; bool enabledHID = false; uint32 txPacketSize = 64; - struct usb_chunk* chunkList; + struct usb_chunk* chunkList = nullptr; // baseChunk holds any explicitly specified report descriptor that // overrides any report descriptors from the chain of registered profiles struct usb_chunk baseChunk = { 0, 0, 0 }; @@ -449,6 +449,12 @@ class USBHID { USBHID(bool _autoRegister=true) { autoRegister = _autoRegister; } + void setTXInterval(uint8 t) { + usb_hid_setTXInterval(t); + } + void setRXInterval(uint8 t) { + usb_hid_setRXInterval(t); + } }; class HIDReporter { @@ -650,6 +656,38 @@ class HIDConsumer : public HIDReporter { #define KEY_F10 0xCB #define KEY_F11 0xCC #define KEY_F12 0xCD +#define KEY_F13 (KEY_HID_OFFSET+0x68) +#define KEY_F14 (KEY_HID_OFFSET+0x69) +#define KEY_F15 (KEY_HID_OFFSET+0x6A) +#define KEY_KP_DOT (KEY_HID_OFFSET+0x63) +#define KEY_KP_ASTERISK (KEY_HID_OFFSET+0x55) +#define KEY_KP_PLUS (KEY_HID_OFFSET+0x57) +#define KEY_NUM_LOCK (KEY_HID_OFFSET+0x53) +#define KEY_KP_SLASH (KEY_HID_OFFSET+0x54) +#define KEY_KP_ENTER (KEY_HID_OFFSET+0x58) +#define KEY_KP_MINUS (KEY_HID_OFFSET+0x56) +#define KEY_KP_EQUAL (KEY_HID_OFFSET+0x86) +#define KEY_KP_0 (KEY_HID_OFFSET+0x62) +#define KEY_KP_1 (KEY_HID_OFFSET+0x59) +#define KEY_KP_2 (KEY_HID_OFFSET+0x5a) +#define KEY_KP_3 (KEY_HID_OFFSET+0x5b) +#define KEY_KP_4 (KEY_HID_OFFSET+0x5c) +#define KEY_KP_5 (KEY_HID_OFFSET+0x5d) +#define KEY_KP_6 (KEY_HID_OFFSET+0x5e) +#define KEY_KP_7 (KEY_HID_OFFSET+0x5f) +#define KEY_KP_8 (KEY_HID_OFFSET+0x60) +#define KEY_KP_9 (KEY_HID_OFFSET+0x61) +#define KEY_VOLUME_UP (KEY_HID_OFFSET+0x80) +#define KEY_VOLUME_DOWN (KEY_HID_OFFSET+0x81) +#define KEY_MUTE (KEY_HID_OFFSET+0x7f) +#define KEY_HELP (KEY_HID_OFFSET+0x75) +#define KEY_POWER (KEY_HID_OFFSET+0x66) +#define KEY_102ND (KEY_HID_OFFSET+0x64) +#define KEY_PRINT_SCREEN (KEY_HID_OFFSET+0x46) +#define KEY_SCROLL_LOCK (KEY_HID_OFFSET+0x47) +#define KEY_PAUSE (KEY_HID_OFFSET+0x48) + + typedef struct{ uint8_t reportID; diff --git a/STM32F1/libraries/USBComposite/examples/mass/image.h b/STM32F1/libraries/USBComposite/examples/mass/image.h index f81df9c06..ffa7c13d0 100644 --- a/STM32F1/libraries/USBComposite/examples/mass/image.h +++ b/STM32F1/libraries/USBComposite/examples/mass/image.h @@ -64,4 +64,4 @@ uint8 image[11776] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xF8,0xFF,0xFF, -}; +}; \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/examples/mass/mass.ino b/STM32F1/libraries/USBComposite/examples/mass/mass.ino index 47c141912..6862f14cd 100644 --- a/STM32F1/libraries/USBComposite/examples/mass/mass.ino +++ b/STM32F1/libraries/USBComposite/examples/mass/mass.ino @@ -1,71 +1,70 @@ -#include - -USBMassStorage MassStorage; -USBCompositeSerial CompositeSerial; - -#define PRODUCT_ID 0x29 - -#include "image.h" - -bool write(const uint8_t *writebuff, uint32_t memoryOffset, uint16_t transferLength) { - memcpy(image+SCSI_BLOCK_SIZE*memoryOffset, writebuff, SCSI_BLOCK_SIZE*transferLength); - - return true; -} - -bool read(uint8_t *readbuff, uint32_t memoryOffset, uint16_t transferLength) { - memcpy(readbuff, image+SCSI_BLOCK_SIZE*memoryOffset, SCSI_BLOCK_SIZE*transferLength); - - return true; -} - -char hexNibble(uint8 x) { - return x < 10 ? x + '0' : x + 'A' - 10; -} - -char* format16(uint16 c) { - static char str[6]; - str[5] = 0; - char *p = str+5; - do { - *--p = (c % 10) + '0'; - c /= 10; - } while(c); - return p; -} - -void dumpDrive() { - char hex[7] = "0x11,"; - CompositeSerial.print("uint8 image["); - CompositeSerial.print(format16(sizeof(image))); - CompositeSerial.println("] = {"); - int last; - for (last=sizeof(image)-1;last>=0 && image[last] == 0;last--); - if (last<0) last=0; - - for (int i=0; i<=last; i++) { - if (i && i % 16 == 0) - CompositeSerial.println(""); - hex[2] = hexNibble(image[i]>>4); - hex[3] = hexNibble(image[i]&0xF); - CompositeSerial.print(hex); - } - CompositeSerial.println("\n};\n"); -} - -void setup() { - USBComposite.setProductId(PRODUCT_ID); - MassStorage.setDriveData(0, sizeof(image)/SCSI_BLOCK_SIZE, read, write); - MassStorage.registerComponent(); - CompositeSerial.registerComponent(); - USBComposite.begin(); - delay(2000); -} - -void loop() { - MassStorage.loop(); - if (CompositeSerial.available() && 'd' == CompositeSerial.read()) { - dumpDrive(); - } -} +#include +USBMassStorage MassStorage; +USBCompositeSerial CompositeSerial; + +#define PRODUCT_ID 0x29 + +#include "image.h" + +bool write(const uint8_t *writebuff, uint32_t memoryOffset, uint16_t transferLength) { + memcpy(image+SCSI_BLOCK_SIZE*memoryOffset, writebuff, SCSI_BLOCK_SIZE*transferLength); + + return true; +} + +bool read(uint8_t *readbuff, uint32_t memoryOffset, uint16_t transferLength) { + memcpy(readbuff, image+SCSI_BLOCK_SIZE*memoryOffset, SCSI_BLOCK_SIZE*transferLength); + + return true; +} + +char hexNibble(uint8 x) { + return x < 10 ? x + '0' : x + 'A' - 10; +} + +char* format16(uint16 c) { + static char str[6]; + str[5] = 0; + char *p = str+5; + do { + *--p = (c % 10) + '0'; + c /= 10; + } while(c); + return p; +} + +void dumpDrive() { + char hex[7] = "0x11,"; + CompositeSerial.print("uint8 image["); + CompositeSerial.print(format16(sizeof(image))); + CompositeSerial.println("] = {"); + int last; + for (last=sizeof(image)-1;last>=0 && image[last] == 0;last--); + if (last<0) last=0; + + for (int i=0; i<=last; i++) { + if (i && i % 16 == 0) + CompositeSerial.println(""); + hex[2] = hexNibble(image[i]>>4); + hex[3] = hexNibble(image[i]&0xF); + CompositeSerial.print(hex); + } + CompositeSerial.println("\n};\n"); +} + +void setup() { + USBComposite.setProductId(PRODUCT_ID); + MassStorage.setDriveData(0, sizeof(image)/SCSI_BLOCK_SIZE, read, write); + MassStorage.registerComponent(); + CompositeSerial.registerComponent(); + USBComposite.begin(); + delay(2000); +} + +void loop() { + MassStorage.loop(); + if (CompositeSerial.available() && 'd' == CompositeSerial.read()) { + dumpDrive(); + } +} diff --git a/STM32F1/libraries/USBComposite/library.properties b/STM32F1/libraries/USBComposite/library.properties index 387790bb2..e01f95e67 100644 --- a/STM32F1/libraries/USBComposite/library.properties +++ b/STM32F1/libraries/USBComposite/library.properties @@ -1,5 +1,5 @@ name=USBComposite for STM32F1 -version=1.06 +version=1.0.8 author=Various email=arpruss@gmail.com sentence=USB HID / MIDI / mass storage / Audio library for STM32F1 diff --git a/STM32F1/libraries/USBComposite/usb_hid.c b/STM32F1/libraries/USBComposite/usb_hid.c index b89ff6ac2..b73a71c83 100644 --- a/STM32F1/libraries/USBComposite/usb_hid.c +++ b/STM32F1/libraries/USBComposite/usb_hid.c @@ -53,6 +53,8 @@ static uint8 IdleValue = 1; static uint8 ProtocolValue = 0; static uint32 txEPSize = 64; static uint32 rxEPSize = 64; +static uint8 txInterval = 0x0A; +static uint8 rxInterval = 0x0A; static volatile int8 transmitting; static struct usb_chunk* reportDescriptorChunks = NULL; @@ -121,7 +123,7 @@ static const hid_part_config hidPartConfigData = { .bEndpointAddress = USB_DESCRIPTOR_ENDPOINT_IN | 0, // PATCH: USB_HID_TX_ENDP .bmAttributes = USB_EP_TYPE_INTERRUPT, .wMaxPacketSize = 64, //PATCH - .bInterval = 0x0A, + .bInterval = 0x0A, //PATCH }, .HIDDataOutEndpoint = { .bLength = sizeof(usb_descriptor_endpoint), @@ -129,7 +131,7 @@ static const hid_part_config hidPartConfigData = { .bEndpointAddress = USB_DESCRIPTOR_ENDPOINT_OUT | 0, // PATCH: USB_HID_RX_ENDP .bmAttributes = USB_EP_TYPE_INTERRUPT, .wMaxPacketSize = 64, //PATCH - .bInterval = 0x0A, + .bInterval = 0x0A, //PATCH }, }; @@ -141,6 +143,14 @@ static ONE_DESCRIPTOR HID_Hid_Descriptor = { sizeof(hidPartConfigData.HID_Descriptor) }; +void usb_hid_setTXInterval(uint8_t t) { + txInterval = t; +} + +void usb_hid_setRXInterval(uint8_t t) { + rxInterval = t; +} + static USBEndpointInfo hidEndpoints[2] = { { .callback = hidDataTxCb, @@ -176,9 +186,12 @@ static void getHIDPartDescriptor(uint8* out) { OUT_BYTE(hidPartConfigData, HID_Descriptor.descLenL) = (uint8)size; OUT_BYTE(hidPartConfigData, HID_Descriptor.descLenH) = (uint8)(size>>8); OUT_16(hidPartConfigData, HIDDataInEndpoint.wMaxPacketSize) = txEPSize; - OUT_16(hidPartConfigData, HIDDataOutEndpoint.wMaxPacketSize) = rxEPSize; - if (numEndpoints > 1) + OUT_BYTE(hidPartConfigData, HIDDataInEndpoint.bInterval) = txInterval; + if (numEndpoints > 1) { OUT_BYTE(hidPartConfigData, HIDDataOutEndpoint.bEndpointAddress) += USB_HID_RX_ENDP; + OUT_BYTE(hidPartConfigData, HIDDataOutEndpoint.bInterval) = rxInterval; + OUT_16(hidPartConfigData, HIDDataOutEndpoint.wMaxPacketSize) = rxEPSize; + } } USBCompositePart usbHIDPart = { diff --git a/STM32F1/libraries/USBComposite/usb_hid.h b/STM32F1/libraries/USBComposite/usb_hid.h index f933b430f..9dac06788 100644 --- a/STM32F1/libraries/USBComposite/usb_hid.h +++ b/STM32F1/libraries/USBComposite/usb_hid.h @@ -82,6 +82,8 @@ void usb_hid_set_feature(uint8_t reportID, uint8_t* data); void usb_hid_setTXEPSize(uint32_t size); uint32 usb_hid_get_pending(void); void usb_hid_setDedicatedRXEndpoint(void* buffer, uint16_t size, USBHIDOutputEndpointReceiver receiver, void* extra); +void usb_hid_setTXInterval(uint8_t t); +void usb_hid_setRXInterval(uint8_t t); /* * HID Requests @@ -138,7 +140,6 @@ typedef struct uint32 usb_hid_tx(const uint8* buf, uint32 len); uint32 usb_hid_tx_mod(const uint8* buf, uint32 len); - uint32 usb_hid_data_available(void); /* in RX buffer */