From 18d1654195c30c3a2ab913574f487c94f3967ffc Mon Sep 17 00:00:00 2001 From: arpruss Date: Thu, 12 Apr 2018 20:45:59 -0500 Subject: [PATCH] usbcomposite library --- STM32F1/libraries/USBComposite/AbsMouse.cpp | 56 ++ .../libraries/USBComposite/BootKeyboard.cpp | 7 + STM32F1/libraries/USBComposite/Consumer.cpp | 13 + STM32F1/libraries/USBComposite/HIDReports.cpp | 14 + STM32F1/libraries/USBComposite/Joystick.cpp | 118 ++++ STM32F1/libraries/USBComposite/Keyboard.cpp | 258 ++++++++ STM32F1/libraries/USBComposite/LICENSE | 45 ++ STM32F1/libraries/USBComposite/MidiSpecs.h | 151 +++++ STM32F1/libraries/USBComposite/MinSysex.c | 306 +++++++++ STM32F1/libraries/USBComposite/MinSysex.h | 37 ++ STM32F1/libraries/USBComposite/Mouse.cpp | 57 ++ STM32F1/libraries/USBComposite/README.md | 88 +++ .../libraries/USBComposite/USBComposite.cpp | 147 +++++ STM32F1/libraries/USBComposite/USBComposite.h | 64 ++ .../USBComposite/USBCompositeSerial.cpp | 274 ++++++++ .../USBComposite/USBCompositeSerial.h | 40 ++ STM32F1/libraries/USBComposite/USBHID.cpp | 180 ++++++ STM32F1/libraries/USBComposite/USBHID.h | 608 ++++++++++++++++++ STM32F1/libraries/USBComposite/USBMIDI.cpp | 469 ++++++++++++++ STM32F1/libraries/USBComposite/USBMIDI.h | 186 ++++++ .../libraries/USBComposite/USBMassStorage.cpp | 45 ++ .../libraries/USBComposite/USBMassStorage.h | 25 + STM32F1/libraries/USBComposite/USBXBox360.cpp | 173 +++++ STM32F1/libraries/USBComposite/USBXBox360.h | 58 ++ .../examples/BootKeyboard/BootKeyboard.ino | 15 + .../examples/absmouse/absmouse.ino | 25 + .../examples/consumer/consumer.ino | 18 + .../keyboardwithleds/keyboardwithleds.ino | 14 + .../USBComposite/examples/mass/image.h | 67 ++ .../USBComposite/examples/mass/mass.ino | 65 ++ .../USBComposite/examples/midiin/midiin.ino | 27 + .../USBComposite/examples/midiout/midiout.ino | 17 + .../USBComposite/examples/rawhid/rawhid.ino | 24 + .../USBComposite/examples/rawhid/send.py | 26 + .../examples/sdreader/sdreader.ino | 52 ++ .../simplejoystick/simplejoystick.ino | 13 + .../simplekeyboard/simplekeyboard.ino | 13 + .../examples/softjoystick/send.py | 60 ++ .../examples/softjoystick/softjoystick.ino | 47 ++ .../examples/twojoysticks/twojoysticks.ino | 40 ++ .../USBComposite/examples/x360/x360.ino | 15 + STM32F1/libraries/USBComposite/keywords.txt | 89 +++ .../libraries/USBComposite/library.properties | 10 + STM32F1/libraries/USBComposite/usb_generic.c | 531 +++++++++++++++ STM32F1/libraries/USBComposite/usb_generic.h | 60 ++ STM32F1/libraries/USBComposite/usb_hid.c | 578 +++++++++++++++++ STM32F1/libraries/USBComposite/usb_hid.h | 153 +++++ STM32F1/libraries/USBComposite/usb_mass.c | 464 +++++++++++++ STM32F1/libraries/USBComposite/usb_mass.h | 112 ++++ .../USBComposite/usb_mass_internal.h | 12 + STM32F1/libraries/USBComposite/usb_mass_mal.c | 42 ++ STM32F1/libraries/USBComposite/usb_mass_mal.h | 39 ++ .../libraries/USBComposite/usb_midi_device.c | 532 +++++++++++++++ .../libraries/USBComposite/usb_midi_device.h | 189 ++++++ STM32F1/libraries/USBComposite/usb_scsi.c | 333 ++++++++++ STM32F1/libraries/USBComposite/usb_scsi.h | 96 +++ .../libraries/USBComposite/usb_scsi_data.c | 120 ++++ STM32F1/libraries/USBComposite/usb_serial.c | 580 +++++++++++++++++ STM32F1/libraries/USBComposite/usb_serial.h | 157 +++++ STM32F1/libraries/USBComposite/usb_setup.cpp | 61 ++ STM32F1/libraries/USBComposite/usb_x360.c | 486 ++++++++++++++ STM32F1/libraries/USBComposite/usb_x360.h | 75 +++ 62 files changed, 8676 insertions(+) create mode 100644 STM32F1/libraries/USBComposite/AbsMouse.cpp create mode 100644 STM32F1/libraries/USBComposite/BootKeyboard.cpp create mode 100644 STM32F1/libraries/USBComposite/Consumer.cpp create mode 100644 STM32F1/libraries/USBComposite/HIDReports.cpp create mode 100644 STM32F1/libraries/USBComposite/Joystick.cpp create mode 100644 STM32F1/libraries/USBComposite/Keyboard.cpp create mode 100644 STM32F1/libraries/USBComposite/LICENSE create mode 100644 STM32F1/libraries/USBComposite/MidiSpecs.h create mode 100644 STM32F1/libraries/USBComposite/MinSysex.c create mode 100644 STM32F1/libraries/USBComposite/MinSysex.h create mode 100644 STM32F1/libraries/USBComposite/Mouse.cpp create mode 100644 STM32F1/libraries/USBComposite/README.md create mode 100644 STM32F1/libraries/USBComposite/USBComposite.cpp create mode 100644 STM32F1/libraries/USBComposite/USBComposite.h create mode 100644 STM32F1/libraries/USBComposite/USBCompositeSerial.cpp create mode 100644 STM32F1/libraries/USBComposite/USBCompositeSerial.h create mode 100644 STM32F1/libraries/USBComposite/USBHID.cpp create mode 100644 STM32F1/libraries/USBComposite/USBHID.h create mode 100644 STM32F1/libraries/USBComposite/USBMIDI.cpp create mode 100644 STM32F1/libraries/USBComposite/USBMIDI.h create mode 100644 STM32F1/libraries/USBComposite/USBMassStorage.cpp create mode 100644 STM32F1/libraries/USBComposite/USBMassStorage.h create mode 100644 STM32F1/libraries/USBComposite/USBXBox360.cpp create mode 100644 STM32F1/libraries/USBComposite/USBXBox360.h create mode 100644 STM32F1/libraries/USBComposite/examples/BootKeyboard/BootKeyboard.ino create mode 100644 STM32F1/libraries/USBComposite/examples/absmouse/absmouse.ino create mode 100644 STM32F1/libraries/USBComposite/examples/consumer/consumer.ino create mode 100644 STM32F1/libraries/USBComposite/examples/keyboardwithleds/keyboardwithleds.ino create mode 100644 STM32F1/libraries/USBComposite/examples/mass/image.h create mode 100644 STM32F1/libraries/USBComposite/examples/mass/mass.ino create mode 100644 STM32F1/libraries/USBComposite/examples/midiin/midiin.ino create mode 100644 STM32F1/libraries/USBComposite/examples/midiout/midiout.ino create mode 100644 STM32F1/libraries/USBComposite/examples/rawhid/rawhid.ino create mode 100644 STM32F1/libraries/USBComposite/examples/rawhid/send.py create mode 100644 STM32F1/libraries/USBComposite/examples/sdreader/sdreader.ino create mode 100644 STM32F1/libraries/USBComposite/examples/simplejoystick/simplejoystick.ino create mode 100644 STM32F1/libraries/USBComposite/examples/simplekeyboard/simplekeyboard.ino create mode 100644 STM32F1/libraries/USBComposite/examples/softjoystick/send.py create mode 100644 STM32F1/libraries/USBComposite/examples/softjoystick/softjoystick.ino create mode 100644 STM32F1/libraries/USBComposite/examples/twojoysticks/twojoysticks.ino create mode 100644 STM32F1/libraries/USBComposite/examples/x360/x360.ino create mode 100644 STM32F1/libraries/USBComposite/keywords.txt create mode 100644 STM32F1/libraries/USBComposite/library.properties create mode 100644 STM32F1/libraries/USBComposite/usb_generic.c create mode 100644 STM32F1/libraries/USBComposite/usb_generic.h create mode 100644 STM32F1/libraries/USBComposite/usb_hid.c create mode 100644 STM32F1/libraries/USBComposite/usb_hid.h create mode 100644 STM32F1/libraries/USBComposite/usb_mass.c create mode 100644 STM32F1/libraries/USBComposite/usb_mass.h create mode 100644 STM32F1/libraries/USBComposite/usb_mass_internal.h create mode 100644 STM32F1/libraries/USBComposite/usb_mass_mal.c create mode 100644 STM32F1/libraries/USBComposite/usb_mass_mal.h create mode 100644 STM32F1/libraries/USBComposite/usb_midi_device.c create mode 100644 STM32F1/libraries/USBComposite/usb_midi_device.h create mode 100644 STM32F1/libraries/USBComposite/usb_scsi.c create mode 100644 STM32F1/libraries/USBComposite/usb_scsi.h create mode 100644 STM32F1/libraries/USBComposite/usb_scsi_data.c create mode 100644 STM32F1/libraries/USBComposite/usb_serial.c create mode 100644 STM32F1/libraries/USBComposite/usb_serial.h create mode 100644 STM32F1/libraries/USBComposite/usb_setup.cpp create mode 100644 STM32F1/libraries/USBComposite/usb_x360.c create mode 100644 STM32F1/libraries/USBComposite/usb_x360.h diff --git a/STM32F1/libraries/USBComposite/AbsMouse.cpp b/STM32F1/libraries/USBComposite/AbsMouse.cpp new file mode 100644 index 0000000..91a27d0 --- /dev/null +++ b/STM32F1/libraries/USBComposite/AbsMouse.cpp @@ -0,0 +1,56 @@ +#include "USBHID.h" + +//================================================================================ +//================================================================================ +// Mouse + +void HIDAbsMouse::begin(void){ +} + +void HIDAbsMouse::end(void){ +} + +void HIDAbsMouse::click(uint8_t b) +{ + report.wheel = 0; + report.buttons = b; + sendReport(); + report.buttons = 0; + sendReport(); +} + +void HIDAbsMouse::move(int16 x, int16 y, int8 wheel) +{ + report.x = x; + report.y = y; + report.wheel = wheel; + + sendReport(); +} + +void HIDAbsMouse::buttons(uint8_t b) +{ + if (b != report.buttons) + { + report.wheel = 0; + report.buttons = b; + sendReport(); + } +} + +void HIDAbsMouse::press(uint8_t b) +{ + buttons(report.buttons | b); +} + +void HIDAbsMouse::release(uint8_t b) +{ + buttons(report.buttons & ~b); +} + +bool HIDAbsMouse::isPressed(uint8_t b) +{ + if ((b & report.buttons) != 0) + return true; + return false; +} diff --git a/STM32F1/libraries/USBComposite/BootKeyboard.cpp b/STM32F1/libraries/USBComposite/BootKeyboard.cpp new file mode 100644 index 0000000..195f4ac --- /dev/null +++ b/STM32F1/libraries/USBComposite/BootKeyboard.cpp @@ -0,0 +1,7 @@ +#include "USBHID.h" + +//================================================================================ +//================================================================================ +// Keyboard + +HIDKeyboard BootKeyboard(0); diff --git a/STM32F1/libraries/USBComposite/Consumer.cpp b/STM32F1/libraries/USBComposite/Consumer.cpp new file mode 100644 index 0000000..6c896b0 --- /dev/null +++ b/STM32F1/libraries/USBComposite/Consumer.cpp @@ -0,0 +1,13 @@ +#include "USBHID.h" + +void HIDConsumer::begin(void) {} +void HIDConsumer::end(void) {} +void HIDConsumer::press(uint16_t button) { + report.button = button; + sendReport(); +} + +void HIDConsumer::release() { + report.button = 0; + sendReport(); +} diff --git a/STM32F1/libraries/USBComposite/HIDReports.cpp b/STM32F1/libraries/USBComposite/HIDReports.cpp new file mode 100644 index 0000000..bd00b54 --- /dev/null +++ b/STM32F1/libraries/USBComposite/HIDReports.cpp @@ -0,0 +1,14 @@ +#include "USBHID.h" + +#define REPORT(name, ...) \ + static uint8_t raw_ ## name[] = { __VA_ARGS__ }; \ + static const HIDReportDescriptor desc_ ## name = { raw_ ##name, sizeof(raw_ ##name) }; \ + const HIDReportDescriptor* hidReport ## name = & desc_ ## name; + +REPORT(KeyboardMouseJoystick, HID_MOUSE_REPORT_DESCRIPTOR(), HID_KEYBOARD_REPORT_DESCRIPTOR(), HID_JOYSTICK_REPORT_DESCRIPTOR()); +REPORT(KeyboardMouse, HID_MOUSE_REPORT_DESCRIPTOR(), HID_KEYBOARD_REPORT_DESCRIPTOR()); +REPORT(Keyboard, HID_KEYBOARD_REPORT_DESCRIPTOR()); +REPORT(Mouse, HID_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()); diff --git a/STM32F1/libraries/USBComposite/Joystick.cpp b/STM32F1/libraries/USBComposite/Joystick.cpp new file mode 100644 index 0000000..969cac5 --- /dev/null +++ b/STM32F1/libraries/USBComposite/Joystick.cpp @@ -0,0 +1,118 @@ +#include "USBHID.h" + +// This code requires gcc on low-endian devices. + +//================================================================================ +//================================================================================ +// Joystick + +void HIDJoystick::begin(void){ +} + +void HIDJoystick::end(void){ +} + +void HIDJoystick::setManualReportMode(bool mode) { + manualReport = mode; +} + +bool HIDJoystick::getManualReportMode() { + return manualReport; +} + +void HIDJoystick::safeSendReport() { + if (!manualReport) { + sendReport(); + } +} + +void HIDJoystick::button(uint8_t button, bool val){ + uint32_t mask = ((uint32_t)1 << (button-1)); + + if (val) { + joyReport.buttons |= mask; + } else { + joyReport.buttons &= ~mask; + } + + safeSendReport(); +} + +void HIDJoystick::X(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.x = val; + + safeSendReport(); +} + +void HIDJoystick::Y(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.y = val; + + safeSendReport(); +} + +void HIDJoystick::position(uint16_t x, uint16_t y){ + if (x > 1023) x = 1023; + if (y > 1023) y = 1023; + joyReport.x = x; + joyReport.y = y; + + safeSendReport(); +} + +void HIDJoystick::Xrotate(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.rx = val; + + safeSendReport(); +} + +void HIDJoystick::Yrotate(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.ry = val; + + safeSendReport(); +} + +void HIDJoystick::sliderLeft(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.sliderLeft = val; + + safeSendReport(); +} + +void HIDJoystick::sliderRight(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.sliderRight = val; + + safeSendReport(); +} + +void HIDJoystick::slider(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.sliderLeft = val; + joyReport.sliderRight = val; + + safeSendReport(); +} + +void HIDJoystick::hat(int16_t dir){ + uint8_t val; + if (dir < 0) val = 15; + else if (dir < 23) val = 0; + else if (dir < 68) val = 1; + else if (dir < 113) val = 2; + else if (dir < 158) val = 3; + else if (dir < 203) val = 4; + else if (dir < 245) val = 5; + else if (dir < 293) val = 6; + else if (dir < 338) val = 7; + else val = 15; + + joyReport.hat = val; + + safeSendReport(); +} + +HIDJoystick Joystick; diff --git a/STM32F1/libraries/USBComposite/Keyboard.cpp b/STM32F1/libraries/USBComposite/Keyboard.cpp new file mode 100644 index 0000000..a658cc5 --- /dev/null +++ b/STM32F1/libraries/USBComposite/Keyboard.cpp @@ -0,0 +1,258 @@ +#include "USBHID.h" +#include + +//================================================================================ +//================================================================================ +// Keyboard + +#define SHIFT 0x80 +static const uint8_t ascii_to_hid[128] = +{ + 0x00, // NUL + 0x00, // SOH + 0x00, // STX + 0x00, // ETX + 0x00, // EOT + 0x00, // ENQ + 0x00, // ACK + 0x00, // BEL + 0x2a, // BS Backspace + 0x2b, // TAB Tab + 0x28, // LF Enter + 0x00, // VT + 0x00, // FF + 0x00, // CR + 0x00, // SO + 0x00, // SI + 0x00, // DEL + 0x00, // DC1 + 0x00, // DC2 + 0x00, // DC3 + 0x00, // DC4 + 0x00, // NAK + 0x00, // SYN + 0x00, // ETB + 0x00, // CAN + 0x00, // EM + 0x00, // SUB + 0x00, // ESC + 0x00, // FS + 0x00, // GS + 0x00, // RS + 0x00, // US + + 0x2c, // ' ' + 0x1e|SHIFT, // ! + 0x34|SHIFT, // " + 0x20|SHIFT, // # + 0x21|SHIFT, // $ + 0x22|SHIFT, // % + 0x24|SHIFT, // & + 0x34, // ' + 0x26|SHIFT, // ( + 0x27|SHIFT, // ) + 0x25|SHIFT, // * + 0x2e|SHIFT, // + + 0x36, // , + 0x2d, // - + 0x37, // . + 0x38, // / + 0x27, // 0 + 0x1e, // 1 + 0x1f, // 2 + 0x20, // 3 + 0x21, // 4 + 0x22, // 5 + 0x23, // 6 + 0x24, // 7 + 0x25, // 8 + 0x26, // 9 + 0x33|SHIFT, // : + 0x33, // ; + 0x36|SHIFT, // < + 0x2e, // = + 0x37|SHIFT, // > + 0x38|SHIFT, // ? + 0x1f|SHIFT, // @ + 0x04|SHIFT, // A + 0x05|SHIFT, // B + 0x06|SHIFT, // C + 0x07|SHIFT, // D + 0x08|SHIFT, // E + 0x09|SHIFT, // F + 0x0a|SHIFT, // G + 0x0b|SHIFT, // H + 0x0c|SHIFT, // I + 0x0d|SHIFT, // J + 0x0e|SHIFT, // K + 0x0f|SHIFT, // L + 0x10|SHIFT, // M + 0x11|SHIFT, // N + 0x12|SHIFT, // O + 0x13|SHIFT, // P + 0x14|SHIFT, // Q + 0x15|SHIFT, // R + 0x16|SHIFT, // S + 0x17|SHIFT, // T + 0x18|SHIFT, // U + 0x19|SHIFT, // V + 0x1a|SHIFT, // W + 0x1b|SHIFT, // X + 0x1c|SHIFT, // Y + 0x1d|SHIFT, // Z + 0x2f, // [ + 0x31, // bslash + 0x30, // ] + 0x23|SHIFT, // ^ + 0x2d|SHIFT, // _ + 0x35, // ` + 0x04, // a + 0x05, // b + 0x06, // c + 0x07, // d + 0x08, // e + 0x09, // f + 0x0a, // g + 0x0b, // h + 0x0c, // i + 0x0d, // j + 0x0e, // k + 0x0f, // l + 0x10, // m + 0x11, // n + 0x12, // o + 0x13, // p + 0x14, // q + 0x15, // r + 0x16, // s + 0x17, // t + 0x18, // u + 0x19, // v + 0x1a, // w + 0x1b, // x + 0x1c, // y + 0x1d, // z + 0x2f|SHIFT, // + 0x31|SHIFT, // | + 0x30|SHIFT, // } + 0x35|SHIFT, // ~ + 0 // DEL +}; + +void HIDKeyboard::begin(void){ + USBHID.addOutputBuffer(&ledData); +} + +void HIDKeyboard::end(void) { +} + +// 136: non-printing key +// shift -> 0x02 +// modifiers: 128 --> bit shift + +uint8_t HIDKeyboard::getKeyCode(uint8_t k, uint8_t* modifiersP) +{ + *modifiersP = 0; + + if (adjustForHostCapsLock && (getLEDs() & 0x02)) { // capslock is down on host OS, so host will reverse + if ('a' <= k && k <= 'z') + k += 'A'-'a'; + else if ('A' <= k && k <= 'Z') + k += 'a'-'A'; + } + + if (k < 0x80) { + k = ascii_to_hid[k]; + if (k & SHIFT) { + k &= 0x7f; + *modifiersP = 0x02; + } + return k; + } + if (k >= 0x88) { // non-printing key, Arduino format + return k - 0x88; + } + else { // shift key + *modifiersP = 1<<(k-0x80); + return 0; + } +} + +size_t HIDKeyboard::press(uint8_t k) { + uint8_t modifiers; + + k = getKeyCode(k, &modifiers); + + if (k == 0) { + if (modifiers == 0) { + return 0; + } + } + else { + for (unsigned i = 0; i. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/MidiSpecs.h b/STM32F1/libraries/USBComposite/MidiSpecs.h new file mode 100644 index 0000000..6d2acbe --- /dev/null +++ b/STM32F1/libraries/USBComposite/MidiSpecs.h @@ -0,0 +1,151 @@ +/*--------------------------------------------------------------------------MidiSpecs.h + * + * These defines are based on specs created by the USB and MMA standards organizations. + * There are not a lot of other ways to code them so licensing this is rather ludicrous. + * However, in order to be able to embed this in client projects, and avoid the stupidity + * of enforced open everything I will declare the following about this file. + * + * Copyright (c) 2011 Donald Delmar Davis, Suspect Devices + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/* + * USB midi commands from + * MIDI10.pdf "Universal Serial Bus Device Class Definition for MIDI Devices" + * REV 1. (1999) + * http://www.usb.org/developers/devclass_docs/midi10.pdf + * + */ + +#ifndef __LETS_MIDI_SPECS_H__ +#define __LETS_MIDI_SPECS_H__ +#include +#include +// rework this for the different architectures.... +#if defined(__GNUC__) +typedef struct +{ + unsigned cin : 4; // this is the low nibble. + unsigned cable : 4; +// uint8_t cin; + uint8_t midi0; + uint8_t midi1; + uint8_t midi2; +} __attribute__ ((__packed__)) MIDI_EVENT_PACKET_t ; +#else +typedef struct // may need to be adjusted for other compilers and bitfield order... +{ + unsigned cable : 4; + unsigned cin : 4; + uint8_t midi0; + uint8_t midi1; + uint8_t midi2; +} MIDI_EVENT_PACKET_t ; +#endif + + +#define CIN_MISC_FUNCTION 0x00 /* Reserved for future extension. */ +#define CIN_CABLE_EVENT 0x01 /* Reserved for future extension. */ +#define CIN_2BYTE_SYS_COMMON 0x02 /* 2Bytes -- MTC, SongSelect, etc. */ +#define CIN_3BYTE_SYS_COMMON 0x03 /* 3Bytes -- SPP, etc. */ +#define CIN_SYSEX 0x04 /* 3Bytes */ +#define CIN_SYSEX_ENDS_IN_1 0x05 /* 1Bytes */ +#define CIN_SYSEX_ENDS_IN_2 0x06 /* 2Bytes */ +#define CIN_SYSEX_ENDS_IN_3 0x07 /* 3Bytes */ +#define CIN_NOTE_OFF 0x08 /* 3Bytes */ +#define CIN_NOTE_ON 0x09 /* 3Bytes */ +#define CIN_AFTER_TOUCH 0x0A /* 3Bytes */ +#define CIN_CONTROL_CHANGE 0x0B /* 3Bytes */ +#define CIN_PROGRAM_CHANGE 0x0C /* 2Bytes */ +#define CIN_CHANNEL_PRESSURE 0x0D /* 2Bytes */ +#define CIN_PITCH_WHEEL 0x0E /* 3Bytes */ +#define CIN_1BYTE 0x0F /* 1Bytes */ +//#define CIN_IS_SYSEX(cin) ((cin == CIN_SYSEX)||(cin == CIN_SYSEX_ENDS_IN_1)||(cin == CIN_SYSEX_ENDS_IN_2)||(cin == CIN_SYSEX_ENDS_IN_3)) +#define CIN_IS_SYSEX(cin) ( ((cin) & ~(0x08)) && ((cin) &0x04) ) + +/* + * MIDI V1 message definitions these are from the MMA document + * http://www.midi.org/techspecs/midimessages.php + */ +#define MIDIv1_BAUD_RATE 31250 + +/* + * parse midi (v1) message macros + */ +#define MIDIv1_IS_STATUS(b) ((b) & 0x80) +#define MIDIv1_IS_VOICE(b) ((b) <= 0xEF) +#define MIDIv1_VOICE_COMMAND(b) ((b) & 0xF0) +#define MIDIv1_VOICE_CHANNEL(b) ((b) & 0x0F) +#define MIDIv1_IS_SYSCOMMON(b) (((b) >= 0xF0) & ((b) < 0xF8)) +#define MIDIv1_IS_REALTIME(b) ((b) >= 0xF8) + +/* + * Voice category messages + */ +#define MIDIv1_NOTE_OFF 0x80 /* 2 bytes data -- CIN_NOTE_OFF */ +#define MIDIv1_NOTE_ON 0x90 /* 2 bytes data -- CIN_NOTE_ON */ +#define MIDIv1_AFTER_TOUCH 0xA0 /* 2 bytes data -- CIN_AFTER_TOUCH */ +#define MIDIv1_CONTROL_CHANGE 0xB0 /* 2 bytes data -- CIN_CONTROL_CHANGE */ +#define MIDIv1_PROGRAM_CHANGE 0xC0 /* 1 byte data -- CIN_PROGRAM_CHANGE */ +#define MIDIv1_CHANNEL_PRESSURE 0xD0 /* 1 byte data -- CIN_CHANNEL_PRESSURE */ +#define MIDIv1_PITCH_WHEEL 0xE0 /* 2 bytes data -- CIN_PITCH_WHEEL */ + +/* + * System common category messages + */ +#define MIDIv1_SYSEX_START 0xF0 +#define MIDIv1_SYSEX_END 0xF7 +#define MIDIv1_MTC_QUARTER_FRAME 0xF1 /* 1 byte data -- CIN_2BYTE_SYS_COMMON */ +#define MIDIv1_SONG_POSITION_PTR 0xF2 /* 2 bytes data -- CIN_3BYTE_SYS_COMMON */ +#define MIDIv1_SONG_SELECT 0xF3 /* 1 byte data -- CIN_2BYTE_SYS_COMMON */ +#define MIDIv1_TUNE_REQUEST 0xF6 /* no data -- CIN_1BYTE */ + +/* + * Realtime category messages, can be sent anytime + */ +#define MIDIv1_CLOCK 0xF8 /* no data -- CIN_1BYTE */ +#define MIDIv1_TICK 0xF9 /* no data -- CIN_1BYTE */ +#define MIDIv1_START 0xFA /* no data -- CIN_1BYTE */ +#define MIDIv1_CONTINUE 0xFB /* no data -- CIN_1BYTE */ +#define MIDIv1_STOP 0xFC /* no data -- CIN_1BYTE */ +#define MIDIv1_ACTIVE_SENSE 0xFE /* no data -- CIN_1BYTE */ +#define MIDIv1_RESET 0xFF /* no data -- CIN_1BYTE */ + +/* + * sysex universal id's + */ +#define MIDIv1_UNIVERSAL_REALTIME_ID 0x7F +#define MIDIv1_UNIVERSAL_NON_REALTIME_ID 0x7E +#define MIDIv1_UNIVERSAL_ALL_CHANNELS 0x7F +/* + * Susbset of universal sysex (general info request) + * As described http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec.htm + */ +#define USYSEX_NON_REAL_TIME 0x7E +#define USYSEX_REAL_TIME 0x7F +#define USYSEX_ALL_CHANNELS 0x7F +#define USYSEX_GENERAL_INFO 0x06 +#define USYSEX_GI_ID_REQUEST 0x01 +#define USYSEX_GI_ID_RESPONSE 0x02 + + +#endif + + diff --git a/STM32F1/libraries/USBComposite/MinSysex.c b/STM32F1/libraries/USBComposite/MinSysex.c new file mode 100644 index 0000000..f9a54d3 --- /dev/null +++ b/STM32F1/libraries/USBComposite/MinSysex.c @@ -0,0 +1,306 @@ +// +// MinSysex.c +// LibMaple4Midi +// +// Created by Donald D Davis on 4/11/13. +// Copyright (c) 2013 Suspect Devices. All rights reserved. +// Modified BSD Liscense +/* + 0xF0 SysEx + 0x7E Non-Realtime + 0x7F The SysEx channel. Could be from 0x00 to 0x7F. + Here we set it to "disregard channel". + 0x06 Sub-ID -- General Information + 0x01 Sub-ID2 -- Identity Request + 0xF7 End of SysEx +---- response + 0xF0 SysEx + 0x7E Non-Realtime + 0x7F The SysEx channel. Could be from 0x00 to 0x7F. + Here we set it to "disregard channel". + 0x06 Sub-ID -- General Information + 0x02 Sub-ID2 -- Identity Reply + 0xID Manufacturer's ID + 0xf1 The f1 and f2 bytes make up the family code. Each + 0xf2 manufacturer assigns different family codes to his products. + 0xp1 The p1 and p2 bytes make up the model number. Each + 0xp2 manufacturer assigns different model numbers to his products. + 0xv1 The v1, v2, v3 and v4 bytes make up the version number. + 0xv2 + 0xv3 + 0xv4 + 0xF7 End of SysEx +*/ + +#define USB_MIDI +#ifdef USB_MIDI + +// change this to packets +#define STANDARD_ID_RESPONSE_LENGTH 7 + +#include "usb_midi_device.h" +#include +#include +#include +//#include + + +#define MAX_SYSEX_SIZE 256 + +/********************************* ACHTUNG! ignores usbmidi cable ********************************/ +/*const MIDI_EVENT_PACKET_t standardIDResponse[]={ + { DEFAULT_MIDI_CABLE, + CIN_SYSEX, + MIDIv1_SYSEX_START, + USYSEX_NON_REAL_TIME, + USYSEX_ALL_CHANNELS}, + { DEFAULT_MIDI_CABLE, + CIN_SYSEX, + USYSEX_GENERAL_INFO, + USYSEX_GI_ID_RESPONSE, + LEAFLABS_MMA_VENDOR_1}, + { DEFAULT_MIDI_CABLE, + CIN_SYSEX, + LEAFLABS_MMA_VENDOR_2, // extended ID + LEAFLABS_MMA_VENDOR_3, // extended ID + 1}, // family #1 + { DEFAULT_MIDI_CABLE, + CIN_SYSEX, + 2, // family #2 + 1, // part #1 + 2}, // part #2 + { DEFAULT_MIDI_CABLE, + CIN_SYSEX, + 0, // version 1 + 0, // version 2 + 1}, // version 3 + { DEFAULT_MIDI_CABLE, + CIN_SYSEX_ENDS_IN_2, + '!', // lgl compatible + MIDIv1_SYSEX_END, + 0} +}; +*/ +const uint8 standardIDResponse[]={ + CIN_SYSEX, + MIDIv1_SYSEX_START, + USYSEX_NON_REAL_TIME, + USYSEX_ALL_CHANNELS, + CIN_SYSEX, + USYSEX_GENERAL_INFO, + USYSEX_GI_ID_RESPONSE, + LEAFLABS_MMA_VENDOR_1, + CIN_SYSEX, + LEAFLABS_MMA_VENDOR_2, // extended ID + LEAFLABS_MMA_VENDOR_3, // extended ID + 1, // family #1 + CIN_SYSEX, + 2, // family #2 + 1, // part #1 + 2, // part #2 + CIN_SYSEX, + 0, // version 1 + 0, // version 2 + 1, // version 3 + CIN_SYSEX_ENDS_IN_2, + '!', // lgl compatible + MIDIv1_SYSEX_END, + 0 +}; +//#define STANDARD_ID_RESPONSE_LENGTH (sizeof(standardIDResponse)) + +typedef enum {NOT_IN_SYSEX=0,COULD_BE_MY_SYSEX,YUP_ITS_MY_SYSEX,ITS_NOT_MY_SYSEX} sysexStates; +volatile uint8 sysexBuffer[MAX_SYSEX_SIZE]; +volatile sysexStates sysexState; +volatile int sysexFinger=0; + +/* + 0xF0 SysEx + 0x?? LEAFLABS_MMA_VENDOR_1 + 0x?? LEAFLABS_MMA_VENDOR_2 + + 0x?? LEAFLABS_MMA_VENDOR_3 + 0x10 LGL_DEVICE_NUMBER + 0xLE CMD: REBOOT + + 0xf7 EOSysEx +*/ +#define STACK_TOP 0x20000800 +#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. + * So we need to respond to any generic requests like information requests. + * We also need to handle requests which are meant for us. At the moment this is just the + * reset request. + * + */ +void dealWithItQuickly(){ + switch (sysexBuffer[1]) { + case USYSEX_NON_REAL_TIME: + switch (sysexBuffer[3]) { + case USYSEX_GENERAL_INFO: + if (sysexBuffer[4]==USYSEX_GI_ID_REQUEST) { + usb_midi_tx((uint32 *) standardIDResponse, STANDARD_ID_RESPONSE_LENGTH); + } + } + 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; + } + ;//turn the led on? +} + +/* -----------------------------------------------------------------------------LglSysexHandler() + * The idea here is to identify which Sysex's belong to us and deal with them. + */ +void LglSysexHandler(uint32 *midiBufferRx, uint32 *rx_offset, uint32 *n_unread_packets) { + MIDI_EVENT_PACKET_t * midiPackets = (MIDI_EVENT_PACKET_t *) (midiBufferRx+(*rx_offset)); + uint8 nPackets=((*n_unread_packets)-(*rx_offset)); + int cPacket; + uint8 soPackets=0; + /********************************* ACHTUNG! ignores usbmidi cable ********************************/ + MIDI_EVENT_PACKET_t *packet; + for (cPacket=0;cPacketcin)) { + continue; + } // else { + if (!soPackets) { + soPackets=cPacket*4; + } + if ((sysexState==YUP_ITS_MY_SYSEX) && ((sysexFinger+3)>=MAX_SYSEX_SIZE)){ + sysexState=ITS_NOT_MY_SYSEX; //eisenhower policy. Even if its mine I cant deal with it. + } + switch (packet->cin) { + case CIN_SYSEX: + switch (sysexState) { + case NOT_IN_SYSEX : // new sysex. + sysexFinger=0; + if (packet->midi0 == MIDIv1_SYSEX_START) { + if (packet->midi1==USYSEX_REAL_TIME + ||packet->midi1==USYSEX_NON_REAL_TIME) { + if ((packet->midi2==myMidiChannel) + ||(packet->midi2==USYSEX_ALL_CHANNELS) + ) { + sysexState=YUP_ITS_MY_SYSEX; + sysexBuffer[sysexFinger++]=MIDIv1_SYSEX_START; + sysexBuffer[sysexFinger++]=packet->midi1; + sysexBuffer[sysexFinger++]=packet->midi2; + break; + } + } else if ((packet->midi1==myMidiID[0]) + && (packet->midi2==myMidiID[1]) + ){ + sysexState=COULD_BE_MY_SYSEX; + sysexBuffer[sysexFinger++]=MIDIv1_SYSEX_START; + sysexBuffer[sysexFinger++]=packet->midi1; + sysexBuffer[sysexFinger++]=packet->midi2; + break; + } + } + break; + + case COULD_BE_MY_SYSEX: + if (packet->midi0==myMidiID[2]) { + sysexState=YUP_ITS_MY_SYSEX; + sysexBuffer[sysexFinger++]=packet->midi0; + sysexBuffer[sysexFinger++]=packet->midi1; + sysexBuffer[sysexFinger++]=packet->midi2; + } else { + sysexState=ITS_NOT_MY_SYSEX; + sysexFinger=0; + } + break; + default: + break; + + } + + break; + case CIN_SYSEX_ENDS_IN_1: + case CIN_SYSEX_ENDS_IN_2: + case CIN_SYSEX_ENDS_IN_3: + sysexBuffer[sysexFinger++]=packet->midi0; + sysexBuffer[sysexFinger++]=packet->midi1; + sysexBuffer[sysexFinger++]=packet->midi2; + if (sysexState==YUP_ITS_MY_SYSEX) { + if(cPacket>=(int32)(*n_unread_packets)){ + *n_unread_packets = soPackets; + *rx_offset = soPackets; + } else { + uint8 c = cPacket; + uint32 *s; + uint32 *d = midiBufferRx + soPackets; + for (s = midiBufferRx+c; + ((*n_unread_packets) && (s <= midiBufferRx+(USB_MIDI_RX_EPSIZE/4))); + d++,s++ + ) { + (*d)=(*s); + (*n_unread_packets)--; + (*rx_offset)++; + + } + // we need to reset the for loop variables to re process remaining data. + nPackets=((*n_unread_packets)-(*rx_offset)); + cPacket=(*rx_offset); + } + dealWithItQuickly(); + + } + sysexFinger=0; + sysexState=NOT_IN_SYSEX; + + break; + default: + return; + } + //} + + + + } + // its our sysex and we will cry if we want to + return; +} + +#endif diff --git a/STM32F1/libraries/USBComposite/MinSysex.h b/STM32F1/libraries/USBComposite/MinSysex.h new file mode 100644 index 0000000..958eded --- /dev/null +++ b/STM32F1/libraries/USBComposite/MinSysex.h @@ -0,0 +1,37 @@ +// +// lgl_min_sysex.h +// LibMaple4Midi +// +// Created by Donald D Davis on 4/11/13. +// Copyright (c) 2013 Suspect Devices. All rights reserved. +// + +#ifndef __LGL_MIN_SYSEX_H__ +#define __LGL_MIN_SYSEX_H__ 1 + + +#include "MidiSpecs.h" +//#include "LGL.h" + +#define LEAFLABS_MMA_VENDOR_1 0x7D +#define LEAFLABS_MMA_VENDOR_2 0x1E +#define LEAFLABS_MMA_VENDOR_3 0x4F + +// move to LGL.h +#define LGL_RESET_CMD 0x1e + +#define DEFAULT_MIDI_CHANNEL 0x0A +#define DEFAULT_MIDI_DEVICE 0x0A +#define DEFAULT_MIDI_CABLE 0x00 + +// eventually all of this should be in a place for settings which can be written to flash. +extern volatile uint8 myMidiChannel; +extern volatile uint8 myMidiDevice; +extern volatile uint8 myMidiCable; +extern volatile uint8 myMidiID[]; + + +void LglSysexHandler(uint32 *midiBufferRx,uint32 *rx_offset,uint32 *n_unread_bytes); + +#endif + diff --git a/STM32F1/libraries/USBComposite/Mouse.cpp b/STM32F1/libraries/USBComposite/Mouse.cpp new file mode 100644 index 0000000..2f3abb9 --- /dev/null +++ b/STM32F1/libraries/USBComposite/Mouse.cpp @@ -0,0 +1,57 @@ +#include "USBHID.h" + +//================================================================================ +//================================================================================ +// Mouse + +void HIDMouse::begin(void){ +} + +void HIDMouse::end(void){ +} + +void HIDMouse::click(uint8_t b) +{ + _buttons = b; + move(0,0,0); + _buttons = 0; + move(0,0,0); +} + +void HIDMouse::move(signed char x, signed char y, signed char wheel) +{ + reportBuffer[1] = _buttons; + reportBuffer[2] = x; + reportBuffer[3] = y; + reportBuffer[4] = wheel; + + sendReport(); +} + +void HIDMouse::buttons(uint8_t b) +{ + if (b != _buttons) + { + _buttons = b; + move(0,0,0); + } +} + +void HIDMouse::press(uint8_t b) +{ + buttons(_buttons | b); +} + +void HIDMouse::release(uint8_t b) +{ + buttons(_buttons & ~b); +} + +bool HIDMouse::isPressed(uint8_t b) +{ + if ((b & _buttons) > 0) + return true; + return false; +} + +HIDMouse Mouse; diff --git a/STM32F1/libraries/USBComposite/README.md b/STM32F1/libraries/USBComposite/README.md new file mode 100644 index 0000000..8c80c13 --- /dev/null +++ b/STM32F1/libraries/USBComposite/README.md @@ -0,0 +1,88 @@ +# USB Composite library for STM32F1 + +## Protocols supported + +- standard USB HID, with many built-in profiles, and customizable with more + +- MIDI over USB + +- XBox360 controller (only controller-to-host is currently supported) + +- Mass storage + +## Basic concepts + +Start with: +``` +#include +``` + +The library defines several crucial objects. The central object is: + +``` +extern USBCompositeDevice USBComposite; +``` + +This controls USB device identification as well as registers the plugins that are connected to it. + +Plugin objects included in the library are: + +``` +extern USBHIDDevice USBHID; +extern USBMidi USBMIDI; +extern USBXBox360 XBox360; +extern USBMassStorageDevice MassStorage; +extern USBCompositeSerial CompositeSerial; +``` + +You can also create your own customized instances of these plugin classes or their subclasses. + +If you want to make a simple (non-composite) USB device, you can just call the plugin's `begin()` +method, and it will take care of registering itself with `USBComposite` and starting up +`USBComposite`. If you want to make a composite USB device, however, +you need to control the device with `USBComposite`: + +``` +USBComposite.clear(); // clear any plugins previously registered +plugin1.registerComponent(); +plugin2.registerComponent(); +USBComposite.begin(); +``` + +Of course, you may need to do some further configuring of the plugins or the `USBComposite` device +before the `USBComposite.begin()` call. + +Finally, there are a number of objects that implement particular protocols for the `USBHID` plugin: +``` +extern HIDMouse Mouse; +extern HIDKeyboard Keyboard; +extern HIDJoystick Joystick; +extern HIDKeyboard BootKeyboard; +``` +And you can customize with more. Moreover, the `USBHID` plugin itself allows for compositing +multiple HID profiles, e.g., Mouse / Keyboard / three joysticks. + +Not all combinations will fit within the constraints of the STM32F1 USB system, and not all +combinations will be supported by all operating systems. + +## Simple USB device configuration + +A simple USB device uses a single plugin. You just need to call any setup methods for the plugin +and the `begin()` method for the plugin. For instance, to inject keyboard data, you can do: + +``` +USBHID.begin(HID_KEYBOARD); +``` + +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. + +Additionally, for backwards compatibility reasons, the `USBHID` plugin has a convenience +`USBHID_begin_with_serial()` function which works just like `USBHID.begin()` except that it also +composites a `CompositeSerial` plugin. + +However, if you want a USB device using more than one plugin, then you will NOT call the plugin's +`begin()` method. \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/USBComposite.cpp b/STM32F1/libraries/USBComposite/USBComposite.cpp new file mode 100644 index 0000000..b659f11 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBComposite.cpp @@ -0,0 +1,147 @@ +#include "USBComposite.h" + +#define DEFAULT_VENDOR_ID 0x1EAF +#define DEFAULT_PRODUCT_ID 0x0004 + +static char* putSerialNumber(char* out, int nibbles, uint32 id) { + for (int i=0; i>= 4) { + uint8 nibble = id & 0xF; + if (nibble <= 9) + *out++ = nibble + '0'; + else + *out++ = nibble - 10 + 'a'; + } + return out; +} + +const char* getDeviceIDString() { + static char string[80/4+1]; + char* p = string; + + uint32 id = (uint32) *(uint16*) (0x1FFFF7E8+0x02); + p = putSerialNumber(p, 4, id); + + id = *(uint32*) (0x1FFFF7E8+0x04); + p = putSerialNumber(p, 8, id); + + id = *(uint32*) (0x1FFFF7E8+0x08); + p = putSerialNumber(p, 8, id); + + *p = 0; + + return string; +} + +USBCompositeDevice::USBCompositeDevice(void) { + vendorId = 0; + productId = 0; + numParts = 0; + setManufacturerString(NULL); + setProductString(NULL); + setSerialString(DEFAULT_SERIAL_STRING); + iManufacturer[0] = 0; + iProduct[0] = 0; + iSerialNumber[0] = 0; + } + +void USBCompositeDevice::setVendorId(uint16 _vendorId) { + if (_vendorId != 0) + vendorId = _vendorId; + else + vendorId = DEFAULT_VENDOR_ID; +} + +void USBCompositeDevice::setProductId(uint16 _productId) { + if (_productId != 0) + productId = _productId; + else + 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= USB_COMPOSITE_MAX_PARTS) + return false; + parts[i] = part; + init[i] = _init; + stop[i] = _stop; + plugin[i] = _plugin; + if (i >= numParts) + numParts++; + return true; +} + +USBCompositeDevice USBComposite; diff --git a/STM32F1/libraries/USBComposite/USBComposite.h b/STM32F1/libraries/USBComposite/USBComposite.h new file mode 100644 index 0000000..152c3c3 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBComposite.h @@ -0,0 +1,64 @@ +#ifndef _USBCOMPOSITE_H_ +#define _USBCOMPOSITE_H_ + +#include +#include "Stream.h" +#include "usb_generic.h" +//#include + +#include +#include +#include +#include + +#define USB_MAX_PRODUCT_LENGTH 32 +#define USB_MAX_MANUFACTURER_LENGTH 32 +#define USB_MAX_SERIAL_NUMBER_LENGTH 20 + + +// 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 + +class USBCompositeDevice; + +#define DEFAULT_SERIAL_STRING "00000000000000000001" + +typedef bool(*USBPartInitializer)(void*); +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)]; + 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; +public: + USBCompositeDevice(void); + void setVendorId(uint16 vendor=0); + void setProductId(uint16 product=0); + void setManufacturerString(const char* manufacturer=NULL); + void setProductString(const char* product=NULL); + void setSerialString(const char* serialNumber=DEFAULT_SERIAL_STRING); + bool begin(void); + void end(void); + void clear(); + bool isReady() { + return enabled && usb_is_connected(USBLIB) && usb_is_configured(USBLIB); + } + bool add(USBCompositePart* part, void* plugin, USBPartInitializer init = NULL, USBPartStopper stop = NULL); +}; + +extern USBCompositeDevice USBComposite; +#endif + \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp b/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp new file mode 100644 index 0000000..9da0f19 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp @@ -0,0 +1,274 @@ +/* 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 + +#include +#include +#include +#include +#include +#include + +#include "usb_serial.h" + +#define USB_TIMEOUT 50 + +#if defined(SERIAL_USB) +static void rxHook(unsigned, void*); +static void ifaceSetupHook(unsigned, void*); +#endif + +bool USBCompositeSerial::init(USBCompositeSerial* me) { + (void)me; +#if defined(SERIAL_USB) + composite_cdcacm_set_hooks(USBHID_CDCACM_HOOK_RX, rxHook); + composite_cdcacm_set_hooks(USBHID_CDCACM_HOOK_IFACE_SETUP, ifaceSetupHook); +#endif + return true; +} + +void USBCompositeSerial::begin(long speed) { + (void)speed; + if (!enabled) { + USBComposite.clear(); + registerComponent(); + USBComposite.begin(); + enabled = true; + } +} + +void USBCompositeSerial::end() { + if (enabled) { + USBComposite.end(); + enabled = false; + } +} + +size_t USBCompositeSerial::write(uint8 ch) { +size_t n = 0; + this->write(&ch, 1); + return n; +} + +size_t USBCompositeSerial::write(const char *str) { +size_t n = 0; + this->write((const uint8*)str, strlen(str)); + return n; +} + +size_t USBCompositeSerial::write(const uint8 *buf, uint32 len) +{ + size_t n = 0; + + if (!this->isConnected() || !buf) { + return 0; + } + + uint32 txed = 0; + while (txed < len) { + txed += composite_cdcacm_tx((const uint8*)buf + txed, len - txed); + } + + return n; +} + +int USBCompositeSerial::available(void) { + return composite_cdcacm_data_available(); +} + +int USBCompositeSerial::peek(void) +{ + uint8 b; + if (composite_cdcacm_peek(&b, 1)==1) + { + return b; + } + else + { + return -1; + } +} + +bool USBCompositeSerial::registerComponent() { + return USBComposite.add(&usbSerialPart, this, (USBPartInitializer)&USBCompositeSerial::init); +} + +void USBCompositeSerial::flush(void) +{ +/*Roger Clark. Rather slow method. Need to improve this */ + uint8 b; + while(composite_cdcacm_data_available()) + { + this->read(&b, 1); + } + return; +} + +uint32 USBCompositeSerial::read(uint8 * buf, uint32 len) { + uint32 rxed = 0; + while (rxed < len) { + rxed += composite_cdcacm_rx(buf + rxed, len - rxed); + } + + return rxed; +} + +/* Blocks forever until 1 byte is received */ +int USBCompositeSerial::read(void) { + uint8 b; + /* + this->read(&b, 1); + return b; + */ + + if (composite_cdcacm_rx(&b, 1)==0) + { + return -1; + } + else + { + return b; + } +} + +uint8 USBCompositeSerial::pending(void) { + return composite_cdcacm_get_pending(); +} + +uint8 USBCompositeSerial::isConnected(void) { + return usb_is_connected(USBLIB) && usb_is_configured(USBLIB) && composite_cdcacm_get_dtr(); +} + +uint8 USBCompositeSerial::getDTR(void) { + return composite_cdcacm_get_dtr(); +} + +uint8 USBCompositeSerial::getRTS(void) { + return composite_cdcacm_get_rts(); +} + +#if defined(SERIAL_USB) + +enum reset_state_t { + DTR_UNSET, + DTR_HIGH, + DTR_NEGEDGE, + DTR_LOW +}; + +static reset_state_t reset_state = DTR_UNSET; + +static void ifaceSetupHook(unsigned hook, void *requestvp) { + (void)hook; + uint8 request = *(uint8*)requestvp; + + // Ignore requests we're not interested in. + if (request != USBHID_CDCACM_SET_CONTROL_LINE_STATE) { + return; + } + + // We need to see a negative edge on DTR before we start looking + // for the in-band magic reset byte sequence. + uint8 dtr = composite_cdcacm_get_dtr(); + switch (reset_state) { + case DTR_UNSET: + reset_state = dtr ? DTR_HIGH : DTR_LOW; + break; + case DTR_HIGH: + reset_state = dtr ? DTR_HIGH : DTR_NEGEDGE; + break; + case DTR_NEGEDGE: + reset_state = dtr ? DTR_HIGH : DTR_LOW; + break; + case DTR_LOW: + reset_state = dtr ? DTR_HIGH : DTR_LOW; + break; + } + + if ((composite_cdcacm_get_baud() == 1200) && (reset_state == DTR_NEGEDGE)) { + iwdg_init(IWDG_PRE_4, 10); + while (1); + } +} + +#define RESET_DELAY 100000 +static void wait_reset(void) { + delay_us(RESET_DELAY); + nvic_sys_reset(); +} + +#define STACK_TOP 0x20000800 +#define EXC_RETURN 0xFFFFFFF9 +#define DEFAULT_CPSR 0x61000000 +static void rxHook(unsigned hook, void *ignored) { + (void)hook; + (void)ignored; + /* FIXME this is mad buggy; we need a new reset sequence. E.g. NAK + * after each RX means you can't reset if any bytes are waiting. */ + if (reset_state == DTR_NEGEDGE) { + reset_state = DTR_LOW; + + if (composite_cdcacm_data_available() >= 4) { + // The magic reset sequence is "1EAF". + static const uint8 magic[4] = {'1', 'E', 'A', 'F'}; + + uint8 chkBuf[4]; + + // Peek at the waiting bytes, looking for reset sequence, + // bailing on mismatch. + composite_cdcacm_peek_ex(chkBuf, composite_cdcacm_data_available() - 4, 4); + for (unsigned i = 0; i < sizeof(magic); i++) { + if (chkBuf[i] != magic[i]) { + return; + } + } + + // Got the magic sequence -> reset, presumably into the bootloader. + // 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 + "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 + + +USBCompositeSerial CompositeSerial; + diff --git a/STM32F1/libraries/USBComposite/USBCompositeSerial.h b/STM32F1/libraries/USBComposite/USBCompositeSerial.h new file mode 100644 index 0000000..4112617 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBCompositeSerial.h @@ -0,0 +1,40 @@ +#ifndef _COMPOSITE_SERIAL_H_ +#define _COMPOSITE_SERIAL_H_ + +#include "USBComposite.h" +#include "usb_serial.h" + +class USBCompositeSerial : public Stream { +private: + bool enabled = false; +public: + void begin(long speed=9600); + void end(); + static bool init(USBCompositeSerial* me); + bool registerComponent(); + + operator bool() { return true; } // Roger Clark. This is needed because in cardinfo.ino it does if (!Serial) . It seems to be a work around for the Leonardo that we needed to implement just to be compliant with the API + + virtual int available(void);// Changed to virtual + + uint32 read(uint8 * buf, uint32 len); + // uint8 read(void); + + // Roger Clark. added functions to support Arduino 1.0 API + virtual int peek(void); + virtual int read(void); + int availableForWrite(void); + virtual void flush(void); + + size_t write(uint8); + size_t write(const char *str); + size_t write(const uint8*, uint32); + + uint8 getRTS(); + uint8 getDTR(); + uint8 isConnected(); + uint8 pending(); +}; + +extern USBCompositeSerial CompositeSerial; +#endif diff --git a/STM32F1/libraries/USBComposite/USBHID.cpp b/STM32F1/libraries/USBComposite/USBHID.cpp new file mode 100644 index 0000000..e0b69b4 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBHID.cpp @@ -0,0 +1,180 @@ +/* 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 "USBHID.h" +#include "USBCompositeSerial.h" + +#include +#include +#include +#include "usb_hid.h" +#include "usb_serial.h" +#include "usb_generic.h" +#include +#include +#include + +#include + +/* + * USB HID interface + */ + +bool USBHIDDevice::registerComponent() { + return USBComposite.add(&usbHIDPart, this); +} + +void USBHIDDevice::setReportDescriptor(const uint8_t* report_descriptor, uint16_t report_descriptor_length) { + usb_hid_set_report_descriptor(report_descriptor, report_descriptor_length); +} + +void USBHIDDevice::setReportDescriptor(const HIDReportDescriptor* report) { + setReportDescriptor(report->descriptor, report->length); +} + +void USBHIDDevice::begin(const uint8_t* report_descriptor, uint16_t report_descriptor_length, uint16_t idVendor, uint16_t idProduct, + const char* manufacturer, const char* product, const char* serialNumber) { + + if (enabledHID) + return; + + setReportDescriptor(report_descriptor, report_descriptor_length); + + USBComposite.clear(); + USBComposite.setVendorId(idVendor); + USBComposite.setProductId(idProduct); + USBComposite.setManufacturerString(manufacturer); + USBComposite.setProductString(product); + USBComposite.setSerialString(serialNumber); + registerComponent(); + + USBComposite.begin(); + + enabledHID = true; +} + +void USBHIDDevice::begin(const HIDReportDescriptor* report, uint16_t idVendor, uint16_t idProduct, + const char* manufacturer, const char* product, const char* serialNumber) { + begin(report->descriptor, report->length, idVendor, idProduct, manufacturer, product, serialNumber); +} + +void USBHIDDevice::setBuffers(uint8_t type, volatile HIDBuffer_t* fb, int count) { + usb_hid_set_buffers(type, fb, count); +} + +bool USBHIDDevice::addBuffer(uint8_t type, volatile HIDBuffer_t* buffer) { + return 0 != usb_hid_add_buffer(type, buffer); +} + +void USBHIDDevice::clearBuffers(uint8_t type) { + usb_hid_clear_buffers(type); +} + +void USBHIDDevice::clearBuffers() { + clearBuffers(HID_REPORT_TYPE_OUTPUT); + clearBuffers(HID_REPORT_TYPE_FEATURE); +} + +void USBHIDDevice::end(void){ + if(enabledHID){ + USBComposite.end(); + enabledHID = false; + } +} + +void HIDReporter::sendReport() { +// while (usb_is_transmitting() != 0) { +// } + + unsigned toSend = bufferSize; + uint8* b = buffer; + + while (toSend) { + unsigned delta = usb_hid_tx(b, toSend); + toSend -= delta; + b += delta; + } + +// while (usb_is_transmitting() != 0) { +// } + + /* flush out to avoid having the pc wait for more data */ + usb_hid_tx(NULL, 0); +} + +HIDReporter::HIDReporter(uint8_t* _buffer, unsigned _size, uint8_t _reportID) { + if (_reportID == 0) { + buffer = _buffer+1; + bufferSize = _size-1; + } + else { + buffer = _buffer; + bufferSize = _size; + } + memset(buffer, 0, bufferSize); + reportID = _reportID; + if (_size > 0 && reportID != 0) + buffer[0] = _reportID; +} + +HIDReporter::HIDReporter(uint8_t* _buffer, unsigned _size) { + buffer = _buffer; + bufferSize = _size; + memset(buffer, 0, _size); + reportID = 0; +} + +void HIDReporter::setFeature(uint8_t* in) { + return usb_hid_set_feature(reportID, in); +} + +uint16_t HIDReporter::getData(uint8_t type, uint8_t* out, uint8_t poll) { + return usb_hid_get_data(type, reportID, out, poll); +} + +uint16_t HIDReporter::getFeature(uint8_t* out, uint8_t poll) { + return usb_hid_get_data(HID_REPORT_TYPE_FEATURE, reportID, out, poll); +} + +uint16_t HIDReporter::getOutput(uint8_t* out, uint8_t poll) { + return usb_hid_get_data(HID_REPORT_TYPE_OUTPUT, reportID, out, poll); +} + +USBHIDDevice USBHID; + +void USBHID_begin_with_serial(const uint8_t* report_descriptor, uint16_t report_descriptor_length, uint16_t idVendor, uint16_t idProduct, + const char* manufacturer, const char* product, const char* serialNumber) { + + USBComposite.clear(); + USBComposite.setVendorId(idVendor); + USBComposite.setProductId(idProduct); + USBComposite.setManufacturerString(manufacturer); + USBComposite.setProductString(product); + USBComposite.setSerialString(serialNumber); + + USBHID.setReportDescriptor(report_descriptor, report_descriptor_length); + USBHID.registerComponent(); + + CompositeSerial.registerComponent(); + + USBComposite.begin(); +} + +void USBHID_begin_with_serial(const HIDReportDescriptor* report, uint16_t idVendor, uint16_t idProduct, + const char* manufacturer, const char* product, const char* serialNumber) { + USBHID_begin_with_serial(report->descriptor, report->length, idVendor, idProduct, manufacturer, product, serialNumber); +} + diff --git a/STM32F1/libraries/USBComposite/USBHID.h b/STM32F1/libraries/USBComposite/USBHID.h new file mode 100644 index 0000000..0362f4e --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBHID.h @@ -0,0 +1,608 @@ +/* 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. +*/ + +#ifndef _USBHID_H_ +#define _USBHID_H_ + +#include +#include +#include +#include +#include "Stream.h" +#include "usb_hid.h" + +#define USB_HID_MAX_PRODUCT_LENGTH 32 +#define USB_HID_MAX_MANUFACTURER_LENGTH 32 +#define USB_HID_MAX_SERIAL_NUMBER_LENGTH 20 + +#define HID_MOUSE_REPORT_ID 1 +#define HID_KEYBOARD_REPORT_ID 2 +#define HID_CONSUMER_REPORT_ID 3 +#define HID_JOYSTICK_REPORT_ID 20 + +#define HID_KEYBOARD_ROLLOVER 6 + +#define MACRO_GET_ARGUMENT_2(x, y, ...) y +#define MACRO_GET_ARGUMENT_1_WITH_DEFAULT(default, ...) MACRO_GET_ARGUMENT_2(placeholder, ## __VA_ARGS__, default) +#define MACRO_ARGUMENT_2_TO_END(skip, ...) __VA_ARGS__ + +// HIDBuffer_t data buffers must have even memory length because of how PMA transfers work +#define HID_DATA_BUFFER_SIZE(n) (((n)+1)/2*2) + +/* note that featureSize must be 1 less than the buffer size for the feature, + since the latter must include the reportId */ +/* this only works in a collection with a report_id */ +#define HID_FEATURE_REPORT_DESCRIPTOR(dataSize) \ + 0x06, 0x00, 0xFF, /* USAGE_PAGE (Vendor Defined Page 1) */ \ + 0x09, 0x01, /* USAGE (Vendor Usage 1) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x95, dataSize, /* REPORT_COUNT (xx) */ \ + 0xB1, 0x02, /* FEATURE (Data,Var,Abs) */ \ + +#define HID_OUTPUT_REPORT_DESCRIPTOR(dataSize) \ + 0x06, 0x00, 0xFF, /* USAGE_PAGE (Vendor Defined Page 1) */ \ + 0x09, 0x01, /* USAGE (Vendor Usage 1) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x95, dataSize, /* REPORT_COUNT (32) */ \ + 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ \ + +#define HID_CONSUMER_REPORT_DESCRIPTOR(...) \ + 0x05, 0x0C, /* usage page (consumer device) */ \ + 0x09, 0x01, /* usage -- consumer control */ \ + 0xA1, 0x01, /* collection (application) */ \ + 0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_CONSUMER_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \ + 0x15, 0x00, /* logical minimum */ \ + 0x26, 0xFF, 0x03, /* logical maximum (3ff) */ \ + 0x19, 0x00, /* usage minimum (0) */ \ + 0x2A, 0xFF, 0x03, /* usage maximum (3ff) */ \ + 0x75, 0x10, /* report size (16) */ \ + 0x95, 0x01, /* report count (1) */ \ + 0x81, 0x00, /* input */ \ + MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ + 0xC0 /* end collection */ + +#define HID_MOUSE_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 54 */ \ + 0x09, 0x02, /* USAGE (Mouse) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_MOUSE_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \ + 0x09, 0x01, /* USAGE (Pointer) */ \ + 0xa1, 0x00, /* COLLECTION (Physical) */ \ + 0x05, 0x09, /* USAGE_PAGE (Button) */ \ + 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ \ + 0x29, 0x08, /* USAGE_MAXIMUM (Button 8) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \ + 0x09, 0x30, /* USAGE (X) */ \ + 0x09, 0x31, /* USAGE (Y) */ \ + 0x09, 0x38, /* USAGE (Wheel) */ \ + 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ \ + 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x95, 0x03, /* REPORT_COUNT (3) */ \ + 0x81, 0x06, /* INPUT (Data,Var,Rel) */ \ + 0xc0, /* END_COLLECTION */ \ + MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ + 0xc0 /* END_COLLECTION */ + +#define HID_ABS_MOUSE_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 54 */ \ + 0x09, 0x02, /* USAGE (Mouse) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_MOUSE_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \ + 0x09, 0x01, /* USAGE (Pointer) */ \ + 0xa1, 0x00, /* COLLECTION (Physical) */ \ + 0x05, 0x09, /* USAGE_PAGE (Button) */ \ + 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ \ + 0x29, 0x08, /* USAGE_MAXIMUM (Button 8) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \ + 0x09, 0x30, /* USAGE (X) */ \ + 0x09, 0x31, /* USAGE (Y) */ \ + 0x16, 0x00, 0x80, /* LOGICAL_MINIMUM (-32768) */ \ + 0x26, 0xFF, 0x7f, /* LOGICAL_MAXIMUM (32767) */ \ + 0x75, 0x10, /* REPORT_SIZE (16) */ \ + 0x95, 0x02, /* REPORT_COUNT (2) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ + 0x09, 0x38, /* USAGE (Wheel) */ \ + 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ \ + 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x95, 0x01, /* REPORT_COUNT (1) */ \ + 0x81, 0x06, /* INPUT (Data,Var,Rel) */ \ + 0xc0, /* END_COLLECTION */ \ + MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ + 0xc0 /* END_COLLECTION */ + +#define HID_KEYBOARD_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 47 */ \ + 0x09, 0x06, /* USAGE (Keyboard) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_KEYBOARD_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \ + 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ \ + 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ +\ + 0x95, 0x01, /* REPORT_COUNT (1) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ \ +\ + 0x95, HID_KEYBOARD_ROLLOVER, /* REPORT_COUNT (6) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ \ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \ +\ + 0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */ \ + 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ \ + 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ \ +\ + 0x05, 0x08, /* USAGE_PAGE (LEDs) */ \ + 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ \ + 0x29, 0x08, /* USAGE_MAXIMUM (Kana + 3 custom)*/ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ \ + MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ + 0xc0 /* END_COLLECTION */ + +#define HID_BOOT_KEYBOARD_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 47 */ \ + 0x09, 0x06, /* USAGE (Keyboard) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \ + 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ \ + 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ +\ + 0x95, 0x01, /* REPORT_COUNT (1) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ \ +\ + 0x95, 0x06, /* REPORT_COUNT (6) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ \ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \ +\ + 0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */ \ + 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ \ + 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ \ +\ + 0x05, 0x08, /* USAGE_PAGE (LEDs) */ \ + 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ \ + 0x29, 0x08, /* USAGE_MAXIMUM (Kana + 3 custom)*/ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ \ + __VA_ARGS__ \ + 0xc0 /* END_COLLECTION */ + +#define HID_JOYSTICK_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ \ + 0x09, 0x04, /* Usage (Joystick) */ \ + 0xA1, 0x01, /* Collection (Application) */ \ + 0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_JOYSTICK_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \ + 0x15, 0x00, /* Logical Minimum (0) */ \ + 0x25, 0x01, /* Logical Maximum (1) */ \ + 0x75, 0x01, /* Report Size (1) */ \ + 0x95, 0x20, /* Report Count (32) */ \ + 0x05, 0x09, /* Usage Page (Button) */ \ + 0x19, 0x01, /* Usage Minimum (Button #1) */ \ + 0x29, 0x20, /* Usage Maximum (Button #32) */ \ + 0x81, 0x02, /* Input (variable,absolute) */ \ + 0x15, 0x00, /* Logical Minimum (0) */ \ + 0x25, 0x07, /* Logical Maximum (7) */ \ + 0x35, 0x00, /* Physical Minimum (0) */ \ + 0x46, 0x3B, 0x01, /* Physical Maximum (315) */ \ + 0x75, 0x04, /* Report Size (4) */ \ + 0x95, 0x01, /* Report Count (1) */ \ + 0x65, 0x14, /* Unit (20) */ \ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ \ + 0x09, 0x39, /* Usage (Hat switch) */ \ + 0x81, 0x42, /* Input (variable,absolute,null_state) */ \ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ \ + 0x09, 0x01, /* Usage (Pointer) */ \ + 0xA1, 0x00, /* Collection () */ \ + 0x15, 0x00, /* Logical Minimum (0) */ \ + 0x26, 0xFF, 0x03, /* Logical Maximum (1023) */ \ + 0x75, 0x0A, /* Report Size (10) */ \ + 0x95, 0x04, /* Report Count (4) */ \ + 0x09, 0x30, /* Usage (X) */ \ + 0x09, 0x31, /* Usage (Y) */ \ + 0x09, 0x33, /* Usage (Rx) */ \ + 0x09, 0x34, /* Usage (Ry) */ \ + 0x81, 0x02, /* Input (variable,absolute) */ \ + 0xC0, /* End Collection */ \ + 0x15, 0x00, /* Logical Minimum (0) */ \ + 0x26, 0xFF, 0x03, /* Logical Maximum (1023) */ \ + 0x75, 0x0A, /* Report Size (10) */ \ + 0x95, 0x02, /* Report Count (2) */ \ + 0x09, 0x36, /* Usage (Slider) */ \ + 0x09, 0x36, /* Usage (Slider) */ \ + 0x81, 0x02, /* Input (variable,absolute) */ \ + MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ + 0xC0 + +#define RAWHID_USAGE_PAGE 0xFFC0 // recommended: 0xFF00 to 0xFFFF +#define RAWHID_USAGE 0x0C00 // recommended: 0x0100 to 0xFFFF + +#define LSB(x) ((x) & 0xFF) +#define MSB(x) (((x) & 0xFF00) >> 8) +// TODO: make this work for txSize > 255 +#define HID_RAW_REPORT_DESCRIPTOR(txSize, rxSize) \ + 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), \ + 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), \ + 0xA1, 0x01, /* Collection 0x01 */ \ +/* 0x85, 10, */ /* REPORT_ID (1) */ \ + 0x75, 0x08, /* report size = 8 bits */ \ + 0x15, 0x00, /* logical minimum = 0 */ \ + 0x26, 0xFF, 0x00, /* logical maximum = 255 */ \ +\ + 0x96, LSB(txSize), MSB(txSize), /* report count TX */ \ + 0x09, 0x01, /* usage */ \ + 0x81, 0x02, /* Input (array) */ \ +\ + 0x75, 0x08, /* report size = 8 bits */ \ + 0x15, 0x00, /* logical minimum = 0 */ \ + 0x26, 0xFF, 0x00, /* logical maximum = 255 */ \ + 0x96, LSB(rxSize), MSB(rxSize), /* report count RX */ \ + 0x09, 0x02, /* usage */ \ + 0x91, 0x02, /* OUTPUT (0x91) */ \ + 0xC0 /* end collection */ + +typedef struct { + uint8_t* descriptor; + uint16_t length; +} HIDReportDescriptor; + +class USBHIDDevice { +private: + bool enabledHID = false; +public: + bool registerComponent(); + void setReportDescriptor(const uint8_t* report_descriptor, uint16_t report_descriptor_length); + void setReportDescriptor(const HIDReportDescriptor* reportDescriptor); + // All the strings are zero-terminated ASCII strings. Use NULL for defaults. + void begin(const uint8_t* report_descriptor, uint16_t length, uint16_t idVendor=0, uint16_t idProduct=0, + const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001"); + void begin(const HIDReportDescriptor* reportDescriptor, uint16_t idVendor=0, uint16_t idProduct=0, + const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001"); + void setSerial(uint8 serialSupport=true); + void setBuffers(uint8_t buffers, volatile HIDBuffer_t* fb=NULL, int count=0); // type = HID_REPORT_TYPE_FEATURE or HID_REPORT_TYPE_OUTPUT + bool addBuffer(uint8_t type, volatile HIDBuffer_t* buffer); + void clearBuffers(uint8_t type); + void clearBuffers(); + inline bool addFeatureBuffer(volatile HIDBuffer_t* buffer) { + return addBuffer(HID_REPORT_TYPE_FEATURE, buffer); + } + inline bool addOutputBuffer(volatile HIDBuffer_t* buffer) { + return addBuffer(HID_REPORT_TYPE_OUTPUT, buffer); + } + inline void setFeatureBuffers(volatile HIDBuffer_t* fb=NULL, int count=0) { + setBuffers(HID_REPORT_TYPE_FEATURE, fb, count); + } + inline void setOutputBuffers(volatile HIDBuffer_t* fb=NULL, int count=0) { + setBuffers(HID_REPORT_TYPE_OUTPUT, fb, count); + } + void end(void); +}; + +void USBHID_begin_with_serial(const uint8_t* report_descriptor, uint16_t length, uint16_t idVendor=0, uint16_t idProduct=0, + const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001"); +void USBHID_begin_with_serial(const HIDReportDescriptor* reportDescriptor, uint16_t idVendor=0, uint16_t idProduct=0, + const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001"); + +class HIDReporter { + private: + uint8_t* buffer; + unsigned bufferSize; + uint8_t reportID; + + public: + void sendReport(); + + public: + // 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 + HIDReporter(uint8_t* _buffer, unsigned _size, uint8_t _reportID); + // if you use this init function, the buffer has no reportID byte in it + HIDReporter(uint8_t* _buffer, unsigned _size); + uint16_t getFeature(uint8_t* out=NULL, uint8_t poll=1); + uint16_t getOutput(uint8_t* out=NULL, uint8_t poll=1); + uint16_t getData(uint8_t type, uint8_t* out, uint8_t poll=1); // type = HID_REPORT_TYPE_FEATURE or HID_REPORT_TYPE_OUTPUT + void setFeature(uint8_t* feature); +}; + +//================================================================================ +//================================================================================ +// Mouse + +#define MOUSE_LEFT 1 +#define MOUSE_RIGHT 2 +#define MOUSE_MIDDLE 4 +#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE) + +class HIDMouse : public HIDReporter { +protected: + uint8_t _buttons; + void buttons(uint8_t b); + uint8_t reportBuffer[5]; +public: + HIDMouse(uint8_t reportID=HID_MOUSE_REPORT_ID) : HIDReporter(reportBuffer, sizeof(reportBuffer), reportID), _buttons(0) {} + void begin(void); + void end(void); + void click(uint8_t b = MOUSE_LEFT); + void move(signed char x, signed char y, signed char wheel = 0); + void press(uint8_t b = MOUSE_LEFT); // press LEFT by default + void release(uint8_t b = MOUSE_LEFT); // release LEFT by default + bool isPressed(uint8_t b = MOUSE_ALL); // check all buttons by default +}; + +typedef struct { + uint8_t reportID; + uint8_t buttons; + int16_t x; + int16_t y; + uint8_t wheel; +} __packed AbsMouseReport_t; + +class HIDAbsMouse : public HIDReporter { +protected: + void buttons(uint8_t b); + AbsMouseReport_t report; +public: + HIDAbsMouse(uint8_t reportID=HID_MOUSE_REPORT_ID) : HIDReporter((uint8_t*)&report, sizeof(report), reportID) { + report.buttons = 0; + report.x = 0; + report.y = 0; + report.wheel = 0; + } + void begin(void); + void end(void); + void click(uint8_t b = MOUSE_LEFT); + void move(int16_t x, int16_t y, int8_t wheel = 0); + void press(uint8_t b = MOUSE_LEFT); // press LEFT by default + void release(uint8_t b = MOUSE_LEFT); // release LEFT by default + bool isPressed(uint8_t b = MOUSE_ALL); // check all buttons by default +}; + +typedef struct { + uint8_t reportID; + uint16_t button; +} __packed ConsumerReport_t; + +class HIDConsumer : public HIDReporter { +protected: + ConsumerReport_t report; +public: + enum { + BRIGHTNESS_UP = 0x6F, + BRIGHTNESS_DOWN = 0x70, + 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 + }; + HIDConsumer(uint8_t reportID=HID_CONSUMER_REPORT_ID) : HIDReporter((uint8_t*)&report, sizeof(report), reportID) { + report.button = 0; + } + void begin(void); + void end(void); + void press(uint16_t button); + void release(); +}; + +#define KEY_LEFT_CTRL 0x80 +#define KEY_LEFT_SHIFT 0x81 +#define KEY_LEFT_ALT 0x82 +#define KEY_LEFT_GUI 0x83 +#define KEY_RIGHT_CTRL 0x84 +#define KEY_RIGHT_SHIFT 0x85 +#define KEY_RIGHT_ALT 0x86 +#define KEY_RIGHT_GUI 0x87 + +#define KEY_UP_ARROW 0xDA +#define KEY_DOWN_ARROW 0xD9 +#define KEY_LEFT_ARROW 0xD8 +#define KEY_RIGHT_ARROW 0xD7 +#define KEY_BACKSPACE 0xB2 +#define KEY_TAB 0xB3 +#define KEY_RETURN 0xB0 +#define KEY_ESC 0xB1 +#define KEY_INSERT 0xD1 +#define KEY_DELETE 0xD4 +#define KEY_PAGE_UP 0xD3 +#define KEY_PAGE_DOWN 0xD6 +#define KEY_HOME 0xD2 +#define KEY_END 0xD5 +#define KEY_CAPS_LOCK 0xC1 +#define KEY_F1 0xC2 +#define KEY_F2 0xC3 +#define KEY_F3 0xC4 +#define KEY_F4 0xC5 +#define KEY_F5 0xC6 +#define KEY_F6 0xC7 +#define KEY_F7 0xC8 +#define KEY_F8 0xC9 +#define KEY_F9 0xCA +#define KEY_F10 0xCB +#define KEY_F11 0xCC +#define KEY_F12 0xCD + +typedef struct{ + uint8_t reportID; + uint8_t modifiers; + uint8_t reserved; + uint8_t keys[HID_KEYBOARD_ROLLOVER]; +} __packed KeyReport_t; + +class HIDKeyboard : public Print, public HIDReporter { +public: + KeyReport_t keyReport; + +protected: + uint8_t leds[HID_BUFFER_ALLOCATE_SIZE(1,1)]; + HIDBuffer_t ledData; + uint8_t reportID; + uint8_t getKeyCode(uint8_t k, uint8_t* modifiersP); + bool adjustForHostCapsLock = true; + +public: + HIDKeyboard(uint8_t _reportID=HID_KEYBOARD_REPORT_ID) : + HIDReporter((uint8*)&keyReport, sizeof(KeyReport_t), _reportID), + ledData(leds, HID_BUFFER_SIZE(1,_reportID), _reportID, HID_BUFFER_MODE_NO_WAIT), + reportID(_reportID) + {} + void begin(void); + void end(void); + void setAdjustForHostCapsLock(bool state) { + adjustForHostCapsLock = state; + } + inline uint8 getLEDs(void) { + 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 void releaseAll(void); +}; + + +//================================================================================ +//================================================================================ +// Joystick + +// only works for little-endian machines, but makes the code so much more +// readable +typedef struct { + uint8_t reportID; + uint32_t buttons; + unsigned hat:4; + unsigned x:10; + unsigned y:10; + unsigned rx:10; + unsigned ry:10; + unsigned sliderLeft:10; + unsigned sliderRight:10; +} __packed JoystickReport_t; + +static_assert(sizeof(JoystickReport_t)==13, "Wrong endianness/packing!"); + +class HIDJoystick : public HIDReporter { +protected: + JoystickReport_t joyReport; + bool manualReport = false; + void safeSendReport(void); +public: + inline void send(void) { + sendReport(); + } + void setManualReportMode(bool manualReport); // in manual report mode, reports only sent when send() is called + bool getManualReportMode(); + void begin(void); + void end(void); + void button(uint8_t button, bool val); + void X(uint16_t val); + void Y(uint16_t val); + void position(uint16_t x, uint16_t y); + void Xrotate(uint16_t val); + void Yrotate(uint16_t val); + void sliderLeft(uint16_t val); + void sliderRight(uint16_t val); + void slider(uint16_t val); + void hat(int16_t dir); + HIDJoystick(uint8_t reportID=HID_JOYSTICK_REPORT_ID) : HIDReporter((uint8_t*)&joyReport, sizeof(joyReport), reportID) { + joyReport.buttons = 0; + joyReport.hat = 15; + joyReport.x = 512; + joyReport.y = 512; + joyReport.rx = 512; + joyReport.ry = 512; + joyReport.sliderLeft = 0; + joyReport.sliderRight = 0; + } +}; + +extern USBHIDDevice USBHID; + +templateclass HIDRaw : public HIDReporter { +private: + uint8_t txBuffer[txSize]; + uint8_t rxBuffer[HID_BUFFER_ALLOCATE_SIZE(rxSize,0)]; + HIDBuffer_t buf; +public: + HIDRaw() : HIDReporter(txBuffer, sizeof(txBuffer)) {} + void begin(void) { + buf.buffer = rxBuffer; + buf.bufferSize = HID_BUFFER_SIZE(rxSize,0); + buf.reportID = 0; + USBHID.addOutputBuffer(&buf); + } + void end(void); + void send(const uint8_t* data, unsigned n=sizeof(txBuffer)) { + memset(txBuffer, 0, sizeof(txBuffer)); + memcpy(txBuffer, data, n>sizeof(txBuffer)?sizeof(txBuffer):n); + sendReport(); + } +}; + +extern HIDMouse Mouse; +extern HIDKeyboard Keyboard; +extern HIDJoystick Joystick; +extern HIDKeyboard BootKeyboard; + +extern const HIDReportDescriptor* hidReportMouse; +extern const HIDReportDescriptor* hidReportKeyboard; +extern const HIDReportDescriptor* hidReportJoystick; +extern const HIDReportDescriptor* hidReportKeyboardMouse; +extern const HIDReportDescriptor* hidReportKeyboardJoystick; +extern const HIDReportDescriptor* hidReportKeyboardMouseJoystick; +extern const HIDReportDescriptor* hidReportBootKeyboard; + +#define HID_MOUSE hidReportMouse +#define HID_KEYBOARD hidReportKeyboard +#define HID_JOYSTICK hidReportJoystick +#define HID_KEYBOARD_MOUSE hidReportKeyboardMouse +#define HID_KEYBOARD_JOYSTICK hidReportKeyboardJoystick +#define HID_KEYBOARD_MOUSE_JOYSTICK hidReportKeyboardMouseJoystick +#define HID_BOOT_KEYBOARD hidReportBootKeyboard + +#endif + \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/USBMIDI.cpp b/STM32F1/libraries/USBComposite/USBMIDI.cpp new file mode 100644 index 0000000..ba0e895 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBMIDI.cpp @@ -0,0 +1,469 @@ +/****************************************************************************** + * This started out as a munging of Tymm Twillman's arduino Midi Library into the Libusb class, + * though by now very little of the original code is left, except for the class API and + * comments. Tymm Twillman kindly gave Alexander Pruss permission to relicense his code under the MIT + * license, which fixed a nasty licensing mess. + * + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2013 Magnus Lundin. + * Copyright (c) 2013 Donald Delmar Davis, Suspect Devices. + * (c) 2003-2008 Tymm Twillman + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + *****************************************************************************/ + +/** + * @brief USB MIDI device with a class compatible with maplemidi + */ + +#include "USBMIDI.h" + +#include +#include +#include +#include +#include "usb_midi_device.h" +#include +#include "usb_generic.h" + + +/* + * USBMidi interface + */ + +#define USB_TIMEOUT 50 + +void USBMidi::setChannel(unsigned int channel) { + channelIn_ = channel; + +} + +/*bool USBMidi::init(USBMidi* me) { + return true; +}*/ + +bool USBMidi::registerComponent() { + return USBComposite.add(&usbMIDIPart, this); +} + +void USBMidi::begin(unsigned channel) { + setChannel(channel); + + if (enabled) + return; + + USBComposite.clear(); + registerComponent(); + USBComposite.begin(); + + enabled = true; +} + +void USBMidi::end(void) { + if (enabled) { + USBComposite.end(); + enabled = false; + } +} + +void USBMidi::writePacket(uint32 p) { + this->writePackets(&p, 1); +} + +void USBMidi::writePackets(const void *buf, uint32 len) { + if (!this->isConnected() || !buf) { + return; + } + + uint32 txed = 0; + uint32 old_txed = 0; + uint32 start = millis(); + + uint32 sent = 0; + + while (txed < len && (millis() - start < USB_TIMEOUT)) { + sent = usb_midi_tx((const uint32*)buf + txed, len - txed); + txed += sent; + if (old_txed != txed) { + start = millis(); + } + old_txed = txed; + } + + + if (sent == USB_MIDI_TX_EPSIZE) { + while (usb_midi_is_transmitting() != 0) { + } + /* flush out to avoid having the pc wait for more data */ + usb_midi_tx(NULL, 0); + } +} + +uint32 USBMidi::available(void) { + return usb_midi_data_available(); +} + +uint32 USBMidi::readPackets(void *buf, uint32 len) { + if (!buf) { + return 0; + } + + uint32 rxed = 0; + while (rxed < len) { + rxed += usb_midi_rx((uint32*)buf + rxed, len - rxed); + } + + return rxed; +} + +/* Blocks forever until 1 byte is received */ +uint32 USBMidi::readPacket(void) { + uint32 p; + this->readPackets(&p, 1); + return p; +} + +uint8 USBMidi::pending(void) { + return usb_midi_get_pending(); +} + +uint8 USBMidi::isConnected(void) { + return usb_is_connected(USBLIB) && usb_is_configured(USBLIB); +} + + +USBMidi USBMIDI; + + +// These are midi status message types are defined in MidiSpec.h + +union EVENT_t { + uint32 i; + uint8 b[4]; + MIDI_EVENT_PACKET_t p; +}; + +// Handle decoding incoming MIDI traffic a word at a time -- remembers +// what it needs to from one call to the next. +// +// This is a private function & not meant to be called from outside this class. +// It's used whenever data is available from the USB port. +// +void USBMidi::dispatchPacket(uint32 p) +{ + union EVENT_t e; + + e.i=p; + + switch (e.p.cin) { + case CIN_3BYTE_SYS_COMMON: + if (e.p.midi0 == MIDIv1_SONG_POSITION_PTR) { + handleSongPosition(((uint16)e.p.midi2)<<7|((uint16)e.p.midi1)); + } + break; + + case CIN_2BYTE_SYS_COMMON: + switch (e.p.midi0) { + case MIDIv1_SONG_SELECT: + handleSongSelect(e.p.midi1); + break; + case MIDIv1_MTC_QUARTER_FRAME: + // reference library doesnt handle quarter frame. + break; + } + break; + case CIN_NOTE_OFF: + handleNoteOff(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); + break; + case CIN_NOTE_ON: + handleNoteOn(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); + break; + case CIN_AFTER_TOUCH: + handleVelocityChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); + break; + case CIN_CONTROL_CHANGE: + handleControlChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); + break; + case CIN_PROGRAM_CHANGE: + handleProgramChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1); + break; + case CIN_CHANNEL_PRESSURE: + handleAfterTouch(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1); + break; + + case CIN_PITCH_WHEEL: + handlePitchChange(((uint16)e.p.midi2)<<7|((uint16)e.p.midi1)); + break; + case CIN_1BYTE: + switch (e.p.midi0) { + case MIDIv1_CLOCK: + handleSync(); + break; + case MIDIv1_TICK: + break; + case MIDIv1_START: + handleStart(); + break; + case MIDIv1_CONTINUE: + handleContinue(); + break; + case MIDIv1_STOP: + handleStop(); + break; + case MIDIv1_ACTIVE_SENSE: + handleActiveSense(); + break; + case MIDIv1_RESET: + handleReset(); + break; + case MIDIv1_TUNE_REQUEST: + handleTuneRequest(); + break; + + default: + break; + } + break; + } +} + + +// Try to read data from USB port & pass anything read to processing function +void USBMidi::poll(void) +{ while(available()) { + dispatchPacket(readPacket()); + } +} + +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; + outPacket.p.cin=CIN_NOTE_OFF; + outPacket.p.midi0=MIDIv1_NOTE_OFF|(channel & 0x0f); + 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) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_NOTE_ON; + outPacket.p.midi0=MIDIv1_NOTE_ON|(channel & 0x0f); + outPacket.p.midi1=note; + outPacket.p.midi2=velocity; + writePacket(outPacket.i); + +} + +// Send a Midi VELOCITY CHANGE message to a given channel, with given note 0-127, +// and new velocity 0-127 +// Note velocity change == polyphonic aftertouch. +// Note aftertouch == channel pressure. +void USBMidi::sendVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_AFTER_TOUCH; + outPacket.p.midi0=MIDIv1_AFTER_TOUCH |(channel & 0x0f); + outPacket.p.midi1=note; + outPacket.p.midi2=velocity; + writePacket(outPacket.i); + +} + + +// Send a Midi CC message to a given channel, as a given controller 0-127, with given +// value 0-127 +void USBMidi::sendControlChange(unsigned int channel, unsigned int controller, unsigned int value) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_CONTROL_CHANGE; + outPacket.p.midi0=MIDIv1_CONTROL_CHANGE |(channel & 0x0f); + outPacket.p.midi1=controller; + outPacket.p.midi2=value; + writePacket(outPacket.i); + +} + +// Send a Midi PROGRAM CHANGE message to given channel, with program ID 0-127 +void USBMidi::sendProgramChange(unsigned int channel, unsigned int program) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_PROGRAM_CHANGE; + outPacket.p.midi0=MIDIv1_PROGRAM_CHANGE |(channel & 0x0f); + outPacket.p.midi1=program; + writePacket(outPacket.i); + +} + +// Send a Midi AFTER TOUCH message to given channel, with velocity 0-127 +void USBMidi::sendAfterTouch(unsigned int channel, unsigned int velocity) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_CHANNEL_PRESSURE; + outPacket.p.midi0=MIDIv1_CHANNEL_PRESSURE |(channel & 0x0f); + outPacket.p.midi1=velocity; + writePacket(outPacket.i); + +} + +// Send a Midi PITCH CHANGE message, with a 14-bit pitch (always for all channels) +void USBMidi::sendPitchChange(unsigned int pitch) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_PITCH_WHEEL; + outPacket.p.midi0=MIDIv1_PITCH_WHEEL; + outPacket.p.midi1= (uint8) pitch & 0x07F; + outPacket.p.midi2= (uint8) (pitch>>7) & 0x7f; + writePacket(outPacket.i); + +} + +// Send a Midi SONG POSITION message, with a 14-bit position (always for all channels) +void USBMidi::sendSongPosition(unsigned int position) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_3BYTE_SYS_COMMON; + outPacket.p.midi0=MIDIv1_SONG_POSITION_PTR; + outPacket.p.midi1= (uint8) position & 0x07F; + outPacket.p.midi2= (uint8) (position>>7) & 0x7f; + writePacket(outPacket.i); + +} + +// Send a Midi SONG SELECT message, with a song ID of 0-127 (always for all channels) +void USBMidi::sendSongSelect(unsigned int song) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_2BYTE_SYS_COMMON; + outPacket.p.midi0=MIDIv1_SONG_SELECT; + outPacket.p.midi1= (uint8) song & 0x07F; + writePacket(outPacket.i); + +} + +// Send a Midi TUNE REQUEST message (TUNE REQUEST is always for all channels) +void USBMidi::sendTuneRequest(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_TUNE_REQUEST; + writePacket(outPacket.i); +} + + +// Send a Midi SYNC message (SYNC is always for all channels) +void USBMidi::sendSync(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_CLOCK; + writePacket(outPacket.i); +} + +// Send a Midi START message (START is always for all channels) +void USBMidi::sendStart(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_START ; + writePacket(outPacket.i); +} + + +// Send a Midi CONTINUE message (CONTINUE is always for all channels) +void USBMidi::sendContinue(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_CONTINUE ; + writePacket(outPacket.i); +} + + +// Send a Midi STOP message (STOP is always for all channels) +void USBMidi::sendStop(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_STOP ; + writePacket(outPacket.i); +} + +// Send a Midi ACTIVE SENSE message (ACTIVE SENSE is always for all channels) +void USBMidi::sendActiveSense(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_ACTIVE_SENSE ; + writePacket(outPacket.i); +} + +// Send a Midi RESET message (RESET is always for all channels) +void USBMidi::sendReset(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_RESET ; + writePacket(outPacket.i); +} + +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, + 519, 550, 583, 617, 654, 693, 734, 778, 824, 873, 925, 980, 1038, 1100, 1165, 1235, + 1308, 1386, 1468, 1556, 1648, 1746, 1850, 1960, 2077, 2200, 2331, 2469, 2616, 2772, 2937, 3111, + 3296, 3492, 3700, 3920, 4153, 4400, 4662, 4939, 5233, 5544, 5873, 6223, 6593, 6985, 7400, 7840, + 8306, 8800, 9323, 9878, 10465, 11087, 11747, 12445, 13185, 13969, 14800, 15680, 16612, 17600, 18647, 19755, + 20930, 22175, 23493, 24890, 26370, 27938, 29600, 31360, 33224, 35200, 37293, 39511, 41860, 44349, 46986, 49780, + 52740, 55877, 59199, 62719, 66449, 70400, 74586, 79021, 83720, 88698, 93973, 99561, 105481, 111753, 118398, 125439 }; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +// Placeholders. You should subclass the Midi base class and define these to have your +// version called. +void USBMidi::handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) {} +void USBMidi::handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) {} +void USBMidi::handleVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity) {} +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::handleSongPosition(unsigned int position) {} +void USBMidi::handleSongSelect(unsigned int song) {} +void USBMidi::handleTuneRequest(void) {} +void USBMidi::handleSync(void) {} +void USBMidi::handleStart(void) {} +void USBMidi::handleContinue(void) {} +void USBMidi::handleStop(void) {} +void USBMidi::handleActiveSense(void) {} +void USBMidi::handleReset(void) {} +#pragma GCC diagnostic pop diff --git a/STM32F1/libraries/USBComposite/USBMIDI.h b/STM32F1/libraries/USBComposite/USBMIDI.h new file mode 100644 index 0000000..e770047 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBMIDI.h @@ -0,0 +1,186 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2013 Magnus Lundin. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @brief Wirish USB MIDI port (MidiUSB). + */ + +#ifndef _USBMIDI_H_ +#define _USBMIDI_H_ + +//#include +#include +#include +#include "usb_generic.h" + +/* + * This is the Midi class. If you are just sending Midi data, you only need to make an + * instance of the class, passing it your USB port -- in most cases it looks like + * + * USBMidi midi; + * + * then you don't need to do anything else; you can start using it to send Midi messages, + * e.g. + * + * midi.sendNoteOn(1, note, velocity); + * + * If you are using it to receive Midi data, it's a little more complex & you will need + * to subclass the Midi class. + * + * For people not used to C++ this may look confusing, but it's actually pretty easy. + * Note that you only need to write the functions for event types you want to handle. + * They should match the names & prototypes of the functions in the class; look at + * the functions in the Midi class below that have the keyword "virtual" to see which + * ones you can use. + * + * Here's an example of one that takes NOTE ON, NOTE OFF, and CONTROL CHANGE: + * + * class MyMidi : public USBMidi { + * public: + * + * // Need this to compile; it just hands things off to the Midi class. + * MyMidi() : USBMidi(s) {} + * + * void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) + * { + * if (note == 40) {digitalWrite(13, HIGH); } + * } + * + * void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) + * { + * if (note == 40) { digitalWrite(13, LOW); } + * } + * + * void handleControlChange(unsigned int channel, unsigned int controller, + * unsigned int value) + * { + * analogWrite(6, value * 2); + * } + * + * Then you need to make an instance of this class: + * + * MyMidi midi(); + * + * If receiving Midi data, you also need to call the poll function every time through + * loop(); e.g. + * + * void loop() { + * midi.poll(); + * } + * + * This causes the Midi class to read data from the USB port and process it. + */ + +class USBMidi { +private: + bool enabled = false; + + /* Private Receive Parameters */ + + // The channel this Midi instance receives data for (0 means all channels) + int channelIn_; + + /* Internal functions */ + + // Called whenever data is read from the USB port + void dispatchPacket(uint32 packet); + +public: + //static bool init(USBMidi* me); + // This registers this USB composite device component with the USBComposite class instance. + bool registerComponent(); + void setChannel(unsigned channel=0); + unsigned getChannel() { + return channelIn_; + } + + // Call to start the USB port, at given baud. For many applications + // the default parameters are just fine (which will cause messages for all + // MIDI channels to be delivered) + void begin(unsigned int channel = 0); + //void begin(); + void end(); + + uint32 available(void); + + uint32 readPackets(void *buf, uint32 len); + uint32 readPacket(void); + + void writePacket(uint32); +// void write(const char *str); + void writePackets(const void*, uint32); + + uint8 isConnected(); + uint8 pending(); + + // poll() should be called every time through loop() IF dealing with incoming MIDI + // (if you're only SENDING MIDI events from the Arduino, you don't need to call + // poll); it causes data to be read from the USB port and processed. + void poll(); + + // Call these to send MIDI messages of the given types + void sendNoteOff(unsigned int channel, unsigned int note, unsigned int velocity); + void sendNoteOn(unsigned int channel, unsigned int note, unsigned int velocity); + void sendVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity); + 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 sendSongPosition(unsigned int position); + void sendSongSelect(unsigned int song); + void sendTuneRequest(void); + void sendSync(void); + void sendStart(void); + void sendContinue(void); + void sendStop(void); + void sendActiveSense(void); + void sendReset(void); + + // 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); + virtual void handleVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity); + 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 handleSongPosition(unsigned int position); + virtual void handleSongSelect(unsigned int song); + virtual void handleTuneRequest(void); + virtual void handleSync(void); + virtual void handleStart(void); + virtual void handleContinue(void); + virtual void handleStop(void); + virtual void handleActiveSense(void); + virtual void handleReset(void); +}; + +extern USBMidi USBMIDI; + +extern const uint32 midiNoteFrequency_10ths[128]; + +#endif \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/USBMassStorage.cpp b/STM32F1/libraries/USBComposite/USBMassStorage.cpp new file mode 100644 index 0000000..c376e69 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBMassStorage.cpp @@ -0,0 +1,45 @@ +#include "USBMassStorage.h" +#include "usb_mass.h" +#include "usb_mass_mal.h" +#include "usb_serial.h" +#include + +void USBMassStorageDevice::begin() { + if(!enabled) { + USBComposite.clear(); + registerComponent(); + USBComposite.begin(); + + enabled = true; + } +} + +void USBMassStorageDevice::end() { + USBComposite.end(); +} + +void USBMassStorageDevice::loop() { + usb_mass_loop(); +} + +bool USBMassStorageDevice::registerComponent() { + return USBComposite.add(&usbMassPart, this); +} + +void USBMassStorageDevice::setDrive(uint32 driveNumber, uint32 byteSize, MassStorageReader reader, + MassStorageWriter writer, MassStorageStatuser statuser, MassStorageInitializer initializer) { + if (driveNumber >= USB_MASS_MAX_DRIVES) + return; + usb_mass_drives[driveNumber].blockCount = byteSize/512; + usb_mass_drives[driveNumber].read = reader; + usb_mass_drives[driveNumber].write = writer; + usb_mass_drives[driveNumber].status = statuser; + usb_mass_drives[driveNumber].init = initializer; + usb_mass_drives[driveNumber].format = initializer; +} + +void USBMassStorageDevice::clearDrives() { + memset(usb_mass_drives, 0, sizeof(usb_mass_drives)); +} + +USBMassStorageDevice MassStorage; diff --git a/STM32F1/libraries/USBComposite/USBMassStorage.h b/STM32F1/libraries/USBComposite/USBMassStorage.h new file mode 100644 index 0000000..02663ab --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBMassStorage.h @@ -0,0 +1,25 @@ +#ifndef USBMASSSTORAGE_H +#define USBMASSSTORAGE_H + +#include +#include "USBComposite.h" +#include "usb_generic.h" +#include "usb_mass_mal.h" + +class USBMassStorageDevice { +private: + bool enabled = false; +public: + void begin(); + void end(); + void loop(); + void clearDrives(void); + bool registerComponent(); + void setDrive(uint32 driveNumber, uint32 byteSize, MassStorageReader reader, + MassStorageWriter writer = NULL, MassStorageStatuser = NULL, MassStorageInitializer = NULL); +}; + +extern USBMassStorageDevice MassStorage; + +#endif /* USBMASSSTORAGE_H */ + diff --git a/STM32F1/libraries/USBComposite/USBXBox360.cpp b/STM32F1/libraries/USBComposite/USBXBox360.cpp new file mode 100644 index 0000000..83237c0 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBXBox360.cpp @@ -0,0 +1,173 @@ +/* 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. +*/ + +/** + * @brief USB HID Keyboard device + */ + +#include +#include +#include +#include +#include "USBXBox360.h" +#include "usb_x360.h" + +void USBXBox360::sendReport(void){ + x360_tx(xbox360_Report, sizeof(xbox360_Report)); + + while (x360_is_transmitting() != 0) { + } + /* flush out to avoid having the pc wait for more data */ + x360_tx(NULL, 0); +} + +void USBXBox360::setRumbleCallback(void (*callback)(uint8 left, uint8 right)) { + x360_set_rumble_callback(callback); +} + +void USBXBox360::setLEDCallback(void (*callback)(uint8 pattern)) { + x360_set_led_callback(callback); +} + + +bool USBXBox360::init(void* ignore) { + (void)ignore; + usb_generic_set_info(0x045e, 0x028e, NULL, NULL, NULL); + return true; +} + +bool USBXBox360::registerComponent() { + return USBComposite.add(&usbX360Part, this, init); +} + +void USBXBox360::begin(void){ + if(!enabled){ + USBComposite.clear(); + registerComponent(); + USBComposite.begin(); + + enabled = true; + } +} + +void USBXBox360::end() { + if (enabled) { + enabled = false; + USBComposite.end(); + } +} + +void USBXBox360::stop(void){ + setRumbleCallback(NULL); + setLEDCallback(NULL); +} + +void USBXBox360::setManualReportMode(bool mode) { + manualReport = mode; +} + +bool USBXBox360::getManualReportMode() { + return manualReport; +} + +void USBXBox360::safeSendReport() { + if (!manualReport) { + while (x360_is_transmitting() != 0) { + } + sendReport(); + } +} + +void USBXBox360::send() { + while (x360_is_transmitting() != 0) { + } + sendReport(); +} + +void USBXBox360::button(uint8_t button, bool val){ + button--; + uint8_t mask = (1 << (button & 7)); + if (val) { + if (button < 8) xbox360_Report[2] |= mask; + else if (button < 16) xbox360_Report[3] |= mask; + } else { + mask = ~mask; + if (button < 8) xbox360_Report[2] &= mask; + else if (button < 16) xbox360_Report[3] &= mask; + } + + safeSendReport(); +} + +void USBXBox360::X(int16_t val){ + xbox360_Report[6] = val; + xbox360_Report[7] = (uint16)val >> 8; + + safeSendReport(); +} + +void USBXBox360::Y(int16_t val){ + xbox360_Report[8] = val; + xbox360_Report[9] = (uint16)val >> 8; + + safeSendReport(); +} + +void USBXBox360::XRight(int16_t val){ + xbox360_Report[0xA] = val; + xbox360_Report[0xB] = (uint16)val >> 8; + + safeSendReport(); +} + +void USBXBox360::YRight(int16_t val){ + xbox360_Report[0xC] = val; + xbox360_Report[0xD] = (uint16)val >> 8; + + safeSendReport(); +} + +void USBXBox360::position(int16_t x, int16_t y){ + xbox360_Report[6] = x; + xbox360_Report[7] = (uint16)x >> 8; + xbox360_Report[8] = y; + xbox360_Report[9] = (uint16)y >> 8; + + safeSendReport(); +} + +void USBXBox360::positionRight(int16_t x, int16_t y){ + xbox360_Report[0xA] = x; + xbox360_Report[0xB] = (uint16)x >> 8; + xbox360_Report[0xC] = y; + xbox360_Report[0xD] = (uint16)y >> 8; + + safeSendReport(); +} + +void USBXBox360::sliderLeft(uint8_t val){ + xbox360_Report[4] = val; + + safeSendReport(); +} + +void USBXBox360::sliderRight(uint8_t val){ + xbox360_Report[5] = val; + + safeSendReport(); +} + +USBXBox360 XBox360; diff --git a/STM32F1/libraries/USBComposite/USBXBox360.h b/STM32F1/libraries/USBComposite/USBXBox360.h new file mode 100644 index 0000000..e48e7a7 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBXBox360.h @@ -0,0 +1,58 @@ +/* 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. +*/ + +#ifndef _USBXBox360_H +#define _USBXBox360_H + +#include +#include +#include "USBComposite.h" +#include "usb_generic.h" + +class USBXBox360 { +private: + uint8_t xbox360_Report[20] = {0,0x14};// 3,0,0,0,0,0x0F,0x20,0x80,0x00,0x02,0x08,0x20,0x80}; + bool manualReport = false; + bool enabled; + void safeSendReport(void); + void sendReport(void); +public: + void send(void); + static bool init(void* ignore); + bool registerComponent(); + void stop(); + void setManualReportMode(bool manualReport); + bool getManualReportMode(); + void begin(void); + void end(void); + void button(uint8_t button, bool val); + void X(int16_t val); + void Y(int16_t val); + void position(int16_t x, int16_t y); + void positionRight(int16_t x, int16_t y); + void XRight(int16_t val); + void YRight(int16_t val); + void sliderLeft(uint8_t val); + void sliderRight(uint8_t val); + void hat(int16_t dir); + void setLEDCallback(void (*callback)(uint8 pattern)); + void setRumbleCallback(void (*callback)(uint8 left, uint8 right)); +}; + +extern USBXBox360 XBox360; + +#endif + diff --git a/STM32F1/libraries/USBComposite/examples/BootKeyboard/BootKeyboard.ino b/STM32F1/libraries/USBComposite/examples/BootKeyboard/BootKeyboard.ino new file mode 100644 index 0000000..72b42f5 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/BootKeyboard/BootKeyboard.ino @@ -0,0 +1,15 @@ +#include + +void setup() +{ + USBHID_begin_with_serial(HID_BOOT_KEYBOARD); + BootKeyboard.begin(); // needed just in case you need LED support +} + +void loop() +{ + BootKeyboard.press(KEY_F12); + delay(100); + BootKeyboard.release(KEY_F12); + delay(1000); +} diff --git a/STM32F1/libraries/USBComposite/examples/absmouse/absmouse.ino b/STM32F1/libraries/USBComposite/examples/absmouse/absmouse.ino new file mode 100644 index 0000000..29368ea --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/absmouse/absmouse.ino @@ -0,0 +1,25 @@ +#include + +const uint8_t reportDescription[] = { + HID_ABS_MOUSE_REPORT_DESCRIPTOR(HID_MOUSE_REPORT_ID) +}; + +HIDAbsMouse mouse; + +void setup(){ + USBHID_begin_with_serial(reportDescription, sizeof(reportDescription)); + delay(1000); + mouse.move(0,0); + delay(1000); + mouse.press(MOUSE_LEFT); + mouse.move(500,500); + mouse.release(MOUSE_ALL); + mouse.click(MOUSE_RIGHT); +} + +void loop(){ + mouse.move(0,0); + delay(1000); + mouse.move(16384,16384); + delay(1000); +} diff --git a/STM32F1/libraries/USBComposite/examples/consumer/consumer.ino b/STM32F1/libraries/USBComposite/examples/consumer/consumer.ino new file mode 100644 index 0000000..9cf9c9f --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/consumer/consumer.ino @@ -0,0 +1,18 @@ +#include + +const uint8_t reportDescription[] = { + HID_CONSUMER_REPORT_DESCRIPTOR() +}; + +HIDConsumer Consumer; + +void setup(){ + USBHID_begin_with_serial(reportDescription, sizeof(reportDescription)); +} + +void loop() { + Consumer.press(HIDConsumer::BRIGHTNESS_DOWN); + Consumer.release(); + delay(500); +} + diff --git a/STM32F1/libraries/USBComposite/examples/keyboardwithleds/keyboardwithleds.ino b/STM32F1/libraries/USBComposite/examples/keyboardwithleds/keyboardwithleds.ino new file mode 100644 index 0000000..d45a312 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/keyboardwithleds/keyboardwithleds.ino @@ -0,0 +1,14 @@ +#include + + +void setup() { + USBHID_begin_with_serial(HID_KEYBOARD); + Keyboard.begin(); // needed for LED support + delay(1000); +} + +void loop() { + CompositeSerial.println(Keyboard.getLEDs()); +} + + diff --git a/STM32F1/libraries/USBComposite/examples/mass/image.h b/STM32F1/libraries/USBComposite/examples/mass/image.h new file mode 100644 index 0000000..f96b941 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/mass/image.h @@ -0,0 +1,67 @@ +uint8 image[11776] = { +0xEB,0x3C,0x90,0x6D,0x6B,0x64,0x6F,0x73,0x66,0x73,0x00,0x00,0x02,0x04,0x01,0x00, +0x02,0x10,0x00,0x17,0x00,0xF8,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x29,0xDB,0x32,0x73,0x5A,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x41,0x54,0x31,0x32,0x20,0x20,0x20,0x0E,0x1F, +0xBE,0x5B,0x7C,0xAC,0x22,0xC0,0x74,0x0B,0x56,0xB4,0x0E,0xBB,0x07,0x00,0xCD,0x10, +0x5E,0xEB,0xF0,0x32,0xE4,0xCD,0x16,0xCD,0x19,0xEB,0xFE,0x54,0x68,0x69,0x73,0x20, +0x69,0x73,0x20,0x6E,0x6F,0x74,0x20,0x61,0x20,0x62,0x6F,0x6F,0x74,0x61,0x62,0x6C, +0x65,0x20,0x64,0x69,0x73,0x6B,0x2E,0x20,0x20,0x50,0x6C,0x65,0x61,0x73,0x65,0x20, +0x69,0x6E,0x73,0x65,0x72,0x74,0x20,0x61,0x20,0x62,0x6F,0x6F,0x74,0x61,0x62,0x6C, +0x65,0x20,0x66,0x6C,0x6F,0x70,0x70,0x79,0x20,0x61,0x6E,0x64,0x0D,0x0A,0x70,0x72, +0x65,0x73,0x73,0x20,0x61,0x6E,0x79,0x20,0x6B,0x65,0x79,0x20,0x74,0x6F,0x20,0x74, +0x72,0x79,0x20,0x61,0x67,0x61,0x69,0x6E,0x20,0x2E,0x2E,0x2E,0x20,0x0D,0x0A,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,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,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,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,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,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,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,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,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,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,0x55,0xAA, +0xF8,0xFF,0xFF,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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, +}; diff --git a/STM32F1/libraries/USBComposite/examples/mass/mass.ino b/STM32F1/libraries/USBComposite/examples/mass/mass.ino new file mode 100644 index 0000000..e10c04e --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/mass/mass.ino @@ -0,0 +1,65 @@ +#include + +#include "image.h" + +bool write(uint32_t memoryOffset, const uint8_t *writebuff, uint16_t transferLength) { + memcpy(image+memoryOffset, writebuff, transferLength); + + return true; +} + +bool read(uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength) { + memcpy(readbuff, image+memoryOffset, 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() { + MassStorage.setDrive(0, sizeof(image), 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/examples/midiin/midiin.ino b/STM32F1/libraries/USBComposite/examples/midiin/midiin.ino new file mode 100644 index 0000000..20da70a --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/midiin/midiin.ino @@ -0,0 +1,27 @@ +#include + +#define SPEAKER_PIN PA0 + +class myMidi : public USBMidi { + virtual void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) { + noTone(SPEAKER_PIN); + } + virtual void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) { + tone(SPEAKER_PIN, (midiNoteFrequency_10ths[note]+5)/10); + } + +}; + +myMidi midi; + +void setup() { + pinMode(SPEAKER_PIN, OUTPUT); + midi.registerComponent(); + CompositeSerial.registerComponent(); + USBComposite.begin(); +} + +void loop() { + midi.poll(); +} + diff --git a/STM32F1/libraries/USBComposite/examples/midiout/midiout.ino b/STM32F1/libraries/USBComposite/examples/midiout/midiout.ino new file mode 100644 index 0000000..3fe98b0 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/midiout/midiout.ino @@ -0,0 +1,17 @@ +#include + +const uint8_t notes[] = {60, 62, 64, 65, 67, 69, 71, 72, 61, 63, 66, 68, 70}; +const int numNotes = sizeof(notes)/sizeof(*notes); + +void setup() { + USBMIDI.begin(); + delay(1000); +} + +void loop() { + for (int i=0;i + +#define TXSIZE 256 +#define RXSIZE 300 + +HIDRaw raw; +uint8 buf[RXSIZE]; + +const uint8_t reportDescription[] = { + HID_RAW_REPORT_DESCRIPTOR(TXSIZE,RXSIZE) +}; + +void setup(){ + USBHID_begin_with_serial(reportDescription, sizeof(reportDescription)); + raw.begin(); +} + +void loop() { + if (raw.getOutput(buf)) { + for (int i=0;i +#include +#include "SdFat.h" + +#define LED_PIN PB12 + +SdFatEX sd; +const uint32_t speed = SPI_CLOCK_DIV2 ; +const uint8_t SD_CHIP_SELECT = SS; +bool enabled = false; +uint32 cardSize; + +bool write(uint32_t memoryOffset, const uint8_t *writebuff, uint16_t transferLength) { + return sd.card()->writeBlocks(memoryOffset/512, writebuff, transferLength/512); +} + +bool read(uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength) { + return sd.card()->readBlocks(memoryOffset/512, readbuff, transferLength/512); +} + +void setup() { + pinMode(LED_PIN,OUTPUT); + digitalWrite(LED_PIN,1); +} + +void initReader() { + digitalWrite(LED_PIN,0); + cardSize = sd.card()->cardSize(); + MassStorage.setDrive(0, cardSize*512, read, write); + MassStorage.registerComponent(); + CompositeSerial.registerComponent(); + USBComposite.begin(); + enabled=true; +} + +void loop() { + if (!enabled) { + if (sd.begin(SD_CHIP_SELECT)) { + initReader(); + } + else { + delay(50); + } + } + else { + MassStorage.loop(); + } +} + diff --git a/STM32F1/libraries/USBComposite/examples/simplejoystick/simplejoystick.ino b/STM32F1/libraries/USBComposite/examples/simplejoystick/simplejoystick.ino new file mode 100644 index 0000000..f0c75df --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/simplejoystick/simplejoystick.ino @@ -0,0 +1,13 @@ +#include + +void setup() { + USBHID_begin_with_serial(HID_JOYSTICK); +} + +void loop() { + Joystick.X(0); + delay(500); + Joystick.X(1023); + delay(500); +} + diff --git a/STM32F1/libraries/USBComposite/examples/simplekeyboard/simplekeyboard.ino b/STM32F1/libraries/USBComposite/examples/simplekeyboard/simplekeyboard.ino new file mode 100644 index 0000000..80c296f --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/simplekeyboard/simplekeyboard.ino @@ -0,0 +1,13 @@ +#include + +void setup() { + USBHID_begin_with_serial(HID_KEYBOARD); + Keyboard.begin(); // useful to detect host capslock state and LEDs + delay(1000); +} + +void loop() { + Keyboard.println("Hello world"); + delay(10000); +} + diff --git a/STM32F1/libraries/USBComposite/examples/softjoystick/send.py b/STM32F1/libraries/USBComposite/examples/softjoystick/send.py new file mode 100644 index 0000000..5025db9 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/softjoystick/send.py @@ -0,0 +1,60 @@ +from pywinusb import hid +from time import sleep + +REPORT_ID = 20 +HID_REPORT_FEATURE = 3 + +device = hid.HidDeviceFilter(vendor_id = 0x1EAF).get_devices()[0] # , product_id = 0x0024 +print(device) +device.open() + +""" + uint8_t reportID; + uint32_t buttons; + unsigned hat:4; + unsigned x:10; + unsigned y:10; + unsigned rx:10; + unsigned ry:10; + unsigned sliderLeft:10; + unsigned sliderRight:10; +""" + +def toBits(n,bits): + return tuple((n>>i)&1 for i in range(bits)) + +def getByteFromBits(bits,n): + out = 0 + for i in range(8): + out += bits[8*n+i] << i + return out + +def joystickData(reportID=REPORT_ID, buttons=0, hat=15, x=512, y=512, rx=512, ry=512, sliderLeft=512, sliderRight=512): + joyData = ( toBits(reportID,8) + toBits(buttons,32) + toBits(hat,4) + toBits(x,10) + toBits(y,10) + + toBits(rx,10) + toBits(ry,10) + toBits(sliderLeft,10) + toBits(sliderRight,10) ) + out = [getByteFromBits(joyData,n) for n in range(13)] + print(out) + return out + +myReport = None + +for report in device.find_feature_reports(): + if report.report_id == REPORT_ID and report.report_type == "Feature": + myReport = report + break +if myReport is None: + for report in device.find_output_reports(): + if report.report_id == REPORT_ID and report.report_type == "Output": + myReport = report + break + +assert myReport is not None + +while True: + myReport.set_raw_data(joystickData(buttons=7,x=0,y=0)) + + myReport.send() + sleep(0.5) + myReport.set_raw_data(joystickData(buttons=0,x=1023,y=1023)) + myReport.send() + sleep(0.5) diff --git a/STM32F1/libraries/USBComposite/examples/softjoystick/softjoystick.ino b/STM32F1/libraries/USBComposite/examples/softjoystick/softjoystick.ino new file mode 100644 index 0000000..0fe9b55 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/softjoystick/softjoystick.ino @@ -0,0 +1,47 @@ +// This is a silly project: you send a feature +// report from the PC, and it becomes a joystick setting. +// I guess it's not completely useless as it lets you +// get vJoy functionality without special vJoy drivers. + +#include + +#define DATA_SIZE (sizeof(JoystickReport_t)-1) + +class HIDJoystickRawData : public HIDJoystick { + private: + uint8_t featureData[HID_BUFFER_ALLOCATE_SIZE(DATA_SIZE,1)]; + HIDBuffer_t fb { featureData, HID_BUFFER_SIZE(DATA_SIZE,1), HID_JOYSTICK_REPORT_ID }; + public: + HIDJoystickRawData(uint8_t reportID=HID_JOYSTICK_REPORT_ID) : HIDJoystick(reportID) {} + + void begin() { + USBHID.setFeatureBuffers(&fb, 1); + } + + void setRawData(JoystickReport_t* p) { + joyReport = *p; + send(); + } +}; + +HIDJoystickRawData joy; +JoystickReport_t report = {HID_JOYSTICK_REPORT_ID}; + +const uint8_t reportDescription[] = { + HID_JOYSTICK_REPORT_DESCRIPTOR(HID_JOYSTICK_REPORT_ID, + HID_FEATURE_REPORT_DESCRIPTOR(DATA_SIZE)) +}; + +void setup() { + USBHID_begin_with_serial(reportDescription, sizeof(reportDescription)); + joy.begin(); +} + +void loop() { + if (joy.getFeature(1+(uint8_t*)&report)) { + joy.setRawData(&report); + } + + delay(5); +} + diff --git a/STM32F1/libraries/USBComposite/examples/twojoysticks/twojoysticks.ino b/STM32F1/libraries/USBComposite/examples/twojoysticks/twojoysticks.ino new file mode 100644 index 0000000..7cf929d --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/twojoysticks/twojoysticks.ino @@ -0,0 +1,40 @@ +#include + +const uint8_t reportDescription[] = { + HID_MOUSE_REPORT_DESCRIPTOR(), + HID_KEYBOARD_REPORT_DESCRIPTOR(), + HID_JOYSTICK_REPORT_DESCRIPTOR(), + HID_JOYSTICK_REPORT_DESCRIPTOR(HID_JOYSTICK_REPORT_ID+1), +}; + +HIDJoystick Joystick2(HID_JOYSTICK_REPORT_ID+1); + +void setup(){ + USBHID_begin_with_serial(reportDescription, sizeof(reportDescription)); + Joystick.setManualReportMode(true); + Joystick2.setManualReportMode(true); +} + +void loop(){ + Joystick.X(0); + Joystick.Y(0); + Joystick.sliderRight(1023); + Joystick.send(); + delay(400); + Joystick.X(1023); + Joystick.Y(1023); + Joystick.sliderRight(0); + Joystick.send(); + delay(400); + Joystick2.X(0); + Joystick2.Y(0); + Joystick2.sliderRight(1023); + Joystick2.send(); + delay(400); + Joystick2.X(1023); + Joystick2.Y(1023); + Joystick2.sliderRight(0); + Joystick2.send(); + delay(400); +} + diff --git a/STM32F1/libraries/USBComposite/examples/x360/x360.ino b/STM32F1/libraries/USBComposite/examples/x360/x360.ino new file mode 100644 index 0000000..d97a7f3 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/x360/x360.ino @@ -0,0 +1,15 @@ +#include + +void setup() { + XBox360.begin(); + delay(1000); +} + +void loop() { + XBox360.X(-32767); + XBox360.Y(-32767); + delay(1000); + XBox360.X(32767); + XBox360.Y(32767); + delay(1000); +} diff --git a/STM32F1/libraries/USBComposite/keywords.txt b/STM32F1/libraries/USBComposite/keywords.txt new file mode 100644 index 0000000..3092c00 --- /dev/null +++ b/STM32F1/libraries/USBComposite/keywords.txt @@ -0,0 +1,89 @@ +####################################### +# Syntax Coloring Map USBHID +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +HID KEYWORD1 +Joystick KEYWORD1 +Keyboard KEYWORD1 +Mouse KEYWORD1 +CompositeSerial KEYWORD1 +XBox360 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +XRight KEYWORD2 +YRight KEYWORD2 +Yrotate KEYWORD2 +Y KEYWORD2 +Xrotate KEYWORD2 +X KEYWORD2 +sliderLeft KEYWORD2 +sliderRight KEYWORD2 +button KEYWORD2 +hat KEYWORD2 +setManualReportMode KEYWORD2 +getManualReportMode KEYWORD2 +release KEYWORD2 +press KEYWORD2 +releaseAll KEYWORD2 +move KEYWORD2 +send KEYWORD2 +click KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +USB_HID_MOUSE LITERAL1 +USB_HID_KEYBOARD LITERAL1 +USB_HID_JOYSTICK LITERAL1 +USB_HID_KEYBOARD_MOUSE LITERAL1 +USB_HID_KEYBOARD_MOUSE_JOYSTICK LITERAL1 +USB_HID_KEYBOARD_JOYSTICK LITERAL1 +KEY_LEFT_CTRL LITERAL1 +KEY_LEFT_SHIFT LITERAL1 +KEY_LEFT_ALT LITERAL1 +KEY_LEFT_GUI LITERAL1 +KEY_RIGHT_CTRL LITERAL1 +KEY_RIGHT_SHIFT LITERAL1 +KEY_RIGHT_ALT LITERAL1 +KEY_RIGHT_GUI LITERAL1 +KEY_UP_ARROW LITERAL1 +KEY_DOWN_ARROW LITERAL1 +KEY_LEFT_ARROW LITERAL1 +KEY_RIGHT_ARROW LITERAL1 +KEY_BACKSPACE LITERAL1 +KEY_TAB LITERAL1 +KEY_RETURN LITERAL1 +KEY_ESC LITERAL1 +KEY_INSERT LITERAL1 +KEY_DELETE LITERAL1 +KEY_PAGE_UP LITERAL1 +KEY_PAGE_DOWN LITERAL1 +KEY_HOME LITERAL1 +KEY_END LITERAL1 +KEY_CAPS_LOCK LITERAL1 +KEY_F1 LITERAL1 +KEY_F2 LITERAL1 +KEY_F3 LITERAL1 +KEY_F4 LITERAL1 +KEY_F5 LITERAL1 +KEY_F6 LITERAL1 +KEY_F7 LITERAL1 +KEY_F8 LITERAL1 +KEY_F9 LITERAL1 +KEY_F10 LITERAL1 +KEY_F11 LITERAL1 +KEY_F12 LITERAL1 +MOUSE_LEFT LITERAL1 +MOUSE_MIDDLE LITERAL1 +MOUSE_RIGHT LITERAL1 +MOUSE_ALL LITERAL1 +HIDConsumer LITERAL1 diff --git a/STM32F1/libraries/USBComposite/library.properties b/STM32F1/libraries/USBComposite/library.properties new file mode 100644 index 0000000..1d8c2cb --- /dev/null +++ b/STM32F1/libraries/USBComposite/library.properties @@ -0,0 +1,10 @@ +name=USBComposite for STM32F1 +version=0.64 +author=Various +email=arpruss@gmail.com +sentence=USB HID / MIDI / mass storage library for STM32F1 +paragraph=USB HID / MIDI / mass storage library for STM32F1 +url=https://github.com/arpruss/USBHID_stm32f1 +architectures=STM32F1 +maintainer=arpruss@gmail.com +category=Communication \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/usb_generic.c b/STM32F1/libraries/USBComposite/usb_generic.c new file mode 100644 index 0000000..c9ed0b3 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_generic.c @@ -0,0 +1,531 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usb/stm32f1/usb_hid.c + * @brief USB HID (human interface device) support + * + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + + +//uint16 GetEPTxAddr(uint8 /*bEpNum*/); + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +#include "usb_generic.h" + +// Are we currently sending an IN packet? +volatile int8 usbGenericTransmitting = -1; + +static uint8* usbGetConfigDescriptor(uint16 length); +static void usbInit(void); +static void usbReset(void); +static void usbClearFeature(void); +static void usbSetConfiguration(void); +static RESULT usbDataSetup(uint8 request); +static RESULT usbNoDataSetup(uint8 request); +static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting); +static uint8* usbGetStringDescriptor(uint16 length); +static uint8* usbGetConfigDescriptor(uint16 length); +static uint8* usbGetDeviceDescriptor(uint16 length); +static void usbSetConfiguration(void); +static void usbSetDeviceAddress(void); + +#define LEAFLABS_ID_VENDOR 0x1EAF +#define MAPLE_ID_PRODUCT 0x0004 // was 0x0024 +#define USB_DEVICE_CLASS 0x00 +#define USB_DEVICE_SUBCLASS 0x00 +#define DEVICE_PROTOCOL 0x01 +#define HID_DESCRIPTOR_TYPE 0x21 + +static usb_descriptor_device usbGenericDescriptor_Device = + { + .bLength = sizeof(usb_descriptor_device), + .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_DEVICE_CLASS, + .bDeviceSubClass = USB_DEVICE_SUBCLASS, + .bDeviceProtocol = DEVICE_PROTOCOL, + .bMaxPacketSize0 = 0x40, + .idVendor = LEAFLABS_ID_VENDOR, + .idProduct = MAPLE_ID_PRODUCT, + .bcdDevice = 0x0200, + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x00, + .bNumConfigurations = 0x01, +}; + +typedef struct { + usb_descriptor_config_header Config_Header; + uint8 descriptorData[MAX_USB_DESCRIPTOR_DATA_SIZE]; +} __packed usb_descriptor_config; + +static usb_descriptor_config usbConfig; + +#define MAX_POWER (100 >> 1) + +static const usb_descriptor_config_header Base_Header = { + .bLength = sizeof(usb_descriptor_config_header), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 0, + .bConfigurationValue = 0x01, + .iConfiguration = 0x00, + .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED), + .bMaxPower = MAX_POWER, +}; + +static ONE_DESCRIPTOR Device_Descriptor = { + (uint8*)&usbGenericDescriptor_Device, + sizeof(usb_descriptor_device) +}; + +static ONE_DESCRIPTOR Config_Descriptor = { + (uint8*)&usbConfig, + 0 +}; + +static DEVICE my_Device_Table = { + .Total_Endpoint = 0, + .Total_Configuration = 1 +}; + +/* Unicode language identifier: 0x0409 is US English */ +/* FIXME move to Wirish */ +static const usb_descriptor_string usbHIDDescriptor_LangID = { + .bLength = USB_DESCRIPTOR_STRING_LEN(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING, + .bString = {0x09, 0x04}, +}; + +#define default_iManufacturer_length 8 +const usb_descriptor_string usb_generic_default_iManufacturer = { + .bLength = USB_DESCRIPTOR_STRING_LEN(default_iManufacturer_length), + .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING, + .bString = {'L', 0, 'e', 0, 'a', 0, 'f', 0, 'L', 0, 'a', 0, 'b', 0, 's', 0}, +}; + +#define default_iProduct_length 5 +const usb_descriptor_string usb_generic_default_iProduct = { + .bLength = USB_DESCRIPTOR_STRING_LEN(default_iProduct_length), + .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING, + .bString = {'M', 0, 'a', 0, 'p', 0, 'l', 0, 'e', 0}, +}; + + +#define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */ +static DEVICE_PROP my_Device_Property = { + .Init = usbInit, + .Reset = usbReset, + .Process_Status_IN = NOP_Process, + .Process_Status_OUT = NOP_Process, + .Class_Data_Setup = usbDataSetup, + .Class_NoData_Setup = usbNoDataSetup, + .Class_Get_Interface_Setting = usbGetInterfaceSetting, + .GetDeviceDescriptor = usbGetDeviceDescriptor, + .GetConfigDescriptor = usbGetConfigDescriptor, + .GetStringDescriptor = usbGetStringDescriptor, + .RxEP_buffer = NULL, + .MaxPacketSize = MAX_PACKET_SIZE +}; + +static const USER_STANDARD_REQUESTS my_User_Standard_Requests = { + .User_GetConfiguration = NOP_Process, + .User_SetConfiguration = usbSetConfiguration, + .User_GetInterface = NOP_Process, + .User_SetInterface = NOP_Process, + .User_GetStatus = NOP_Process, + .User_ClearFeature = usbClearFeature, + .User_SetEndPointFeature = NOP_Process, + .User_SetDeviceFeature = NOP_Process, + .User_SetDeviceAddress = usbSetDeviceAddress +}; + +static uint8 numStringDescriptors = 3; + + +#define MAX_STRING_DESCRIPTORS 4 +static ONE_DESCRIPTOR String_Descriptor[MAX_STRING_DESCRIPTORS] = { + {(uint8*)&usbHIDDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)}, + {(uint8*)&usb_generic_default_iManufacturer, USB_DESCRIPTOR_STRING_LEN(default_iManufacturer_length)}, + {(uint8*)&usb_generic_default_iProduct, USB_DESCRIPTOR_STRING_LEN(default_iProduct_length)}, + {NULL, 0}, +}; + +static USBCompositePart** parts; +static uint32 numParts; +static DEVICE saved_Device_Table; +static DEVICE_PROP saved_Device_Property; +static USER_STANDARD_REQUESTS saved_User_Standard_Requests; + +static void (*ep_int_in[7])(void); +static void (*ep_int_out[7])(void); + +uint8 usb_generic_set_parts(USBCompositePart** _parts, unsigned _numParts) { + parts = _parts; + numParts = _numParts; + unsigned numInterfaces = 0; + unsigned numEndpoints = 1; + uint16 usbDescriptorSize = 0; + uint16 pmaOffset = USB_EP0_RX_BUFFER_ADDRESS + USB_EP0_BUFFER_SIZE; + + for (unsigned i = 0 ; i < 7 ; i++) { + ep_int_in[i] = NOP_Process; + ep_int_out[i] = NOP_Process; + } + + usbDescriptorSize = 0; + for (unsigned i = 0 ; i < _numParts ; i++ ) { + parts[i]->startInterface = numInterfaces; + numInterfaces += parts[i]->numInterfaces; + if (numEndpoints + parts[i]->numEndpoints > 8) { + return 0; + } + if (usbDescriptorSize + parts[i]->descriptorSize > MAX_USB_DESCRIPTOR_DATA_SIZE) { + return 0; + } + parts[i]->startEndpoint = numEndpoints; + USBEndpointInfo* ep = parts[i]->endpoints; + for (unsigned j = 0 ; j < parts[i]->numEndpoints ; j++) { + if (ep[j].bufferSize + pmaOffset > PMA_MEMORY_SIZE) { + return 0; + } + ep[j].pmaAddress = pmaOffset; + pmaOffset += ep[j].bufferSize; + ep[j].address = numEndpoints; + if (ep[j].callback == NULL) + ep[j].callback = NOP_Process; + if (ep[j].tx) { + ep_int_in[numEndpoints - 1] = ep[j].callback; + } + else { + ep_int_out[numEndpoints - 1] = ep[j].callback; + } + numEndpoints++; + } + parts[i]->getPartDescriptor(usbConfig.descriptorData + usbDescriptorSize); + usbDescriptorSize += parts[i]->descriptorSize; + } + + usbConfig.Config_Header = Base_Header; + usbConfig.Config_Header.bNumInterfaces = numInterfaces; + usbConfig.Config_Header.wTotalLength = usbDescriptorSize + sizeof(Base_Header); + Config_Descriptor.Descriptor_Size = usbConfig.Config_Header.wTotalLength; + + my_Device_Table.Total_Endpoint = numEndpoints; + + return 1; +} + +void usb_generic_set_info( uint16 idVendor, uint16 idProduct, const uint8* iManufacturer, const uint8* iProduct, const uint8* iSerialNumber) { + if (idVendor != 0) + usbGenericDescriptor_Device.idVendor = idVendor; + else + usbGenericDescriptor_Device.idVendor = LEAFLABS_ID_VENDOR; + + if (idProduct != 0) + usbGenericDescriptor_Device.idProduct = idProduct; + else + usbGenericDescriptor_Device.idProduct = MAPLE_ID_PRODUCT; + + if (iManufacturer == NULL) { + iManufacturer = (uint8*)&usb_generic_default_iManufacturer; + } + + String_Descriptor[1].Descriptor = (uint8*)iManufacturer; + String_Descriptor[1].Descriptor_Size = iManufacturer[0]; + + if (iProduct == NULL) { + iProduct = (uint8*)&usb_generic_default_iProduct; + } + + String_Descriptor[2].Descriptor = (uint8*)iProduct; + String_Descriptor[2].Descriptor_Size = iProduct[0]; + + if (iSerialNumber == NULL) { + numStringDescriptors = 3; + usbGenericDescriptor_Device.iSerialNumber = 0; + } + else { + String_Descriptor[3].Descriptor = (uint8*)iSerialNumber; + String_Descriptor[3].Descriptor_Size = iSerialNumber[0]; + numStringDescriptors = 4; + usbGenericDescriptor_Device.iSerialNumber = 3; + } +} + +void usb_generic_enable(void) { + /* Present ourselves to the host. Writing 0 to "disc" pin must + * pull USB_DP pin up while leaving USB_DM pulled down by the + * transceiver. See USB 2.0 spec, section 7.1.7.3. */ + +#ifdef GENERIC_BOOTLOADER + //Reset the USB interface on generic boards - developed by Victor PV + gpio_set_mode(GPIOA, 12, GPIO_OUTPUT_PP); + gpio_write_bit(GPIOA, 12, 0); + + for(volatile unsigned int i=0;i<512;i++);// Only small delay seems to be needed + gpio_set_mode(GPIOA, 12, GPIO_INPUT_FLOATING); +#endif + + if (BOARD_USB_DISC_DEV != NULL) { + gpio_set_mode(BOARD_USB_DISC_DEV, (uint8)(uint32)BOARD_USB_DISC_BIT, GPIO_OUTPUT_PP); + gpio_write_bit(BOARD_USB_DISC_DEV, (uint8)(uint32)BOARD_USB_DISC_BIT, 0); + } + + saved_Device_Table = Device_Table; + saved_Device_Property = Device_Property; + saved_User_Standard_Requests = User_Standard_Requests; + Device_Table = my_Device_Table; + Device_Property = my_Device_Property; + User_Standard_Requests = my_User_Standard_Requests; + + /* Initialize the USB peripheral. */ + usb_init_usblib(USBLIB, ep_int_in, ep_int_out); +} + +static void usbInit(void) { + pInformation->Current_Configuration = 0; + + USB_BASE->CNTR = USB_CNTR_FRES; + + USBLIB->irq_mask = 0; + USB_BASE->CNTR = USBLIB->irq_mask; + USB_BASE->ISTR = 0; + USBLIB->irq_mask = USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; + USB_BASE->CNTR = USBLIB->irq_mask; + + USB_BASE->ISTR = 0; + USBLIB->irq_mask = USB_ISR_MSK; + USB_BASE->CNTR = USBLIB->irq_mask; + + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + + for (unsigned i = 0 ; i < numParts ; i++) + if(parts[i]->usbInit != NULL) + parts[i]->usbInit(); + + USBLIB->state = USB_UNCONNECTED; +} + +#define BTABLE_ADDRESS 0x00 + +static void usbReset(void) { + pInformation->Current_Configuration = 0; + + /* current feature is current bmAttributes */ + pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED); + + USB_BASE->BTABLE = BTABLE_ADDRESS; + + /* setup control endpoint 0 */ + usb_set_ep_type(USB_EP0, USB_EP_EP_TYPE_CONTROL); + usb_set_ep_tx_stat(USB_EP0, USB_EP_STAT_TX_STALL); + usb_set_ep_rx_addr(USB_EP0, USB_EP0_RX_BUFFER_ADDRESS); + usb_set_ep_tx_addr(USB_EP0, USB_EP0_TX_BUFFER_ADDRESS); + usb_clear_status_out(USB_EP0); + + usb_set_ep_rx_count(USB_EP0, USB_EP0_BUFFER_SIZE); + usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID); + + for (unsigned i = 0 ; i < numParts ; i++) { + for (unsigned j = 0 ; j < parts[i]->numEndpoints ; j++) { + USBEndpointInfo* e = &(parts[i]->endpoints[j]); + uint8 address = e->address; + usb_set_ep_type(address, e->type); + if (parts[i]->endpoints[j].tx) { + usb_set_ep_tx_addr(address, e->pmaAddress); + usb_set_ep_tx_stat(address, USB_EP_STAT_TX_NAK); + usb_set_ep_rx_stat(address, USB_EP_STAT_RX_DISABLED); + } + else { + usb_set_ep_rx_addr(address, e->pmaAddress); + usb_set_ep_rx_count(address, e->bufferSize); + usb_set_ep_rx_stat(address, USB_EP_STAT_RX_VALID); + } + } + if (parts[i]->usbReset != NULL) + parts[i]->usbReset(); + } + + usbGenericTransmitting = -1; + + USBLIB->state = USB_ATTACHED; + SetDeviceAddress(0); + +} + +static void usb_power_down(void) { + USB_BASE->CNTR = USB_CNTR_FRES; + USB_BASE->ISTR = 0; + USB_BASE->CNTR = USB_CNTR_FRES + USB_CNTR_PDWN; +} + +void usb_generic_disable(void) { + /* Turn off the interrupt and signal disconnect (see e.g. USB 2.0 + * spec, section 7.1.7.3). */ + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); + + if (BOARD_USB_DISC_DEV != NULL) { + gpio_write_bit(BOARD_USB_DISC_DEV, (uint8)(uint32)BOARD_USB_DISC_BIT, 1); + } + + usb_power_down(); + + Device_Table = saved_Device_Table; + Device_Property = saved_Device_Property; + User_Standard_Requests = saved_User_Standard_Requests; +} + +static RESULT usbDataSetup(uint8 request) { + uint8* (*CopyRoutine)(uint16) = 0; + + if(Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT) && request == GET_DESCRIPTOR && + pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE){ + CopyRoutine = usbGetConfigDescriptor; + } + + if (CopyRoutine == NULL){ + for (unsigned i = 0 ; i < numParts ; i++) { + RESULT r = parts[i]->usbDataSetup(request); + if (USB_UNSUPPORT != r) + return r; + } + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +static RESULT usbNoDataSetup(uint8 request) { + for (unsigned i = 0 ; i < numParts ; i++) { + RESULT r = parts[i]->usbNoDataSetup(request); + if (USB_UNSUPPORT != r) + return r; + } + + return USB_UNSUPPORT; +} + +static void usbSetConfiguration(void) { + if (pInformation->Current_Configuration != 0) { + USBLIB->state = USB_CONFIGURED; + } + for (unsigned i = 0 ; i < numParts ; i++) { + if (parts[i]->usbSetConfiguration != NULL) + parts[i]->usbSetConfiguration(); + } +} + +static void usbClearFeature(void) { + for (unsigned i = 0 ; i < numParts ; i++) { + if (parts[i]->usbClearFeature != NULL) + parts[i]->usbClearFeature(); + } +} + +static void usbSetDeviceAddress(void) { + USBLIB->state = USB_ADDRESSED; +} + +static uint8* usbGetDeviceDescriptor(uint16 length) { + return Standard_GetDescriptorData(length, &Device_Descriptor); +} + +static uint8* usbGetConfigDescriptor(uint16 length) { + return Standard_GetDescriptorData(length, &Config_Descriptor); +} + +static uint8* usbGetStringDescriptor(uint16 length) { + uint8 wValue0 = pInformation->USBwValue0; + + if (wValue0 >= numStringDescriptors) { + return NULL; + } + return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]); +} + + +static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) { + if (alt_setting > 0) { + return USB_UNSUPPORT; + } else if (interface >= usbConfig.Config_Header.bNumInterfaces) { + return USB_UNSUPPORT; + } + + return USB_SUCCESS; +} + +void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset) { + uint16 *dst = (uint16*)usb_pma_ptr(pma_offset); + uint16 n = len >> 1; + uint16 i; + for (i = 0; i < n; i++) { + *dst = (uint16)(*buf) | *(buf + 1) << 8; + buf += 2; + dst += 2; + } + if (len & 1) { + *dst = *buf; + } +} + +void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset) { + uint32 *src = (uint32*)usb_pma_ptr(pma_offset); + uint16 *dst = (uint16*)buf; + uint16 n = len >> 1; + uint16 i; + for (i = 0; i < n; i++) { + *dst++ = *src++; + } + if (len & 1) { + *dst = *src & 0xFF; + } +} + diff --git a/STM32F1/libraries/USBComposite/usb_generic.h b/STM32F1/libraries/USBComposite/usb_generic.h new file mode 100644 index 0000000..d665d8f --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_generic.h @@ -0,0 +1,60 @@ +#ifndef _USB_GENERIC_H +#define _USB_GENERIC_H +#include +typedef unsigned short u16; +typedef unsigned char u8; +#include +#include + +#define PMA_MEMORY_SIZE 512 +#define MAX_USB_DESCRIPTOR_DATA_SIZE 200 + +#define USB_EP0_BUFFER_SIZE 0x40 +#define USB_EP0_TX_BUFFER_ADDRESS 0x40 +#define USB_EP0_RX_BUFFER_ADDRESS (USB_EP0_TX_BUFFER_ADDRESS+USB_EP0_BUFFER_SIZE) + +#ifdef __cplusplus +extern "C" { +#endif + +extern const usb_descriptor_string usb_generic_default_iManufacturer; +extern const usb_descriptor_string usb_generic_default_iProduct; + +typedef struct USBEndpointInfo { + void (*callback)(void); + uint16 bufferSize; + uint16 type; // bulk, interrupt, etc. + uint8 tx; // 1 if TX, 0 if RX + uint8 address; + uint16 pmaAddress; +} USBEndpointInfo; + +typedef struct USBCompositePart { + uint8 numInterfaces; + uint8 numEndpoints; + uint8 startInterface; + uint8 startEndpoint; + uint16 descriptorSize; + void (*getPartDescriptor)(uint8* out); + void (*usbInit)(void); + void (*usbReset)(void); + void (*usbSetConfiguration)(void); + void (*usbClearFeature)(void); + RESULT (*usbDataSetup)(uint8 request); + RESULT (*usbNoDataSetup)(uint8 request); + USBEndpointInfo* endpoints; +} USBCompositePart; + +void usb_generic_set_info(uint16 idVendor, uint16 idProduct, const uint8* iManufacturer, const uint8* iProduct, const uint8* iSerialNumber); +uint8 usb_generic_set_parts(USBCompositePart** _parts, unsigned _numParts); +void usb_generic_disable(void); +void usb_generic_enable(void); +extern volatile int8 usbGenericTransmitting; +void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset); +void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_hid.c b/STM32F1/libraries/USBComposite/usb_hid.c new file mode 100644 index 0000000..162cd4a --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_hid.c @@ -0,0 +1,578 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usb/stm32f1/usb_hid.c + * @brief USB HID (human interface device) support + * + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. + */ + +#include "usb_hid.h" +#include +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" + +uint16 GetEPTxAddr(uint8 /*bEpNum*/); + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +static uint32 ProtocolValue = 0; + +static void hidDataTxCb(void); +static void hidUSBReset(void); +static RESULT hidUSBDataSetup(uint8 request); +static RESULT hidUSBNoDataSetup(uint8 request); +//static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting); +static uint8* HID_GetReportDescriptor(uint16 Length); +static uint8* HID_GetProtocolValue(uint16 Length); + +static volatile HIDBuffer_t hidBuffers[MAX_HID_BUFFERS] = {{ 0 }}; +static volatile HIDBuffer_t* currentHIDBuffer = NULL; + +//#define DUMMY_BUFFER_SIZE 0x40 // at least as big as a buffer size + +#define HID_INTERFACE_OFFSET 0x00 +#define NUM_HID_ENDPOINTS 1 +#define HID_INTERFACE_NUMBER (HID_INTERFACE_OFFSET+usbHIDPart.startInterface) + +/* + * Descriptors + */ + +static ONE_DESCRIPTOR HID_Report_Descriptor = { + (uint8*)NULL, + 0 +}; + + +#define HID_ENDPOINT_TX 0 + +typedef struct { + //HID + usb_descriptor_interface HID_Interface; + HIDDescriptor HID_Descriptor; + usb_descriptor_endpoint HIDDataInEndpoint; +} __packed hid_part_config; + +static const hid_part_config hidPartConfigData = { + .HID_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = HID_INTERFACE_OFFSET, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = NUM_HID_ENDPOINTS, + .bInterfaceClass = USB_INTERFACE_CLASS_HID, + .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_HID, + .bInterfaceProtocol = 0x00, /* Common AT Commands */ + .iInterface = 0x00, + }, + .HID_Descriptor = { + .len = 9,//sizeof(HIDDescDescriptor), + .dtype = HID_DESCRIPTOR_TYPE, + .versionL = 0x10, + .versionH = 0x01, + .country = 0x00, + .numDesc = 0x01, + .desctype = REPORT_DESCRIPTOR,//0x22, + .descLenL = 0x00, //PATCH + .descLenH = 0x00, //PATCH + }, + .HIDDataInEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = USB_DESCRIPTOR_ENDPOINT_IN | HID_ENDPOINT_TX, // PATCH + .bmAttributes = USB_ENDPOINT_TYPE_INTERRUPT, + .wMaxPacketSize = USB_HID_TX_EPSIZE,//0x40,//big enough for a keyboard 9 byte packet and for a mouse 5 byte packet + .bInterval = 0x0A, + } +}; + +static USBEndpointInfo hidEndpoints[1] = { + { + .callback = hidDataTxCb, + .bufferSize = USB_HID_TX_EPSIZE, + .type = USB_EP_EP_TYPE_INTERRUPT, // TODO: interrupt??? + .tx = 1, + } +}; + +#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s] + +static void getHIDPartDescriptor(uint8* out) { + memcpy(out, &hidPartConfigData, sizeof(hid_part_config)); + // patch to reflect where the part goes in the descriptor + OUT_BYTE(hidPartConfigData, HID_Interface.bInterfaceNumber) += usbHIDPart.startInterface; + OUT_BYTE(hidPartConfigData, HIDDataInEndpoint.bEndpointAddress) += usbHIDPart.startEndpoint; + OUT_BYTE(hidPartConfigData, HID_Descriptor.descLenL) = (uint8)HID_Report_Descriptor.Descriptor_Size; + OUT_BYTE(hidPartConfigData, HID_Descriptor.descLenH) = (uint8)(HID_Report_Descriptor.Descriptor_Size>>8); +} + +USBCompositePart usbHIDPart = { + .numInterfaces = 1, + .numEndpoints = sizeof(hidEndpoints)/sizeof(*hidEndpoints), + .descriptorSize = sizeof(hid_part_config), + .getPartDescriptor = getHIDPartDescriptor, + .usbInit = NULL, + .usbReset = hidUSBReset, + .usbDataSetup = hidUSBDataSetup, + .usbNoDataSetup = hidUSBNoDataSetup, + .usbClearFeature = NULL, + .usbSetConfiguration = NULL, + .endpoints = hidEndpoints +}; + + +#define HID_TX_BUFFER_SIZE 256 // must be power of 2 +#define HID_TX_BUFFER_SIZE_MASK (HID_TX_BUFFER_SIZE-1) +// Tx data +static volatile uint8 hidBufferTx[HID_TX_BUFFER_SIZE]; +// Write index to hidBufferTx +static volatile uint32 hid_tx_head = 0; +// Read index from hidBufferTx +static volatile uint32 hid_tx_tail = 0; + +#define CDC_SERIAL_RX_BUFFER_SIZE 256 // must be power of 2 +#define CDC_SERIAL_RX_BUFFER_SIZE_MASK (CDC_SERIAL_RX_BUFFER_SIZE-1) + + + + +void usb_hid_putc(char ch) { + while (!usb_hid_tx((uint8*)&ch, 1)) + ; +} + + /* +static void hidStatusIn() { + if (pInformation->ControlState == WAIT_STATUS_IN) { + if (currentInFeature >= 0) { + if (featureBuffers[currentInFeature].bufferSize == featureBuffers[currentInFeature].currentDataSize) + featureBuffers[currentInFeature].state = HID_BUFFER_UNREAD; + currentInFeature = -1; + } + if (currentOutput >= 0) { + if (outputBuffers[currentOutput].bufferSize == outputBuffers[currentOutput].currentDataSize) + outputBuffers[currentOutput].state = HID_BUFFER_UNREAD; + currentOutput = -1; + } + } +} + */ + +void usb_hid_set_report_descriptor(const uint8* report_descriptor, uint16 report_descriptor_length) { + HID_Report_Descriptor.Descriptor = (uint8*)report_descriptor; + HID_Report_Descriptor.Descriptor_Size = report_descriptor_length; +} + + +static volatile HIDBuffer_t* usb_hid_find_buffer(uint8 type, uint8 reportID) { + uint8 typeTest = type == HID_REPORT_TYPE_OUTPUT ? HID_BUFFER_MODE_OUTPUT : 0; + for (int i=0; ibuffer+delta, data, buffer->bufferSize-delta); + if (reportID) + buffer->buffer[0] = reportID; + buffer->currentDataSize = buffer->bufferSize; + buffer->state = HID_BUFFER_READ; + usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID); + return; + } +} + +static uint8 have_unread_data_in_hid_buffer() { + for (int i=0;ireportID == reportID && buffer->state != HID_BUFFER_EMPTY && !(poll && buffer->state == HID_BUFFER_READ)) { + if (buffer->bufferSize != buffer->currentDataSize) { + buffer->state = HID_BUFFER_EMPTY; + ret = 0; + } + else { + unsigned delta = reportID != 0; + if (out != NULL) + memcpy(out, (uint8*)buffer->buffer+delta, buffer->bufferSize-delta); + + if (poll) { + buffer->state = HID_BUFFER_READ; + } + + ret = buffer->bufferSize-delta; + } + } + + if (! have_unread_data_in_hid_buffer() ) { + usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID); + } + + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + + return ret; +} + +void usb_hid_clear_buffers(uint8 type) { + uint8 typeTest = type == HID_REPORT_TYPE_OUTPUT ? HID_BUFFER_MODE_OUTPUT : 0; + for (int i=0; imode |= HID_BUFFER_MODE_OUTPUT; + else + buf->mode &= ~HID_BUFFER_MODE_OUTPUT; + memset((void*)buf->buffer, 0, buf->bufferSize); + buf->buffer[0] = buf->reportID; + + volatile HIDBuffer_t* buffer = usb_hid_find_buffer(type, buf->reportID); + + if (buffer != NULL) { + *buffer = *buf; + return 1; + } + else { + for (int i=0; i (HID_TX_BUFFER_SIZE-tx_unsent-1) ) { + len = (HID_TX_BUFFER_SIZE-tx_unsent-1); + } + if (len==0) return 0; // buffer full + + uint16 i; + // copy data from user buffer to USB Tx buffer + for (i=0; i= 0); + + if (usbGenericTransmitting<0) { + hidDataTxCb(); // initiate data transmission + } + + return len; +} + + + +uint16 usb_hid_get_pending(void) { + return (hid_tx_head - hid_tx_tail) & HID_TX_BUFFER_SIZE_MASK; +} + +static void hidDataTxCb(void) +{ + uint32 tail = hid_tx_tail; // load volatile variable + uint32 tx_unsent = (hid_tx_head - tail) & HID_TX_BUFFER_SIZE_MASK; + if (tx_unsent==0) { + if ( (--usbGenericTransmitting)==0) goto flush_hid; // no more data to send + return; // it was already flushed, keep Tx endpoint disabled + } + usbGenericTransmitting = 1; + // We can only send up to USBHID_CDCACM_TX_EPSIZE bytes in the endpoint. + if (tx_unsent > USB_HID_TX_EPSIZE) { + tx_unsent = USB_HID_TX_EPSIZE; + } + // copy the bytes from USB Tx buffer to PMA buffer + uint32 *dst = usb_pma_ptr(usbHIDPart.endpoints[HID_ENDPOINT_TX].pmaAddress); + uint16 tmp = 0; + uint16 val; + unsigned i; + for (i = 0; i < tx_unsent; i++) { + val = hidBufferTx[tail]; + tail = (tail + 1) & HID_TX_BUFFER_SIZE_MASK; + if (i&1) { + *dst++ = tmp | (val<<8); + } else { + tmp = val; + } + } + if ( tx_unsent&1 ) { + *dst = tmp; + } + hid_tx_tail = tail; // store volatile variable + +flush_hid: + // enable Tx endpoint + usb_set_ep_tx_count(usbHIDPart.endpoints[HID_ENDPOINT_TX].address, tx_unsent); + usb_set_ep_tx_stat(usbHIDPart.endpoints[HID_ENDPOINT_TX].address, USB_EP_STAT_TX_VALID); +} + + + +static void hidUSBReset(void) { + /* Reset the RX/TX state */ + hid_tx_head = 0; + hid_tx_tail = 0; + + currentHIDBuffer = NULL; +} + +static uint8* HID_Set(uint16 length) { + if (currentHIDBuffer == NULL) + return NULL; + + if (length ==0) { + if ( (0 == (currentHIDBuffer->mode & HID_BUFFER_MODE_NO_WAIT)) && + currentHIDBuffer->state == HID_BUFFER_UNREAD && + pInformation->Ctrl_Info.Usb_wOffset < pInformation->USBwLengths.w) { + pInformation->Ctrl_Info.Usb_wLength = 0xFFFF; + return NULL; + } + + uint16 len = pInformation->USBwLengths.w; + if (len > currentHIDBuffer->bufferSize) + len = currentHIDBuffer->bufferSize; + + currentHIDBuffer->currentDataSize = len; + + currentHIDBuffer->state = HID_BUFFER_EMPTY; + + if (pInformation->Ctrl_Info.Usb_wOffset < len) { + pInformation->Ctrl_Info.Usb_wLength = len - pInformation->Ctrl_Info.Usb_wOffset; + } + else { + pInformation->Ctrl_Info.Usb_wLength = 0; + } + + return NULL; + } + + if (pInformation->USBwLengths.w <= pInformation->Ctrl_Info.Usb_wOffset + pInformation->Ctrl_Info.PacketSize) { + currentHIDBuffer->state = HID_BUFFER_UNREAD; + } + + return (uint8*)currentHIDBuffer->buffer + pInformation->Ctrl_Info.Usb_wOffset; +} + +static uint8* HID_GetFeature(uint16 length) { + if (currentHIDBuffer == NULL) + return NULL; + + unsigned wOffset = pInformation->Ctrl_Info.Usb_wOffset; + + if (length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = currentHIDBuffer->bufferSize - wOffset; + return NULL; + } + + return (uint8*)currentHIDBuffer->buffer + wOffset; +} + +static RESULT hidUSBDataSetup(uint8 request) { + uint8* (*CopyRoutine)(uint16) = 0; + + if (pInformation->USBwIndex0 != HID_INTERFACE_NUMBER) + return USB_UNSUPPORT; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + switch (request) { + case SET_REPORT: + if (pInformation->USBwValue1 == HID_REPORT_TYPE_FEATURE) { + volatile HIDBuffer_t* buffer = usb_hid_find_buffer(HID_REPORT_TYPE_FEATURE, pInformation->USBwValue0); + + if (buffer == NULL) { + return USB_UNSUPPORT; + } + + if (0 == (buffer->mode & HID_BUFFER_MODE_NO_WAIT) && buffer->state == HID_BUFFER_UNREAD) { + return USB_NOT_READY; + } + else + { + currentHIDBuffer = buffer; + CopyRoutine = HID_Set; + } + } + else if (pInformation->USBwValue1 == HID_REPORT_TYPE_OUTPUT) { + volatile HIDBuffer_t* buffer = usb_hid_find_buffer(HID_REPORT_TYPE_OUTPUT, pInformation->USBwValue0); + + if (buffer == NULL) { + return USB_UNSUPPORT; + } + + if (0 == (buffer->mode & HID_BUFFER_MODE_NO_WAIT) && buffer->state == HID_BUFFER_UNREAD) { + return USB_NOT_READY; + } + else + { + currentHIDBuffer = buffer; + CopyRoutine = HID_Set; + } + } + break; + case GET_REPORT: + if (pInformation->USBwValue1 == HID_REPORT_TYPE_FEATURE) { + volatile HIDBuffer_t* buffer = usb_hid_find_buffer(HID_REPORT_TYPE_FEATURE, pInformation->USBwValue0); + + if (buffer == NULL || buffer->state == HID_BUFFER_EMPTY) { + return USB_UNSUPPORT; + } + + currentHIDBuffer = buffer; + CopyRoutine = HID_GetFeature; + break; + } + default: + break; + } + } + + if(Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)){ + switch (request){ + case GET_DESCRIPTOR: + if (pInformation->USBwValue1 == REPORT_DESCRIPTOR){ + CopyRoutine = HID_GetReportDescriptor; + } + break; + case GET_PROTOCOL: // TODO: check for interface number? + CopyRoutine = HID_GetProtocolValue; + break; + } + } + + if (CopyRoutine == NULL){ + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +static RESULT hidUSBNoDataSetup(uint8 request) { + if (pInformation->USBwIndex0 != HID_INTERFACE_NUMBER) + return USB_UNSUPPORT; + + RESULT ret = USB_UNSUPPORT; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + switch(request) { + case SET_PROTOCOL: + ProtocolValue = pInformation->USBwValue0; + ret = USB_SUCCESS; + break; + } + } + return ret; +} + +/* +static RESULT HID_SetProtocol(void){ + uint8 wValue0 = pInformation->USBwValue0; + ProtocolValue = wValue0; + return USB_SUCCESS; +} +*/ +static uint8* HID_GetProtocolValue(uint16 Length){ + if (Length == 0){ + pInformation->Ctrl_Info.Usb_wLength = 1; + return NULL; + } else { + return (uint8 *)(&ProtocolValue); + } +} + +static uint8* HID_GetReportDescriptor(uint16 Length){ + return Standard_GetDescriptorData(Length, &HID_Report_Descriptor); +} + diff --git a/STM32F1/libraries/USBComposite/usb_hid.h b/STM32F1/libraries/USBComposite/usb_hid.h new file mode 100644 index 0000000..856fd3e --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_hid.h @@ -0,0 +1,153 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/usb_device.h + * @brief USB Composite with CDC ACM and HID support + * + * IMPORTANT: this API is unstable, and may change without notice. + */ + +#ifndef _USB_HID_H_ +#define _USB_HID_H_ + +#include +#include +#include "usb_generic.h" + +#define MAX_HID_BUFFERS 8 +#define HID_BUFFER_SIZE(n,reportID) ((n)+((reportID)!=0)) +#define HID_BUFFER_ALLOCATE_SIZE(n,reportID) ((HID_BUFFER_SIZE((n),(reportID))+1)/2*2) + +#define HID_BUFFER_MODE_NO_WAIT 1 +#define HID_BUFFER_MODE_OUTPUT 2 + +#define HID_BUFFER_EMPTY 0 +#define HID_BUFFER_UNREAD 1 +#define HID_BUFFER_READ 2 + +extern USBCompositePart usbHIDPart; + +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 + uint8_t reportID; + uint8_t mode; + uint16_t currentDataSize; + uint8_t state; // HID_BUFFER_EMPTY, etc. +#ifdef __cplusplus + inline HIDBuffer_t(volatile uint8_t* _buffer=NULL, uint16_t _bufferSize=0, uint8_t _reportID=0, uint8_t _mode=0) { + reportID = _reportID; + buffer = _buffer; + bufferSize = _bufferSize; + mode = _mode; + } +#endif +} HIDBuffer_t; + +#ifdef __cplusplus +extern "C" { +#endif + +#define USB_HID_TX_EPSIZE 0x40 + +void usb_hid_set_report_descriptor(const uint8* report_descriptor, uint16 report_descriptor_length); +void usb_hid_clear_buffers(uint8_t type); +uint8_t usb_hid_add_buffer(uint8_t type, volatile HIDBuffer_t* buf); +void usb_hid_set_buffers(uint8_t type, volatile HIDBuffer_t* featureBuffers, int count); +uint16_t usb_hid_get_data(uint8_t type, uint8_t reportID, uint8_t* out, uint8_t poll); +void usb_hid_set_feature(uint8_t reportID, uint8_t* data); + + + +/* + * HID Requests + */ + +typedef enum _HID_REQUESTS +{ + + GET_REPORT = 1, + GET_IDLE, + GET_PROTOCOL, + + SET_REPORT = 9, + SET_IDLE, + SET_PROTOCOL + +} HID_REQUESTS; + +#define HID_REPORT_TYPE_INPUT 0x01 +#define HID_REPORT_TYPE_OUTPUT 0x02 +#define HID_REPORT_TYPE_FEATURE 0x03 + + +/* + * HID Descriptors, etc. + */ + +#define HID_ENDPOINT_INT 1 + +#define HID_DESCRIPTOR_TYPE 0x21 +#define REPORT_DESCRIPTOR 0x22 + + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 0x21 + uint8_t versionL; // 0x101 + uint8_t versionH; // 0x101 + uint8_t country; + uint8_t numDesc; + uint8_t desctype; // 0x22 report + uint8_t descLenL; + uint8_t descLenH; +} HIDDescriptor; + + +#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 + +#define USB_INTERFACE_CLASS_HID 0x03 +#define USB_INTERFACE_SUBCLASS_HID 0x01 + + /* + * HID interface + */ + +void usb_hid_putc(char ch); +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 */ +uint16 usb_hid_get_pending(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_mass.c b/STM32F1/libraries/USBComposite/usb_mass.c new file mode 100644 index 0000000..5ef053e --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_mass.c @@ -0,0 +1,464 @@ +#include + +#include "usb_generic.h" +#include "usb_mass.h" +#include "usb_scsi.h" +#include "usb_mass_internal.h" + +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" +#include "usb_regs.h" + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +static void usb_mass_bot_cbw_decode(); + +static void usb_mass_set_configuration(); +static void usb_mass_clear_feature(); +static RESULT usb_mass_data_setup(uint8 request); +static RESULT usb_mass_no_data_setup(uint8 request); +static void usb_mass_reset(); +static uint8_t* usb_mass_get_max_lun(uint16_t Length); +static void usb_mass_in(void); +static void usb_mass_out(void); +uint32_t usb_mass_sil_write(uint8_t* pBufferPointer, uint32_t wBufferSize); +uint32_t usb_mass_sil_read(uint8_t* pBufferPointer); + +#define MASS_INTERFACE_OFFSET 0x00 +#define MASS_INTERFACE_NUMBER (MASS_INTERFACE_OFFSET+usbMassPart.startInterface) + + +#define LUN_DATA_LENGTH 1 + +static uint32_t maxLun = 0; +static uint32_t deviceState = DEVICE_STATE_UNCONNECTED; +uint8_t usb_mass_botState = BOT_STATE_IDLE; +BulkOnlyCBW usb_mass_CBW; +BulkOnlyCSW usb_mass_CSW; +uint8_t usb_mass_bulkDataBuff[MAX_BULK_PACKET_SIZE]; +uint16_t usb_mass_dataLength; +static uint8_t inRequestPending; +static uint8_t outRequestPending; + +typedef struct mass_descriptor_config { +// usb_descriptor_config_header Config_Header; + usb_descriptor_interface MASS_Interface; + usb_descriptor_endpoint DataInEndpoint; + usb_descriptor_endpoint DataOutEndpoint; +} __packed mass_descriptor_config; + + +#define MAX_POWER (500 >> 1) +const mass_descriptor_config usbMassConfigDescriptor = { + /*.Config_Header = + { + .bLength = sizeof (usb_descriptor_config_header), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = sizeof (usb_descriptor_config), + .bNumInterfaces = 0x01, + .bConfigurationValue = 0x01, + .iConfiguration = 0x00, + .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED), + .bMaxPower = MAX_POWER, + }, */ + + .MASS_Interface = + { + .bLength = sizeof (usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = 0x00, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = 8, // mass storage + .bInterfaceSubClass = 6, // SCSI + .bInterfaceProtocol = 0x50, // Bulk-Only + .iInterface = 0, + }, + + .DataInEndpoint = + { + .bLength = sizeof (usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | MASS_ENDPOINT_TX), // PATCH + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = MAX_BULK_PACKET_SIZE, + .bInterval = 0, + }, + + .DataOutEndpoint = + { + .bLength = sizeof (usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | MASS_ENDPOINT_RX), // PATCH + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = MAX_BULK_PACKET_SIZE, + .bInterval = 1, + } +}; + +USBEndpointInfo usbMassEndpoints[2] = { + { + .callback = usb_mass_in, + .bufferSize = MAX_BULK_PACKET_SIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 1, + }, + { + .callback = usb_mass_out, + .bufferSize = MAX_BULK_PACKET_SIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 0, + }, +}; + +#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s] + +static void getMassPartDescriptor(uint8* out) { + memcpy(out, &usbMassConfigDescriptor, sizeof(mass_descriptor_config)); + // patch to reflect where the part goes in the descriptor + OUT_BYTE(usbMassConfigDescriptor, MASS_Interface.bInterfaceNumber) += usbMassPart.startInterface; + OUT_BYTE(usbMassConfigDescriptor, DataInEndpoint.bEndpointAddress) += usbMassPart.startEndpoint; + OUT_BYTE(usbMassConfigDescriptor, DataOutEndpoint.bEndpointAddress) += usbMassPart.startEndpoint; +} + + + +USBCompositePart usbMassPart = { + .numInterfaces = 1, + .numEndpoints = sizeof(usbMassEndpoints)/sizeof(*usbMassEndpoints), + .descriptorSize = sizeof(mass_descriptor_config), + .getPartDescriptor = getMassPartDescriptor, + .usbInit = NULL, + .usbReset = usb_mass_reset, + .usbDataSetup = usb_mass_data_setup, + .usbNoDataSetup = usb_mass_no_data_setup, + .usbClearFeature = usb_mass_clear_feature, + .usbSetConfiguration = usb_mass_set_configuration, + .endpoints = usbMassEndpoints +}; + +static void usb_mass_reset(void) { + usb_mass_mal_init(0); + + pInformation->Current_Configuration = 0; // TODO: remove? + + /* current feature is current bmAttributes */ + pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED); // usbMassConfigDescriptor.Config_Header.bmAttributes; // TODO: remove? + + deviceState = DEVICE_STATE_ATTACHED; + usb_mass_CBW.dSignature = BOT_CBW_SIGNATURE; + usb_mass_botState = BOT_STATE_IDLE; +} + +static void usb_mass_set_configuration(void) { + if (pInformation->Current_Configuration != 0) { + deviceState = USB_CONFIGURED; + ClearDTOG_TX(USB_MASS_TX_ENDP); + ClearDTOG_RX(USB_MASS_RX_ENDP); + usb_mass_botState = BOT_STATE_IDLE; + } +} + +static void usb_mass_clear_feature(void) { + /* when the host send a usb_mass_CBW with invalid signature or invalid length the two + Endpoints (IN & OUT) shall stall until receiving a Mass Storage Reset */ + if (usb_mass_CBW.dSignature != BOT_CBW_SIGNATURE) { + usb_mass_bot_abort(BOT_DIR_BOTH); + } +} + +static RESULT usb_mass_data_setup(uint8 request) { + uint8_t * (*copy_routine)(uint16_t); + + copy_routine = NULL; + if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + && (request == REQUEST_GET_MAX_LUN) && (pInformation->USBwValue == 0) + && (pInformation->USBwIndex == MASS_INTERFACE_NUMBER) && (pInformation->USBwLength == 0x01)) { + copy_routine = usb_mass_get_max_lun; + } else { + return USB_UNSUPPORT; + } + + if (copy_routine == NULL) { + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = copy_routine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*copy_routine)(0); + + return USB_SUCCESS; +} + +static uint8_t* usb_mass_get_max_lun(uint16_t length) { + if (length == 0) { + pInformation->Ctrl_Info.Usb_wLength = LUN_DATA_LENGTH; + return 0; + } else { + return ((uint8_t*) (&maxLun)); + } +} + +static RESULT usb_mass_no_data_setup(uint8 request) { + if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + && (request == REQUEST_MASS_STORAGE_RESET) && (pInformation->USBwValue == 0) + && (pInformation->USBwIndex == MASS_INTERFACE_NUMBER) && (pInformation->USBwLength == 0x00)) { + + /* Initialize Endpoint 1 */ + ClearDTOG_TX(USB_MASS_TX_ENDP); + + /* Initialize Endpoint 2 */ + ClearDTOG_RX(USB_MASS_RX_ENDP); + + /*initialize the usb_mass_CBW signature to enable the clear feature*/ + usb_mass_CBW.dSignature = BOT_CBW_SIGNATURE; + usb_mass_botState = BOT_STATE_IDLE; + + return USB_SUCCESS; + } + return USB_UNSUPPORT; +} + + +void usb_mass_loop() { + if (inRequestPending) { + inRequestPending = 0; + + switch (usb_mass_botState) { + case BOT_STATE_CSW_Send: + case BOT_STATE_ERROR: + usb_mass_botState = BOT_STATE_IDLE; + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL); /* enable the Endpoint to receive the next cmd*/ + break; + case BOT_STATE_DATA_IN: + switch (usb_mass_CBW.CB[0]) { + case SCSI_READ10: + scsi_read10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen); + break; + } + break; + case BOT_STATE_DATA_IN_LAST: + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL); + break; + + default: + break; + } + } + + if (outRequestPending) { + outRequestPending = 0; + + uint8_t CMD; + CMD = usb_mass_CBW.CB[0]; + + switch (usb_mass_botState) { + case BOT_STATE_IDLE: + usb_mass_bot_cbw_decode(); + break; + case BOT_STATE_DATA_OUT: + if (CMD == SCSI_WRITE10) { + scsi_write10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen); + break; + } + usb_mass_bot_abort(BOT_DIR_OUT); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_PHASE_ERROR, BOT_SEND_CSW_DISABLE); + break; + default: + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_PHASE_ERROR, BOT_SEND_CSW_DISABLE); + break; + } + } +} + +/* + * IN + */ +static void usb_mass_in(void) { + inRequestPending = 1; +} + +/* + * OUT + */ +static void usb_mass_out(void) { + usb_mass_dataLength = usb_mass_sil_read(usb_mass_bulkDataBuff); + outRequestPending = 1; +} + +static void usb_mass_bot_cbw_decode() { + uint32_t counter; + + for (counter = 0; counter < usb_mass_dataLength; counter++) { + *((uint8_t *) & usb_mass_CBW + counter) = usb_mass_bulkDataBuff[counter]; + } + usb_mass_CSW.dTag = usb_mass_CBW.dTag; + usb_mass_CSW.dDataResidue = usb_mass_CBW.dDataLength; + if (usb_mass_dataLength != BOT_CBW_PACKET_LENGTH) { + usb_mass_bot_abort(BOT_DIR_BOTH); + /* reset the usb_mass_CBW.dSignature to disable the clear feature until receiving a Mass storage reset*/ + usb_mass_CBW.dSignature = 0; + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_PARAMETER_LIST_LENGTH_ERROR); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + return; + } + + if ((usb_mass_CBW.CB[0] == SCSI_READ10) || (usb_mass_CBW.CB[0] == SCSI_WRITE10)) { + /* Calculate Logical Block Address */ + SCSI_lba = (usb_mass_CBW.CB[2] << 24) | (usb_mass_CBW.CB[3] << 16) | (usb_mass_CBW.CB[4] << 8) | usb_mass_CBW.CB[5]; + /* Calculate the Number of Blocks to transfer */ + SCSI_blkLen = (usb_mass_CBW.CB[7] << 8) | usb_mass_CBW.CB[8]; + } + + if (usb_mass_CBW.dSignature == BOT_CBW_SIGNATURE) { + /* Valid usb_mass_CBW */ + if ((usb_mass_CBW.bLUN > maxLun) || (usb_mass_CBW.bCBLength < 1) || (usb_mass_CBW.bCBLength > 16)) { + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + } else { + switch (usb_mass_CBW.CB[0]) { + case SCSI_REQUEST_SENSE: + scsi_request_sense_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_INQUIRY: + scsi_inquiry_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_START_STOP_UNIT: + scsi_start_stop_unit_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_ALLOW_MEDIUM_REMOVAL: + scsi_start_stop_unit_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_MODE_SENSE6: + scsi_mode_sense6_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_MODE_SENSE10: + scsi_mode_sense10_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_READ_FORMAT_CAPACITIES: + scsi_read_format_capacity_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_READ_CAPACITY10: + scsi_read_capacity10_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_TEST_UNIT_READY: + scsi_test_unit_ready_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_READ10: + scsi_read10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen); + break; + case SCSI_WRITE10: + scsi_write10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen); + break; + case SCSI_VERIFY10: + scsi_verify10_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_FORMAT_UNIT: + scsi_format_cmd(usb_mass_CBW.bLUN); + break; + + case SCSI_MODE_SELECT10: + case SCSI_MODE_SELECT6: + case SCSI_SEND_DIAGNOSTIC: + case SCSI_READ6: + case SCSI_READ12: + case SCSI_READ16: + case SCSI_READ_CAPACITY16: + case SCSI_WRITE6: + case SCSI_WRITE12: + case SCSI_VERIFY12: + case SCSI_VERIFY16: + case SCSI_WRITE16: + scsi_invalid_cmd(usb_mass_CBW.bLUN); + break; + + default: + { + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + } + } + } + } else { + /* Invalid usb_mass_CBW */ + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + } +} + +void usb_mass_bot_abort(uint8_t direction) { + switch (direction) { + case BOT_DIR_IN: + SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_STL); + break; + case BOT_DIR_OUT: + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_STL); + break; + case BOT_DIR_BOTH: + SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_STL); + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_STL); + break; + default: + break; + } +} + +void usb_mass_transfer_data_request(uint8_t* dataPointer, uint16_t dataLen) { + usb_mass_sil_write(dataPointer, dataLen); + + SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_VAL); + usb_mass_botState = BOT_STATE_DATA_IN_LAST; + usb_mass_CSW.dDataResidue -= dataLen; + usb_mass_CSW.bStatus = BOT_CSW_CMD_PASSED; +} + +void usb_mass_bot_set_csw(uint8_t status, uint8_t sendPermission) { + usb_mass_CSW.dSignature = BOT_CSW_SIGNATURE; + usb_mass_CSW.bStatus = status; + + usb_mass_sil_write(((uint8_t *) & usb_mass_CSW), BOT_CSW_DATA_LENGTH); + + usb_mass_botState = BOT_STATE_ERROR; + if (sendPermission) { + usb_mass_botState = BOT_STATE_CSW_Send; + SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_VAL); + } +} + +uint32_t usb_mass_sil_write(uint8_t* pBufferPointer, uint32_t wBufferSize) { + /* Use the memory interface function to write to the selected endpoint */ + usb_copy_to_pma(pBufferPointer, wBufferSize, USB_MASS_TX_ADDR); + + /* Update the data length in the control register */ + SetEPTxCount(USB_MASS_TX_ENDP, wBufferSize); + + return 0; +} + +uint32_t usb_mass_sil_read(uint8_t* pBufferPointer) { + uint32_t usb_mass_dataLength = 0; + + /* Get the number of received data on the selected Endpoint */ + usb_mass_dataLength = GetEPRxCount(USB_MASS_RX_ENDP); + + /* Use the memory interface function to write to the selected endpoint */ + usb_copy_from_pma(pBufferPointer, usb_mass_dataLength, USB_MASS_RX_ADDR); + + /* Return the number of received data */ + return usb_mass_dataLength; +} diff --git a/STM32F1/libraries/USBComposite/usb_mass.h b/STM32F1/libraries/USBComposite/usb_mass.h new file mode 100644 index 0000000..7d4f7ce --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_mass.h @@ -0,0 +1,112 @@ + +#ifndef _LIBMAPLE_USB_MASS_H_ +#define _LIBMAPLE_USB_MASS_H_ + +#include +#include +#include +#include +#include "usb_generic.h" +#include "usb_mass_mal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define N_STRING_DESCRIPTORS 4 + +#define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */ +#define MAX_BULK_PACKET_SIZE 0x40 /* 64B, max bulk Can't use 512 because the internal buffers for USB is only 512B */ + + + /* MASS Storage Requests */ +#define REQUEST_GET_MAX_LUN 0xFE +#define REQUEST_MASS_STORAGE_RESET 0xFF + + /* USB device state */ + typedef enum _DEVICE_STATE { + DEVICE_STATE_UNCONNECTED, + DEVICE_STATE_ATTACHED, + DEVICE_STATE_POWERED, + DEVICE_STATE_SUSPENDED, + DEVICE_STATE_ADDRESSED, + DEVICE_STATE_CONFIGURED + } DEVICE_STATE; + +#define BOT_DIR_IN 0 +#define BOT_DIR_OUT 1 +#define BOT_DIR_BOTH 2 + + /*****************************************************************************/ + /*********************** Bulk-Only Transfer State machine ********************/ + /*****************************************************************************/ +#define BOT_STATE_IDLE 0 /* Idle state */ +#define BOT_STATE_DATA_OUT 1 /* Data Out state */ +#define BOT_STATE_DATA_IN 2 /* Data In state */ +#define BOT_STATE_DATA_IN_LAST 3 /* Last Data In Last */ +#define BOT_STATE_CSW_Send 4 /* Command Status Wrapper */ +#define BOT_STATE_ERROR 5 /* error state */ + +#define BOT_CBW_SIGNATURE 0x43425355 +#define BOT_CSW_SIGNATURE 0x53425355 +#define BOT_CBW_PACKET_LENGTH 31 + +#define BOT_CSW_DATA_LENGTH 0x000D + + /* CSW Status Definitions */ +#define BOT_CSW_CMD_PASSED 0x00 +#define BOT_CSW_CMD_FAILED 0x01 +#define BOT_CSW_PHASE_ERROR 0x02 + +#define BOT_SEND_CSW_DISABLE 0 +#define BOT_SEND_CSW_ENABLE 1 + +#define USB_EP1_IN 0x81 + + /* Bulk-only Command Block Wrapper */ + typedef struct _BulkOnlyCBW { + uint32_t dSignature; + uint32_t dTag; + uint32_t dDataLength; + uint8_t bmFlags; + uint8_t bLUN; + uint8_t bCBLength; + uint8_t CB[16]; + } BulkOnlyCBW; + + /* Bulk-only Command Status Wrapper */ + typedef struct _BulkOnlyCSW { + uint32_t dSignature; + uint32_t dTag; + uint32_t dDataResidue; + uint8_t bStatus; + } BulkOnlyCSW; + + typedef struct _usb_descriptor_config { + usb_descriptor_config_header Config_Header; + usb_descriptor_interface MASS_Interface; + usb_descriptor_endpoint DataInEndpoint; + usb_descriptor_endpoint DataOutEndpoint; + } __packed usb_descriptor_config; + + void usb_mass_enable(gpio_dev *disc_dev, uint8 disc_bit); + void usb_mass_disable(gpio_dev *disc_dev, uint8 disc_bit); + void usb_mass_loop(); + + void usb_mass_bot_set_csw(uint8_t cswStatus, uint8_t sendPermission); + void usb_mass_transfer_data_request(uint8_t* dataPointer, uint16_t dataLen); + void usb_mass_bot_abort(uint8_t direction); + + extern USBCompositePart usbMassPart; + +extern uint8_t usb_mass_botState; +extern BulkOnlyCBW usb_mass_CBW; +extern BulkOnlyCSW usb_mass_CSW; +extern uint8_t usb_mass_bulkDataBuff[MAX_BULK_PACKET_SIZE]; +extern uint16_t usb_mass_dataLength; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_mass_internal.h b/STM32F1/libraries/USBComposite/usb_mass_internal.h new file mode 100644 index 0000000..c3405a8 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_mass_internal.h @@ -0,0 +1,12 @@ +#ifndef _USB_MASS_INTERNAL_H_ +#define _USB_MASS_INTERNAL_H_ + +extern USBEndpointInfo usbMassEndpoints[]; + +#define MASS_ENDPOINT_TX 0 +#define MASS_ENDPOINT_RX 1 +#define USB_MASS_RX_ENDP (usbMassEndpoints[MASS_ENDPOINT_RX].address) +#define USB_MASS_TX_ENDP (usbMassEndpoints[MASS_ENDPOINT_TX].address) +#define USB_MASS_RX_ADDR (usbMassEndpoints[MASS_ENDPOINT_RX].pmaAddress) +#define USB_MASS_TX_ADDR (usbMassEndpoints[MASS_ENDPOINT_TX].pmaAddress) +#endif \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/usb_mass_mal.c b/STM32F1/libraries/USBComposite/usb_mass_mal.c new file mode 100644 index 0000000..b3a79c3 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_mass_mal.c @@ -0,0 +1,42 @@ +#include +#include "usb_mass_mal.h" + + +#define USB_MASS_MAL_FAIL 1 +#define USB_MASS_MAL_SUCCESS 0 + +MassStorageDriveInfo usb_mass_drives[USB_MASS_MAX_DRIVES] = { { 0 } }; + +uint16_t usb_mass_mal_init(uint8_t lun) { + if (lun >= USB_MASS_MAX_DRIVES || (usb_mass_drives[lun].init != NULL && ! usb_mass_drives[lun].init())) + return USB_MASS_MAL_FAIL; + else + return USB_MASS_MAL_SUCCESS; +} + +void usb_mass_mal_format(uint8_t lun) { + if (lun < USB_MASS_MAX_DRIVES && usb_mass_drives[lun].format != NULL) + usb_mass_drives[lun].format(); +} + +uint16_t usb_mass_mal_get_status(uint8_t lun) { + if (lun >= USB_MASS_MAX_DRIVES || (usb_mass_drives[lun].status != NULL && ! usb_mass_drives[lun].status())) + return USB_MASS_MAL_FAIL; + else + return USB_MASS_MAL_SUCCESS; +} + +uint16_t usb_mass_mal_read_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength) { + if (lun >= USB_MASS_MAX_DRIVES || ! usb_mass_drives[lun].read(memoryOffset, readbuff, transferLength)) + return USB_MASS_MAL_FAIL; + else + return USB_MASS_MAL_SUCCESS; +} + +uint16_t usb_mass_mal_write_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *writebuff, uint16_t transferLength) { + if (lun >= USB_MASS_MAX_DRIVES || usb_mass_drives[lun].write == NULL + || ! usb_mass_drives[lun].write(memoryOffset, writebuff, transferLength)) + return USB_MASS_MAL_FAIL; + else + return USB_MASS_MAL_SUCCESS; +} diff --git a/STM32F1/libraries/USBComposite/usb_mass_mal.h b/STM32F1/libraries/USBComposite/usb_mass_mal.h new file mode 100644 index 0000000..455fd71 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_mass_mal.h @@ -0,0 +1,39 @@ +#ifndef __USB_MASS_MAL_H +#define __USB_MASS_MAL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define USB_MASS_MAX_DRIVES 2 + +typedef bool (*MassStorageWriter)(uint32_t memoryOffset, const uint8_t *writebuff, uint16_t transferLength); +typedef bool (*MassStorageReader)(uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength); +typedef bool (*MassStorageStatuser)(void); +typedef bool (*MassStorageInitializer)(void); +typedef bool (*MassStorageFormatter)(void); + +typedef struct { + uint32_t blockCount; + MassStorageReader read; + MassStorageWriter write; + MassStorageStatuser status; + MassStorageInitializer init; + MassStorageFormatter format; +} MassStorageDriveInfo; + +extern MassStorageDriveInfo usb_mass_drives[USB_MASS_MAX_DRIVES]; +uint16_t usb_mass_mal_init(uint8_t lun); +uint16_t usb_mass_mal_get_status(uint8_t lun); +uint16_t usb_mass_mal_read_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength); +uint16_t usb_mass_mal_write_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *writebuff, uint16_t transferLength); +void usb_mass_mal_format(uint8_t lun); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_midi_device.c b/STM32F1/libraries/USBComposite/usb_midi_device.c new file mode 100644 index 0000000..549d581 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_midi_device.c @@ -0,0 +1,532 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * Copyright (c) 2013 Magnus Lundin. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usb/stm32f1/usb_midi_device.c + * @brief USB MIDI. + * + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. + */ + +#include +#include "usb_generic.h" +#include "usb_midi_device.h" +#include +#include + +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +static void midiDataTxCb(void); +static void midiDataRxCb(void); + +static void usbMIDIReset(void); +static RESULT usbMIDIDataSetup(uint8 request); +static RESULT usbMIDINoDataSetup(uint8 request); + +#define MIDI_ENDPOINT_RX 0 +#define MIDI_ENDPOINT_TX 1 +#define USB_MIDI_RX_ENDP (midiEndpoints[MIDI_ENDPOINT_RX].address) +#define USB_MIDI_TX_ENDP (midiEndpoints[MIDI_ENDPOINT_TX].address) +#define USB_MIDI_RX_ADDR (midiEndpoints[MIDI_ENDPOINT_RX].pmaAddress) +#define USB_MIDI_TX_ADDR (midiEndpoints[MIDI_ENDPOINT_TX].pmaAddress) + +/* + * Descriptors + */ + +typedef struct { +// usb_descriptor_config_header Config_Header; + /* Control Interface */ + usb_descriptor_interface AC_Interface; + AC_CS_INTERFACE_DESCRIPTOR(1) AC_CS_Interface; + /* Control Interface */ + usb_descriptor_interface MS_Interface; + MS_CS_INTERFACE_DESCRIPTOR MS_CS_Interface; + MIDI_IN_JACK_DESCRIPTOR MIDI_IN_JACK_1; + MIDI_IN_JACK_DESCRIPTOR MIDI_IN_JACK_2; + MIDI_OUT_JACK_DESCRIPTOR(1) MIDI_OUT_JACK_3; + MIDI_OUT_JACK_DESCRIPTOR(1) MIDI_OUT_JACK_4; + usb_descriptor_endpoint DataOutEndpoint; + MS_CS_BULK_ENDPOINT_DESCRIPTOR(1) MS_CS_DataOutEndpoint; + usb_descriptor_endpoint DataInEndpoint; + MS_CS_BULK_ENDPOINT_DESCRIPTOR(1) MS_CS_DataInEndpoint; +} __packed usb_descriptor_config; + +static const usb_descriptor_config usbMIDIDescriptor_Config = { + /* .Config_Header = { + .bLength = sizeof(usb_descriptor_config_header), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = sizeof(usb_descriptor_config), + .bNumInterfaces = 0x02, + .bConfigurationValue = 0x01, + .iConfiguration = 0x00, + .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED), + .bMaxPower = MAX_POWER, + }, */ + + .AC_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = 0x00, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x00, + .bInterfaceClass = USB_INTERFACE_CLASS_AUDIO, + .bInterfaceSubClass = USB_INTERFACE_AUDIOCONTROL, + .bInterfaceProtocol = 0x00, + .iInterface = 0x00, + }, + + .AC_CS_Interface = { + .bLength = AC_CS_INTERFACE_DESCRIPTOR_SIZE(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = 0x01, + .bcdADC = 0x0100, + .wTotalLength = AC_CS_INTERFACE_DESCRIPTOR_SIZE(1), + .bInCollection = 0x01, + .baInterfaceNr = {0x01}, + }, + + .MS_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = 0x01, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = USB_INTERFACE_CLASS_AUDIO, + .bInterfaceSubClass = USB_INTERFACE_MIDISTREAMING, + .bInterfaceProtocol = 0x00, + .iInterface = 0, // was 0x04 + }, + + .MS_CS_Interface = { + .bLength = sizeof(MS_CS_INTERFACE_DESCRIPTOR), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = 0x01, + .bcdADC = 0x0100, + .wTotalLength = sizeof(MS_CS_INTERFACE_DESCRIPTOR) + +sizeof(MIDI_IN_JACK_DESCRIPTOR) + +sizeof(MIDI_IN_JACK_DESCRIPTOR) + +MIDI_OUT_JACK_DESCRIPTOR_SIZE(1) + +MIDI_OUT_JACK_DESCRIPTOR_SIZE(1) + +sizeof(usb_descriptor_endpoint) + +MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1) + +sizeof(usb_descriptor_endpoint) + +MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1) + /* 0x41-4 */, + }, + + .MIDI_IN_JACK_1 = { + .bLength = sizeof(MIDI_IN_JACK_DESCRIPTOR), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = MIDI_IN_JACK, + .bJackType = MIDI_JACK_EMBEDDED, + .bJackId = 0x01, + .iJack = 0x05, + }, + + .MIDI_IN_JACK_2 = { + .bLength = sizeof(MIDI_IN_JACK_DESCRIPTOR), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = MIDI_IN_JACK, + .bJackType = MIDI_JACK_EXTERNAL, + .bJackId = 0x02, + .iJack = 0x00, + }, + + .MIDI_OUT_JACK_3 = { + .bLength = MIDI_OUT_JACK_DESCRIPTOR_SIZE(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = MIDI_OUT_JACK, + .bJackType = MIDI_JACK_EMBEDDED, + .bJackId = 0x03, + .bNrInputPins = 0x01, + .baSourceId = {0x02}, + .baSourcePin = {0x01}, + .iJack = 0x00, + }, + + .MIDI_OUT_JACK_4 = { + .bLength = MIDI_OUT_JACK_DESCRIPTOR_SIZE(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = MIDI_OUT_JACK, + .bJackType = MIDI_JACK_EXTERNAL, +// .bJackId = 0x04, + .bJackId = 0x03, + .bNrInputPins = 0x01, + .baSourceId = {0x01}, + .baSourcePin = {0x01}, + .iJack = 0x00, + }, + + .DataOutEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | + MIDI_ENDPOINT_RX), // PATCH + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = USB_MIDI_RX_EPSIZE, + .bInterval = 0x00, + }, + + .MS_CS_DataOutEndpoint = { + .bLength = MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_ENDPOINT, + .SubType = 0x01, + .bNumEmbMIDIJack = 0x01, + .baAssocJackID = {0x01}, + }, + + .DataInEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | MIDI_ENDPOINT_TX), // PATCH + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = USB_MIDI_TX_EPSIZE, + .bInterval = 0x00, + }, + + .MS_CS_DataInEndpoint = { + .bLength = MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_ENDPOINT, + .SubType = 0x01, + .bNumEmbMIDIJack = 0x01, + .baAssocJackID = {0x03}, + }, + +}; + +/* I/O state */ + +/* Received data */ +static volatile uint32 midiBufferRx[USB_MIDI_RX_EPSIZE/4]; +/* Read index into midiBufferRx */ +static volatile uint32 rx_offset = 0; +/* Transmit data */ +static volatile uint32 midiBufferTx[USB_MIDI_TX_EPSIZE/4]; +/* Write index into midiBufferTx */ +static volatile uint32 tx_offset = 0; +/* Number of bytes left to transmit */ +static volatile uint32 n_unsent_packets = 0; +/* Are we currently sending an IN packet? */ +static volatile uint8 transmitting = 0; +/* Number of unread bytes */ +static volatile uint32 n_unread_packets = 0; + + +// eventually all of this should be in a place for settings which can be written to flash. +volatile uint8 myMidiChannel = DEFAULT_MIDI_CHANNEL; +volatile uint8 myMidiDevice = DEFAULT_MIDI_DEVICE; +volatile uint8 myMidiCable = DEFAULT_MIDI_CABLE; +volatile uint8 myMidiID[] = { LEAFLABS_MMA_VENDOR_1,LEAFLABS_MMA_VENDOR_2,LEAFLABS_MMA_VENDOR_3,0}; + +#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s] + +static void getMIDIPartDescriptor(uint8* out) { + memcpy(out, &usbMIDIDescriptor_Config, sizeof(usbMIDIDescriptor_Config)); + // patch to reflect where the part goes in the descriptor + OUT_BYTE(usbMIDIDescriptor_Config, AC_Interface.bInterfaceNumber) += usbMIDIPart.startInterface; + OUT_BYTE(usbMIDIDescriptor_Config, MS_Interface.bInterfaceNumber) += usbMIDIPart.startInterface; + OUT_BYTE(usbMIDIDescriptor_Config, DataOutEndpoint.bEndpointAddress) += usbMIDIPart.startEndpoint; + OUT_BYTE(usbMIDIDescriptor_Config, DataInEndpoint.bEndpointAddress) += usbMIDIPart.startEndpoint; +} + +static USBEndpointInfo midiEndpoints[2] = { + { + .callback = midiDataRxCb, + .bufferSize = USB_MIDI_RX_EPSIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 0 + }, + { + .callback = midiDataTxCb, + .bufferSize = USB_MIDI_TX_EPSIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 1, + } +}; + +USBCompositePart usbMIDIPart = { + .numInterfaces = 2, + .numEndpoints = sizeof(midiEndpoints)/sizeof(*midiEndpoints), + .descriptorSize = sizeof(usbMIDIDescriptor_Config), + .getPartDescriptor = getMIDIPartDescriptor, + .usbInit = NULL, + .usbReset = usbMIDIReset, + .usbDataSetup = usbMIDIDataSetup, + .usbNoDataSetup = usbMIDINoDataSetup, + .endpoints = midiEndpoints +}; + +/* + * MIDI interface + */ + +/* This function is non-blocking. + * + * It copies data from a usercode buffer into the USB peripheral TX + * buffer, and returns the number of bytes copied. */ +uint32 usb_midi_tx(const uint32* buf, uint32 packets) { + uint32 bytes=packets*4; + /* Last transmission hasn't finished, so abort. */ + if (usb_midi_is_transmitting()) { + /* Copy to TxBuffer */ + + return 0; /* return len */ + } + + /* We can only put USB_MIDI_TX_EPSIZE bytes in the buffer. */ + if (bytes > USB_MIDI_TX_EPSIZE) { + bytes = USB_MIDI_TX_EPSIZE; + packets=bytes/4; + } + + /* Queue bytes for sending. */ + if (packets) { + usb_copy_to_pma((uint8 *)buf, bytes, USB_MIDI_TX_ADDR); + } + // We still need to wait for the interrupt, even if we're sending + // zero bytes. (Sending zero-size packets is useful for flushing + // host-side buffers.) + usb_set_ep_tx_count(USB_MIDI_TX_ENDP, bytes); + n_unsent_packets = packets; + transmitting = 1; + usb_set_ep_tx_stat(USB_MIDI_TX_ENDP, USB_EP_STAT_TX_VALID); + + return packets; +} + +uint32 usb_midi_data_available(void) { + return n_unread_packets; +} + +uint8 usb_midi_is_transmitting(void) { + return transmitting; +} + +uint16 usb_midi_get_pending(void) { + return n_unsent_packets; +} + +/* Nonblocking byte receive. + * + * Copies up to len bytes from our private data buffer (*NOT* the PMA) + * into buf and deq's the FIFO. */ +uint32 usb_midi_rx(uint32* buf, uint32 packets) { + /* Copy bytes to buffer. */ + uint32 n_copied = usb_midi_peek(buf, packets); + + /* Mark bytes as read. */ + n_unread_packets -= n_copied; + rx_offset += n_copied; + + /* If all bytes have been read, re-enable the RX endpoint, which + * was set to NAK when the current batch of bytes was received. */ + if (n_unread_packets == 0) { + usb_set_ep_rx_count(USB_MIDI_RX_ENDP, USB_MIDI_RX_EPSIZE); + usb_set_ep_rx_stat(USB_MIDI_RX_ENDP, USB_EP_STAT_RX_VALID); + rx_offset = 0; + } + + return n_copied; +} + +/* Nonblocking byte lookahead. + * + * Looks at unread bytes without marking them as read. */ +uint32 usb_midi_peek(uint32* buf, uint32 packets) { + uint32 i; + if (packets > n_unread_packets) { + packets = n_unread_packets; + } + + for (i = 0; i < packets; i++) { + buf[i] = midiBufferRx[i + rx_offset]; + } + + return packets; +} + +/* + * Callbacks + */ + +static void midiDataTxCb(void) { + n_unsent_packets = 0; + transmitting = 0; +} + +static void midiDataRxCb(void) { + usb_set_ep_rx_stat(USB_MIDI_RX_ENDP, USB_EP_STAT_RX_NAK); + n_unread_packets = usb_get_ep_rx_count(USB_MIDI_RX_ENDP) / 4; + /* This copy won't overwrite unread bytes, since we've set the RX + * endpoint to NAK, and will only set it to VALID when all bytes + * have been read. */ + + usb_copy_from_pma((uint8*)midiBufferRx, n_unread_packets * 4, + USB_MIDI_RX_ADDR); + + // discard volatile + LglSysexHandler((uint32*)midiBufferRx,(uint32*)&rx_offset,(uint32*)&n_unread_packets); + + if (n_unread_packets == 0) { + usb_set_ep_rx_count(USB_MIDI_RX_ENDP, USB_MIDI_RX_EPSIZE); + usb_set_ep_rx_stat(USB_MIDI_RX_ENDP, USB_EP_STAT_RX_VALID); + rx_offset = 0; + } + +} + +static void usbMIDIReset(void) { + /* Reset the RX/TX state */ + n_unread_packets = 0; + n_unsent_packets = 0; + rx_offset = 0; +} + +static RESULT usbMIDIDataSetup(uint8 request) { + (void)request;//unused +#if 0 + uint8* (*CopyRoutine)(uint16) = 0; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + } + + if (CopyRoutine == NULL) { + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +#endif + return USB_UNSUPPORT; +} + +static RESULT usbMIDINoDataSetup(uint8 request) { + (void)request;//unused +#if 0 + RESULT ret = USB_UNSUPPORT; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + } + return ret; +#endif + return USB_UNSUPPORT; +} + +// .............THIS IS NOT WORKING YET................ +// send debugging information to +static uint8_t sysexbuffer[80]={CIN_SYSEX,0xF0,0x7D,0x33,CIN_SYSEX,0x33,0x00,0xf7}; // !!!bad hardcoded number foo !!! +uint8_t iSysHexLine(uint8_t rectype, uint16_t address, uint8_t *payload,uint8_t payloadlength, uint8_t *buffer); +void sendThroughSysex(char *printbuffer, int bufferlength) { + int n; + n = iSysHexLine(1, 0 , (uint8_t *) printbuffer, (uint8_t) bufferlength , sysexbuffer+6); + usb_midi_tx((uint32*)sysexbuffer,n/4); +} + +#define HIGHBYTE(x) ((uint8_t) (((x) >> 8) & 0x00ff) ) +#define LOWBYTE(x) ((uint8_t) ((x) & 0x00ff) ) +#define HIGHNIBBLE(x) ((((uint8_t)(x)) & 0xF0) >> 4) +#define LOWNIBBLE(x) (((uint8_t)(x)) & 0x0F) +#define HEXCHAR(c) ((c>9)?55+c:48+c) + + +uint8_t iSysHexLine(uint8_t rectype, uint16_t address, uint8_t *payload,uint8_t payloadlength, uint8_t *buffer) { + + int i=0; int j; int thirdone; + uint8_t n=0; + uint16_t checksum=0; + //uint16_t length=0; + + buffer[i++]=':'; + + checksum+=payloadlength; + buffer[i++]=HEXCHAR(HIGHNIBBLE(payloadlength)); + buffer[i++]=HEXCHAR(LOWNIBBLE(payloadlength)); + buffer[i++]=CIN_SYSEX; + + n=HIGHBYTE(address); + checksum+=n; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + + n=LOWBYTE(address); + checksum+=n; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=CIN_SYSEX; + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + + n=rectype; + checksum+=n; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + buffer[i++]=CIN_SYSEX; + thirdone=0; + for (j=0; j +#include +#include +#include +#include "usb_generic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern USBCompositePart usbMIDIPart; + +typedef union { + uint8 byte[4]; + uint32 data; +} USB_MIDI_Event_Packet; + +/* + * USB MIDI Requests + */ + +/* + * Descriptors, etc. + */ +#define USB_DESCRIPTOR_TYPE_CS_INTERFACE 0x24 +#define USB_DESCRIPTOR_TYPE_CS_ENDPOINT 0x25 + + +#define USB_DEVICE_CLASS_UNDEFINED 0x00 +#define USB_DEVICE_CLASS_CDC 0x02 +#define USB_DEVICE_SUBCLASS_UNDEFINED 0x00 + +#define USB_INTERFACE_CLASS_AUDIO 0x01 +#define USB_INTERFACE_SUBCLASS_UNDEFINED 0x00 +#define USB_INTERFACE_AUDIOCONTROL 0x01 +#define USB_INTERFACE_AUDIOSTREAMING 0x02 +#define USB_INTERFACE_MIDISTREAMING 0x03 + +/* MIDI Streaming class specific interfaces */ +#define MIDI_IN_JACK 0x02 +#define MIDI_OUT_JACK 0x03 + +#define MIDI_JACK_EMBEDDED 0x01 +#define MIDI_JACK_EXTERNAL 0x02 + + +#define AC_CS_INTERFACE_DESCRIPTOR_SIZE(DataSize) (8 + DataSize) +#define AC_CS_INTERFACE_DESCRIPTOR(DataSize) \ + struct { \ + uint8 bLength; \ + uint8 bDescriptorType; \ + uint8 SubType; \ + uint16 bcdADC; \ + uint16 wTotalLength; \ + uint8 bInCollection; \ + uint8 baInterfaceNr[DataSize]; \ + } __packed + +typedef struct { + uint8 bLength; + uint8 bDescriptorType; + uint8 SubType; + uint16 bcdADC; + uint16 wTotalLength; + } __packed MS_CS_INTERFACE_DESCRIPTOR; + +typedef struct { + uint8 bLength; + uint8 bDescriptorType; + uint8 SubType; + uint8 bJackType; + uint8 bJackId; + uint8 iJack; + } __packed MIDI_IN_JACK_DESCRIPTOR; + +#define MIDI_OUT_JACK_DESCRIPTOR_SIZE(DataSize) (7 + 2*DataSize) +#define MIDI_OUT_JACK_DESCRIPTOR(DataSize) \ + struct { \ + uint8 bLength; \ + uint8 bDescriptorType; \ + uint8 SubType; \ + uint8 bJackType; \ + uint8 bJackId; \ + uint8 bNrInputPins; \ + uint8 baSourceId[DataSize]; \ + uint8 baSourcePin[DataSize]; \ + uint8 iJack; \ + } __packed + + +#define MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(DataSize) (4 + DataSize) +#define MS_CS_BULK_ENDPOINT_DESCRIPTOR(DataSize) \ + struct { \ + uint8 bLength; \ + uint8 bDescriptorType; \ + uint8 SubType; \ + uint8 bNumEmbMIDIJack; \ + uint8 baAssocJackID[DataSize]; \ + } __packed + +/* + * Endpoint configuration + */ + +#define USB_MIDI_TX_EPSIZE 0x40 + +#define USB_MIDI_RX_EPSIZE 0x40 + +#ifndef __cplusplus +#define USB_MIDI_DECLARE_DEV_DESC(vid, pid) \ + { \ + .bLength = sizeof(usb_descriptor_device), \ + .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, \ + .bcdUSB = 0x0110, \ + .bDeviceClass = USB_DEVICE_CLASS_UNDEFINED, \ + .bDeviceSubClass = USB_DEVICE_SUBCLASS_UNDEFINED, \ + .bDeviceProtocol = 0x00, \ + .bMaxPacketSize0 = 0x40, \ + .idVendor = vid, \ + .idProduct = pid, \ + .bcdDevice = 0x0200, \ + .iManufacturer = 0x01, \ + .iProduct = 0x02, \ + .iSerialNumber = 0x00, \ + .bNumConfigurations = 0x01, \ + } +#endif + +/* + * Sysex Stuff. + */ + +#define SYSEX_BUFFER_LENGTH 256 + + + /* + * MIDI interface + */ + + void usb_midi_putc(char ch); + uint32 usb_midi_tx(const uint32* buf, uint32 len); + uint32 usb_midi_rx(uint32* buf, uint32 len); + uint32 usb_midi_peek(uint32* buf, uint32 len); + + uint32 usb_midi_data_available(void); /* in RX buffer */ + uint16 usb_midi_get_pending(void); + uint8 usb_midi_is_transmitting(void); + + void sendThroughSysex(char *printbuffer, int bufferlength); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_scsi.c b/STM32F1/libraries/USBComposite/usb_scsi.c new file mode 100644 index 0000000..2ff3dfd --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_scsi.c @@ -0,0 +1,333 @@ +#include "usb_mass.h" +#include "usb_mass_mal.h" +#include "usb_mass_internal.h" +#include "usb_scsi.h" + +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" +#include "usb_regs.h" + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +#define SCSI_READ_FORMAT_CAPACITY_DATA_LEN 0x0C +#define SCSI_READ_FORMAT_CAPACITY10_DATA_LEN 0x08 +#define SCSI_MODE_SENSE6_DATA_LEN 0x04 +#define SCSI_MODE_SENSE10_DATA_LEN 0x08 + +#define SCSI_TXFR_IDLE 0 +#define SCSI_TXFR_ONGOING 1 + +extern uint32_t usb_mass_sil_write(uint8_t* pBufferPointer, uint32_t wBufferSize); + +/* See usb_scsi_data.c */ +extern uint8_t SCSI_page00InquiryData[]; +extern uint8_t SCSI_standardInquiryData[]; +extern uint8_t SCSI_standardInquiryData2[]; +extern uint8_t SCSI_senseData[]; +extern uint8_t SCSI_modeSense6Data[]; +extern uint8_t SCSI_modeSense10Data[]; +extern uint8_t SCSI_readFormatCapacityData[]; +extern uint8_t SCSI_readFormatCapacity10Data[]; + +uint32_t SCSI_lba; +uint32_t SCSI_blkLen; +uint8_t SCSI_transferState = SCSI_TXFR_IDLE; +uint32_t SCSI_blockReadCount = 0; +uint32_t SCSI_blockOffset; +uint32_t SCSI_counter = 0; +uint8_t SCSI_dataBuffer[512]; /* 512 bytes (SDCard block size) */ + +uint8_t scsi_address_management(uint8_t lun, uint8_t cmd, uint32_t lba, uint32_t blockNbr); +void scsi_read_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength); +void scsi_write_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength); + +void scsi_inquiry_cmd(uint8_t lun) { + uint8_t* inquiryData; + uint16_t inquiryDataLength; + + if (usb_mass_CBW.CB[1] & 0x01) /*Evpd is set*/ { + inquiryData = SCSI_page00InquiryData; + inquiryDataLength = 5; + } else { + if (lun == 0) { + inquiryData = SCSI_standardInquiryData; + } else { + inquiryData = SCSI_standardInquiryData2; + } + + if (usb_mass_CBW.CB[4] <= SCSI_STANDARD_INQUIRY_DATA_LEN) { + inquiryDataLength = usb_mass_CBW.CB[4]; + } else { + inquiryDataLength = SCSI_STANDARD_INQUIRY_DATA_LEN; + } + } + usb_mass_transfer_data_request(inquiryData, inquiryDataLength); +} + +void scsi_request_sense_cmd(uint8_t lun) { + uint8_t requestSenseDataLength; + if (usb_mass_CBW.CB[4] <= SCSI_REQUEST_SENSE_DATA_LEN) { + requestSenseDataLength = usb_mass_CBW.CB[4]; + } else { + requestSenseDataLength = SCSI_REQUEST_SENSE_DATA_LEN; + } + usb_mass_transfer_data_request(SCSI_senseData, requestSenseDataLength); +} + +void scsi_start_stop_unit_cmd(uint8_t lun) { + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); +} + +void scsi_mode_sense6_cmd(uint8_t lun) { + usb_mass_transfer_data_request(SCSI_modeSense6Data, SCSI_MODE_SENSE6_DATA_LEN); +} + +void scsi_mode_sense10_cmd(uint8_t lun) { + usb_mass_transfer_data_request(SCSI_modeSense10Data, SCSI_MODE_SENSE10_DATA_LEN); +} + +void scsi_read_format_capacity_cmd(uint8_t lun) { + if (usb_mass_mal_get_status(lun)) { + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE); + usb_mass_bot_abort(BOT_DIR_IN); + return; + } + SCSI_readFormatCapacityData[4] = (uint8_t) (usb_mass_drives[lun].blockCount >> 24); + SCSI_readFormatCapacityData[5] = (uint8_t) (usb_mass_drives[lun].blockCount >> 16); + SCSI_readFormatCapacityData[6] = (uint8_t) (usb_mass_drives[lun].blockCount >> 8); + SCSI_readFormatCapacityData[7] = (uint8_t) (usb_mass_drives[lun].blockCount); + + SCSI_readFormatCapacityData[9] = (uint8_t) (SCSI_BLOCK_SIZE >> 16); + SCSI_readFormatCapacityData[10] = (uint8_t) (SCSI_BLOCK_SIZE >> 8); + SCSI_readFormatCapacityData[11] = (uint8_t) (SCSI_BLOCK_SIZE); + usb_mass_transfer_data_request(SCSI_readFormatCapacityData, SCSI_READ_FORMAT_CAPACITY_DATA_LEN); +} + +void scsi_read_capacity10_cmd(uint8_t lun) { + if (usb_mass_mal_get_status(lun)) { + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE); + usb_mass_bot_abort(BOT_DIR_IN); + return; + } + + SCSI_readFormatCapacity10Data[0] = (uint8_t) ((usb_mass_drives[lun].blockCount - 1) >> 24); + SCSI_readFormatCapacity10Data[1] = (uint8_t) ((usb_mass_drives[lun].blockCount - 1) >> 16); + SCSI_readFormatCapacity10Data[2] = (uint8_t) ((usb_mass_drives[lun].blockCount - 1) >> 8); + SCSI_readFormatCapacity10Data[3] = (uint8_t) (usb_mass_drives[lun].blockCount - 1); + + SCSI_readFormatCapacity10Data[4] = (uint8_t) (SCSI_BLOCK_SIZE >> 24); + SCSI_readFormatCapacity10Data[5] = (uint8_t) (SCSI_BLOCK_SIZE >> 16); + SCSI_readFormatCapacity10Data[6] = (uint8_t) (SCSI_BLOCK_SIZE >> 8); + SCSI_readFormatCapacity10Data[7] = (uint8_t) (SCSI_BLOCK_SIZE); + usb_mass_transfer_data_request(SCSI_readFormatCapacity10Data, SCSI_READ_FORMAT_CAPACITY10_DATA_LEN); +} + +void scsi_read10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr) { + if (usb_mass_botState == BOT_STATE_IDLE) { + if (!(scsi_address_management(usb_mass_CBW.bLUN, SCSI_READ10, lba, blockNbr))) /*address out of range*/ { + return; + } + + if ((usb_mass_CBW.bmFlags & 0x80) != 0) { + usb_mass_botState = BOT_STATE_DATA_IN; + scsi_read_memory(lun, lba, blockNbr); + } else { + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE); + } + return; + } else if (usb_mass_botState == BOT_STATE_DATA_IN) { + scsi_read_memory(lun, lba, blockNbr); + } +} + +void scsi_write10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr) { + if (usb_mass_botState == BOT_STATE_IDLE) { + if (!(scsi_address_management(usb_mass_CBW.bLUN, SCSI_WRITE10, lba, blockNbr)))/*address out of range*/ { + return; + } + + if ((usb_mass_CBW.bmFlags & 0x80) == 0) { + usb_mass_botState = BOT_STATE_DATA_OUT; + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL); + } else { + usb_mass_bot_abort(BOT_DIR_IN); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + } + return; + } else if (usb_mass_botState == BOT_STATE_DATA_OUT) { + scsi_write_memory(lun, lba, blockNbr); + } +} + +void scsi_test_unit_ready_cmd(uint8_t lun) { + if (usb_mass_mal_get_status(lun)) { + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE); + usb_mass_bot_abort(BOT_DIR_IN); + return; + } else { + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); + } +} + +void scsi_verify10_cmd(uint8_t lun) { + if ((usb_mass_CBW.dDataLength == 0) && !(usb_mass_CBW.CB[1] & SCSI_BLKVFY))/* BLKVFY not set*/ { + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); + } else { + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + } +} + +void scsi_format_cmd(uint8_t lun) { + if (usb_mass_mal_get_status(lun)) { + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE); + usb_mass_bot_abort(BOT_DIR_IN); + return; + } + usb_mass_mal_format(lun); + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); +} + +void scsi_set_sense_data(uint8_t lun, uint8_t sensKey, uint8_t asc) { + SCSI_senseData[2] = sensKey; + SCSI_senseData[12] = asc; +} + +void scsi_invalid_cmd(uint8_t lun) { + if (usb_mass_CBW.dDataLength == 0) { + usb_mass_bot_abort(BOT_DIR_IN); + } else { + if ((usb_mass_CBW.bmFlags & 0x80) != 0) { + usb_mass_bot_abort(BOT_DIR_IN); + } else { + usb_mass_bot_abort(BOT_DIR_BOTH); + } + } + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); +} + +uint8_t scsi_address_management(uint8_t lun, uint8_t cmd, uint32_t lba, uint32_t blockNbr) { + + if ((lba + blockNbr) > usb_mass_drives[lun].blockCount) { + if (cmd == SCSI_WRITE10) { + usb_mass_bot_abort(BOT_DIR_BOTH); + } + usb_mass_bot_abort(BOT_DIR_IN); + scsi_set_sense_data(lun, SCSI_ILLEGAL_REQUEST, SCSI_ADDRESS_OUT_OF_RANGE); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + return (FALSE); + } + + + if (usb_mass_CBW.dDataLength != blockNbr * SCSI_BLOCK_SIZE) { + if (cmd == SCSI_WRITE10) { + usb_mass_bot_abort(BOT_DIR_BOTH); + } else { + usb_mass_bot_abort(BOT_DIR_IN); + } + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + return (FALSE); + } + return (TRUE); +} + +void scsi_read_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength) { + static uint32_t offset, length; + + if (SCSI_transferState == SCSI_TXFR_IDLE) { + offset = memoryOffset * SCSI_BLOCK_SIZE; + length = transferLength * SCSI_BLOCK_SIZE; + SCSI_transferState = SCSI_TXFR_ONGOING; + } + + if (SCSI_transferState == SCSI_TXFR_ONGOING) { + if (SCSI_blockReadCount == 0) { + usb_mass_mal_read_memory(lun, offset, SCSI_dataBuffer, SCSI_BLOCK_SIZE); + + usb_mass_sil_write(SCSI_dataBuffer, MAX_BULK_PACKET_SIZE); + + SCSI_blockReadCount = SCSI_BLOCK_SIZE - MAX_BULK_PACKET_SIZE; + SCSI_blockOffset = 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; + } + + SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_VAL); + + offset += MAX_BULK_PACKET_SIZE; + length -= MAX_BULK_PACKET_SIZE; + + usb_mass_CSW.dDataResidue -= MAX_BULK_PACKET_SIZE; + usb_mass_CSW.bStatus = BOT_CSW_CMD_PASSED; + // TODO: Led_RW_ON(); + } + + if (length == 0) { + SCSI_blockReadCount = 0; + SCSI_blockOffset = 0; + offset = 0; + usb_mass_botState = BOT_STATE_DATA_IN_LAST; + SCSI_transferState = SCSI_TXFR_IDLE; + // TODO: Led_RW_OFF(); + } +} + +void scsi_write_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength) { + static uint32_t offset, length; + uint32_t idx; + uint32_t temp = SCSI_counter + 64; + + if (SCSI_transferState == SCSI_TXFR_IDLE) { + offset = memoryOffset * SCSI_BLOCK_SIZE; + length = transferLength * SCSI_BLOCK_SIZE; + SCSI_transferState = SCSI_TXFR_ONGOING; + } + + if (SCSI_transferState == SCSI_TXFR_ONGOING) { + + for (idx = 0; SCSI_counter < temp; SCSI_counter++) { + *((uint8_t *) SCSI_dataBuffer + SCSI_counter) = usb_mass_bulkDataBuff[idx++]; + } + + offset += usb_mass_dataLength; + length -= usb_mass_dataLength; + + if (!(length % SCSI_BLOCK_SIZE)) { + SCSI_counter = 0; + usb_mass_mal_write_memory(lun, offset - SCSI_BLOCK_SIZE, SCSI_dataBuffer, SCSI_BLOCK_SIZE); + } + + usb_mass_CSW.dDataResidue -= usb_mass_dataLength; + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL); /* enable the next transaction*/ + + // TODO: Led_RW_ON(); + } + + if ((length == 0) || (usb_mass_botState == BOT_STATE_CSW_Send)) { + SCSI_counter = 0; + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); + SCSI_transferState = SCSI_TXFR_IDLE; + // TODO: Led_RW_OFF(); + } +} \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/usb_scsi.h b/STM32F1/libraries/USBComposite/usb_scsi.h new file mode 100644 index 0000000..a5b121a --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_scsi.h @@ -0,0 +1,96 @@ +#ifndef __USB_SCSI_H +#define __USB_SCSI_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SCSI_BLOCK_SIZE 512 + + /* SCSI Commands */ +#define SCSI_FORMAT_UNIT 0x04 +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SELECT6 0x15 +#define SCSI_MODE_SELECT10 0x55 +#define SCSI_MODE_SENSE6 0x1A +#define SCSI_MODE_SENSE10 0x5A +#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_READ6 0x08 +#define SCSI_READ10 0x28 +#define SCSI_READ12 0xA8 +#define SCSI_READ16 0x88 + +#define SCSI_READ_CAPACITY10 0x25 +#define SCSI_READ_CAPACITY16 0x9E + +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_START_STOP_UNIT 0x1B +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_WRITE6 0x0A +#define SCSI_WRITE10 0x2A +#define SCSI_WRITE12 0xAA +#define SCSI_WRITE16 0x8A + +#define SCSI_VERIFY10 0x2F +#define SCSI_VERIFY12 0xAF +#define SCSI_VERIFY16 0x8F + +#define SCSI_SEND_DIAGNOSTIC 0x1D +#define SCSI_READ_FORMAT_CAPACITIES 0x23 + +#define SCSI_NO_SENSE 0 +#define SCSI_RECOVERED_ERROR 1 +#define SCSI_NOT_READY 2 +#define SCSI_MEDIUM_ERROR 3 +#define SCSI_HARDWARE_ERROR 4 +#define SCSI_ILLEGAL_REQUEST 5 +#define SCSI_UNIT_ATTENTION 6 +#define SCSI_DATA_PROTECT 7 +#define SCSI_BLANK_CHECK 8 +#define SCSI_VENDOR_SPECIFIC 9 +#define SCSI_COPY_ABORTED 10 +#define SCSI_ABORTED_COMMAND 11 +#define SCSI_VOLUME_OVERFLOW 13 +#define SCSI_MISCOMPARE 14 + +#define SCSI_INVALID_COMMAND 0x20 +#define SCSI_INVALID_FIELED_IN_COMMAND 0x24 +#define SCSI_PARAMETER_LIST_LENGTH_ERROR 0x1A +#define SCSI_INVALID_FIELD_IN_PARAMETER_LIST 0x26 +#define SCSI_ADDRESS_OUT_OF_RANGE 0x21 +#define SCSI_MEDIUM_NOT_PRESENT 0x3A +#define SCSI_MEDIUM_HAVE_CHANGED 0x28 + +#define SCSI_READ_FORMAT_CAPACITY_DATA_LEN 0x0C +#define SCSI_READ_CAPACITY10_DATA_LEN 0x08 +#define SCSI_MODE_SENSE10_DATA_LEN 0x08 +#define SCSI_MODE_SENSE6_DATA_LEN 0x04 +#define SCSI_REQUEST_SENSE_DATA_LEN 0x12 +#define SCSI_STANDARD_INQUIRY_DATA_LEN 0x24 +#define SCSI_BLKVFY 0x04 + + extern uint32_t SCSI_lba; + extern uint32_t SCSI_blkLen; + + void scsi_inquiry_cmd(uint8_t lun); + void scsi_request_sense_cmd(uint8_t lun); + void scsi_start_stop_unit_cmd(uint8_t lun); + void scsi_mode_sense6_cmd(uint8_t lun); + void scsi_mode_sense10_cmd(uint8_t lun); + void scsi_read_format_capacity_cmd(uint8_t lun); + void scsi_read_capacity10_cmd(uint8_t lun); + void scsi_read10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr); + void scsi_write10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr); + void scsi_test_unit_ready_cmd(uint8_t lun); + void scsi_verify10_cmd(uint8_t lun); + void scsi_format_cmd(uint8_t lun); + void scsi_set_sense_data(uint8_t lun, uint8_t sensKey, uint8_t asc); + void scsi_invalid_cmd(uint8_t lun); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_scsi_data.c b/STM32F1/libraries/USBComposite/usb_scsi_data.c new file mode 100644 index 0000000..a692fd7 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_scsi_data.c @@ -0,0 +1,120 @@ + +#include "usb_scsi.h" + +uint8_t SCSI_page00InquiryData[] = { + 0x00, /* PERIPHERAL QUALIFIER & PERIPHERAL DEVICE TYPE*/ + 0x00, + 0x00, + 0x00, + 0x00 /* Supported Pages 00*/ +}; + +uint8_t SCSI_standardInquiryData[] = { + 0x00, /* Direct Access Device */ + 0x80, /* RMB = 1: Removable Medium */ + 0x02, /* Version: No conformance claim to standard */ + 0x02, + + 36 - 4, /* Additional Length */ + 0x00, /* SCCS = 1: Storage Controller Component */ + 0x00, + 0x00, + /* Vendor Identification */ + 'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', + /* Product Identification */ + 'S', 'D', ' ', 'F', 'l', 'a', 's', 'h', ' ', + 'D', 'i', 's', 'k', ' ', ' ', ' ', + /* Product Revision Level */ + '1', '.', '0', ' ' +}; + +uint8_t SCSI_standardInquiryData2[] = { + 0x00, /* Direct Access Device */ + 0x80, /* RMB = 1: Removable Medium */ + 0x02, /* Version: No conformance claim to standard */ + 0x02, + + 36 - 4, /* Additional Length */ + 0x00, /* SCCS = 1: Storage Controller Component */ + 0x00, + 0x00, + /* Vendor Identification */ + 'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', + /* Product Identification */ + 'N', 'A', 'N', 'D', ' ', 'F', 'l', 'a', 's', 'h', ' ', + 'D', 'i', 's', 'k', ' ', + /* Product Revision Level */ + '1', '.', '0', ' ' +}; + +uint8_t SCSI_senseData[] = { + 0x70, /*RespCode*/ + 0x00, /*SegmentNumber*/ + SCSI_NO_SENSE, /* Sens_Key*/ + 0x00, + 0x00, + 0x00, + 0x00, /*Information*/ + 0x0A, /*AdditionalSenseLength*/ + 0x00, + 0x00, + 0x00, + 0x00, /*CmdInformation*/ + SCSI_NO_SENSE, /*Asc*/ + 0x00, /*ASCQ*/ + 0x00, /*FRUC*/ + 0x00, /*TBD*/ + 0x00, + 0x00 /*SenseKeySpecific*/ +}; + +uint8_t SCSI_modeSense6Data[] = { + 0x03, + 0x00, + 0x00, + 0x00, +}; + +uint8_t SCSI_modeSense10Data[] = { + 0x00, + 0x06, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + +uint8_t SCSI_readFormatCapacityData[] = { + 0x00, + 0x00, + 0x00, + 0x08, /* Capacity List Length */ + + /* Block Count */ + 0, + 0, + 0, + 0, + + /* Block Length */ + 0x02, /* Descriptor Code: Formatted Media */ + 0, + 0, + 0 +}; + +uint8_t SCSI_readFormatCapacity10Data[] = { + /* Last Logical Block */ + 0, + 0, + 0, + 0, + + /* Block Length */ + 0, + 0, + 0, + 0 +}; \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/usb_serial.c b/STM32F1/libraries/USBComposite/usb_serial.c new file mode 100644 index 0000000..390d256 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_serial.c @@ -0,0 +1,580 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usb/stm32f1/usb_hid.c + * @brief USB HID (human interface device) support + * + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. + */ + +#include "usb_serial.h" +#include "usb_generic.h" +#include +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" + +#define CDCACM_ENDPOINT_TX 0 +#define CDCACM_ENDPOINT_MANAGEMENT 1 +#define CDCACM_ENDPOINT_RX 2 + +uint16 GetEPTxAddr(uint8 /*bEpNum*/); + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +static void serialUSBReset(void); +static RESULT serialUSBDataSetup(uint8 request); +static RESULT serialUSBNoDataSetup(uint8 request); +static void vcomDataTxCb(void); +static void vcomDataRxCb(void); + +#define NUM_SERIAL_ENDPOINTS 3 +#define CCI_INTERFACE_OFFSET 0x00 +#define DCI_INTERFACE_OFFSET 0x01 +#define SERIAL_MANAGEMENT_INTERFACE_NUMBER (CCI_INTERFACE_OFFSET+usbSerialPart.startInterface) + +/* + * Descriptors + */ + + +typedef struct { + //CDCACM + IADescriptor IAD; + usb_descriptor_interface CCI_Interface; + CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_IntHeader; + CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_CallManagement; + CDC_FUNCTIONAL_DESCRIPTOR(1) CDC_Functional_ACM; + CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Union; + usb_descriptor_endpoint ManagementEndpoint; + usb_descriptor_interface DCI_Interface; + usb_descriptor_endpoint DataOutEndpoint; + usb_descriptor_endpoint DataInEndpoint; +} __packed serial_part_config; + + +static const serial_part_config serialPartConfigData = { + .IAD = { + .bLength = 0x08, + .bDescriptorType = 0x0B, + .bFirstInterface = CCI_INTERFACE_OFFSET, // PATCH + .bInterfaceCount = 0x02, + .bFunctionClass = 0x02, + .bFunctionSubClass = 0x02, + .bFunctionProtocol = 0x01, + .iFunction = 0x02, + }, + .CCI_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = CCI_INTERFACE_OFFSET, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x01, + .bInterfaceClass = USB_INTERFACE_CLASS_CDC, + .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_CDC_ACM, + .bInterfaceProtocol = 0x01, /* Common AT Commands */ + .iInterface = 0x00, + }, + + .CDC_Functional_IntHeader = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), + .bDescriptorType = 0x24, + .SubType = 0x00, + .Data = {0x01, 0x10}, + }, + + .CDC_Functional_CallManagement = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), + .bDescriptorType = 0x24, + .SubType = 0x01, + .Data = {0x03, DCI_INTERFACE_OFFSET}, // PATCH + }, + + .CDC_Functional_ACM = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(1), + .bDescriptorType = 0x24, + .SubType = 0x02, + .Data = {0x06}, + }, + + .CDC_Functional_Union = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), + .bDescriptorType = 0x24, + .SubType = 0x06, + .Data = {CCI_INTERFACE_OFFSET, DCI_INTERFACE_OFFSET}, // PATCH, PATCH + }, + + .ManagementEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | + CDCACM_ENDPOINT_MANAGEMENT), // PATCH + .bmAttributes = USB_EP_TYPE_INTERRUPT, + .wMaxPacketSize = USBHID_CDCACM_MANAGEMENT_EPSIZE, + .bInterval = 0xFF, + }, + + .DCI_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = DCI_INTERFACE_OFFSET, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = USB_INTERFACE_CLASS_DIC, + .bInterfaceSubClass = 0x00, /* None */ + .bInterfaceProtocol = 0x00, /* None */ + .iInterface = 0x00, + }, + + .DataOutEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | + CDCACM_ENDPOINT_RX), // patch + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = USBHID_CDCACM_RX_EPSIZE, + .bInterval = 0x00, + }, + + .DataInEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | CDCACM_ENDPOINT_TX), // PATCH + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = USBHID_CDCACM_TX_EPSIZE, + .bInterval = 0x00, + } +}; + +#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s] + +static USBEndpointInfo serialEndpoints[3] = { + { + .callback = vcomDataTxCb, + .bufferSize = USBHID_CDCACM_TX_EPSIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 1, + }, + { + .callback = NULL, + .bufferSize = USBHID_CDCACM_MANAGEMENT_EPSIZE, + .type = USB_EP_EP_TYPE_INTERRUPT, + .tx = 1, + }, + { + .callback = vcomDataRxCb, + .bufferSize = USBHID_CDCACM_RX_EPSIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 0, + }, +}; + +static void getSerialPartDescriptor(uint8* out) { + memcpy(out, &serialPartConfigData, sizeof(serial_part_config)); + + // patch to reflect where the part goes in the descriptor + OUT_BYTE(serialPartConfigData, ManagementEndpoint.bEndpointAddress) += usbSerialPart.startEndpoint; + OUT_BYTE(serialPartConfigData, DataOutEndpoint.bEndpointAddress) += usbSerialPart.startEndpoint; + OUT_BYTE(serialPartConfigData, DataInEndpoint.bEndpointAddress) += usbSerialPart.startEndpoint; + + OUT_BYTE(serialPartConfigData, IAD.bFirstInterface) += usbSerialPart.startInterface; + OUT_BYTE(serialPartConfigData, CCI_Interface.bInterfaceNumber) += usbSerialPart.startInterface; + OUT_BYTE(serialPartConfigData, DCI_Interface.bInterfaceNumber) += usbSerialPart.startInterface; + OUT_BYTE(serialPartConfigData, CDC_Functional_CallManagement.Data[1]) += usbSerialPart.startInterface; + OUT_BYTE(serialPartConfigData, CDC_Functional_Union.Data[0]) += usbSerialPart.startInterface; + OUT_BYTE(serialPartConfigData, CDC_Functional_Union.Data[1]) += usbSerialPart.startInterface; +} + +USBCompositePart usbSerialPart = { + .numInterfaces = 2, + .numEndpoints = sizeof(serialEndpoints)/sizeof(*serialEndpoints), + .descriptorSize = sizeof(serial_part_config), + .getPartDescriptor = getSerialPartDescriptor, + .usbInit = NULL, + .usbReset = serialUSBReset, + .usbDataSetup = serialUSBDataSetup, + .usbNoDataSetup = serialUSBNoDataSetup, + .endpoints = serialEndpoints +}; + +#define CDC_SERIAL_RX_BUFFER_SIZE 256 // must be power of 2 +#define CDC_SERIAL_RX_BUFFER_SIZE_MASK (CDC_SERIAL_RX_BUFFER_SIZE-1) + +/* Received data */ +static volatile uint8 vcomBufferRx[CDC_SERIAL_RX_BUFFER_SIZE]; +/* Write index to vcomBufferRx */ +static volatile uint32 vcom_rx_head; +/* Read index from vcomBufferRx */ +static volatile uint32 vcom_rx_tail; + +#define CDC_SERIAL_TX_BUFFER_SIZE 256 // must be power of 2 +#define CDC_SERIAL_TX_BUFFER_SIZE_MASK (CDC_SERIAL_TX_BUFFER_SIZE-1) +// Tx data +static volatile uint8 vcomBufferTx[CDC_SERIAL_TX_BUFFER_SIZE]; +// Write index to vcomBufferTx +static volatile uint32 vcom_tx_head; +// Read index from vcomBufferTx +static volatile uint32 vcom_tx_tail; + + + +/* Other state (line coding, DTR/RTS) */ + +static volatile composite_cdcacm_line_coding line_coding = { + /* This default is 115200 baud, 8N1. */ + .dwDTERate = 115200, + .bCharFormat = USBHID_CDCACM_STOP_BITS_1, + .bParityType = USBHID_CDCACM_PARITY_NONE, + .bDataBits = 8, +}; + +/* DTR in bit 0, RTS in bit 1. */ +static volatile uint8 line_dtr_rts = 0; + + +static void (*rx_hook)(unsigned, void*) = 0; +static void (*iface_setup_hook)(unsigned, void*) = 0; + +void composite_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*)) { + if (hook_flags & USBHID_CDCACM_HOOK_RX) { + rx_hook = hook; + } + if (hook_flags & USBHID_CDCACM_HOOK_IFACE_SETUP) { + iface_setup_hook = hook; + } +} + +void composite_cdcacm_putc(char ch) { + while (!composite_cdcacm_tx((uint8*)&ch, 1)) + ; +} + +/* This function is non-blocking. + * + * It copies data from a user buffer into the USB peripheral TX + * buffer, and returns the number of bytes copied. */ +uint32 composite_cdcacm_tx(const uint8* buf, uint32 len) +{ + if (len==0) return 0; // no data to send + + uint32 head = vcom_tx_head; // load volatile variable + uint32 tx_unsent = (head - vcom_tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; + + // We can only put bytes in the buffer if there is place + if (len > (CDC_SERIAL_TX_BUFFER_SIZE-tx_unsent-1) ) { + len = (CDC_SERIAL_TX_BUFFER_SIZE-tx_unsent-1); + } + if (len==0) return 0; // buffer full + + uint16 i; + // copy data from user buffer to USB Tx buffer + for (i=0; i= 0); + + if (usbGenericTransmitting<0) { + vcomDataTxCb(); // initiate data transmission + } + + return len; +} + + + +uint32 composite_cdcacm_data_available(void) { + return (vcom_rx_head - vcom_rx_tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; +} + +uint16 composite_cdcacm_get_pending(void) { + return (vcom_tx_head - vcom_tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; +} + +/* Non-blocking byte receive. + * + * Copies up to len bytes from our private data buffer (*NOT* the PMA) + * into buf and deq's the FIFO. */ +uint32 composite_cdcacm_rx(uint8* buf, uint32 len) +{ + /* Copy bytes to buffer. */ + uint32 n_copied = composite_cdcacm_peek(buf, len); + + /* Mark bytes as read. */ + uint16 tail = vcom_rx_tail; // load volatile variable + tail = (tail + n_copied) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + vcom_rx_tail = tail; // store volatile variable + + uint32 rx_unread = (vcom_rx_head - tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + // If buffer was emptied to a pre-set value, re-enable the RX endpoint + if ( rx_unread <= 64 ) { // experimental value, gives the best performance + usb_set_ep_rx_stat(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].address, USB_EP_STAT_RX_VALID); + } + return n_copied; +} + +/* Non-blocking byte lookahead. + * + * Looks at unread bytes without marking them as read. */ +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; + + if (len > rx_unread) { + len = rx_unread; + } + + for (i = 0; i < len; i++) { + buf[i] = vcomBufferRx[tail]; + tail = (tail + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + } + + return len; +} + +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; + + if (len + offset > rx_unread) { + len = rx_unread - offset; + } + + for (i = 0; i < len; i++) { + buf[i] = vcomBufferRx[tail]; + tail = (tail + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + } + + return len; +} + +/* Roger Clark. Added. for Arduino 1.0 API support of Serial.peek() */ +int composite_cdcacm_peek_char() +{ + if (composite_cdcacm_data_available() == 0) + { + return -1; + } + + return vcomBufferRx[vcom_rx_tail]; +} + +uint8 composite_cdcacm_get_dtr() { + return ((line_dtr_rts & USBHID_CDCACM_CONTROL_LINE_DTR) != 0); +} + +uint8 composite_cdcacm_get_rts() { + return ((line_dtr_rts & USBHID_CDCACM_CONTROL_LINE_RTS) != 0); +} + +void composite_cdcacm_get_line_coding(composite_cdcacm_line_coding *ret) { + ret->dwDTERate = line_coding.dwDTERate; + ret->bCharFormat = line_coding.bCharFormat; + ret->bParityType = line_coding.bParityType; + ret->bDataBits = line_coding.bDataBits; +} + +int composite_cdcacm_get_baud(void) { + return line_coding.dwDTERate; +} + +int composite_cdcacm_get_stop_bits(void) { + return line_coding.bCharFormat; +} + +int composite_cdcacm_get_parity(void) { + return line_coding.bParityType; +} + +int composite_cdcacm_get_n_data_bits(void) { + return line_coding.bDataBits; +} + +/* + * Callbacks + */ +static void vcomDataTxCb(void) +{ + uint32 tail = vcom_tx_tail; // load volatile variable + uint32 tx_unsent = (vcom_tx_head - tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; + if (tx_unsent==0) { + if ( (--usbGenericTransmitting)==0) goto flush_vcom; // no more data to send + return; // it was already flushed, keep Tx endpoint disabled + } + usbGenericTransmitting = 1; + // We can only send up to USBHID_CDCACM_TX_EPSIZE bytes in the endpoint. + if (tx_unsent > USBHID_CDCACM_TX_EPSIZE) { + tx_unsent = USBHID_CDCACM_TX_EPSIZE; + } + // copy the bytes from USB Tx buffer to PMA buffer + uint32 *dst = usb_pma_ptr(usbSerialPart.endpoints[CDCACM_ENDPOINT_TX].pmaAddress); + uint16 tmp = 0; + uint16 val; + unsigned i; + for (i = 0; i < tx_unsent; i++) { + val = vcomBufferTx[tail]; + tail = (tail + 1) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; + if (i&1) { + *dst++ = tmp | (val<<8); + } else { + tmp = val; + } + } + if ( tx_unsent&1 ) { + *dst = tmp; + } + vcom_tx_tail = tail; // store volatile variable +flush_vcom: + // enable Tx endpoint + usb_set_ep_tx_count(usbSerialPart.endpoints[CDCACM_ENDPOINT_TX].address, tx_unsent); + usb_set_ep_tx_stat(usbSerialPart.endpoints[CDCACM_ENDPOINT_TX].address, USB_EP_STAT_TX_VALID); +} + + +static void vcomDataRxCb(void) +{ + uint32 head = vcom_rx_head; // load volatile variable + + uint32 ep_rx_size = usb_get_ep_rx_count(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].address); + // This copy won't overwrite unread bytes as long as there is + // enough room in the USB Rx buffer for next packet + uint32 *src = usb_pma_ptr(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].pmaAddress); + uint16 tmp = 0; + uint8 val; + uint32 i; + for (i = 0; i < ep_rx_size; i++) { + if (i&1) { + val = tmp>>8; + } else { + tmp = *src++; + val = tmp&0xFF; + } + vcomBufferRx[head] = val; + head = (head + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + } + vcom_rx_head = head; // store volatile variable + + uint32 rx_unread = (head - vcom_rx_tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + // only enable further Rx if there is enough room to receive one more packet + if ( rx_unread < (CDC_SERIAL_RX_BUFFER_SIZE-USBHID_CDCACM_RX_EPSIZE) ) { + usb_set_ep_rx_stat(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].address, USB_EP_STAT_RX_VALID); + } + + if (rx_hook) { + rx_hook(USBHID_CDCACM_HOOK_RX, 0); + } +} + +static uint8* vcomGetSetLineCoding(uint16 length) { + if (length == 0) { + pInformation->Ctrl_Info.Usb_wLength = sizeof(struct composite_cdcacm_line_coding); + } + return (uint8*)&line_coding; +} + +static void serialUSBReset(void) { + //VCOM + vcom_rx_head = 0; + vcom_rx_tail = 0; + vcom_tx_head = 0; + vcom_tx_tail = 0; +} + +static RESULT serialUSBDataSetup(uint8 request) { + uint8* (*CopyRoutine)(uint16) = 0; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT) && + pInformation->USBwIndex0 == SERIAL_MANAGEMENT_INTERFACE_NUMBER) { + switch (request) { + case USBHID_CDCACM_GET_LINE_CODING: + CopyRoutine = vcomGetSetLineCoding; + break; + case USBHID_CDCACM_SET_LINE_CODING: + CopyRoutine = vcomGetSetLineCoding; + break; + default: + break; + } + /* Call the user hook. */ + if (iface_setup_hook) { + uint8 req_copy = request; + iface_setup_hook(USBHID_CDCACM_HOOK_IFACE_SETUP, &req_copy); + } + } + + if (CopyRoutine == NULL){ + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +static RESULT serialUSBNoDataSetup(uint8 request) { + RESULT ret = USB_UNSUPPORT; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT) && + pInformation->USBwIndex0 == SERIAL_MANAGEMENT_INTERFACE_NUMBER) { + switch(request) { + case USBHID_CDCACM_SET_COMM_FEATURE: + /* We support set comm. feature, but don't handle it. */ + ret = USB_SUCCESS; + break; + case USBHID_CDCACM_SET_CONTROL_LINE_STATE: + /* Track changes to DTR and RTS. */ + line_dtr_rts = (pInformation->USBwValues.bw.bb0 & + (USBHID_CDCACM_CONTROL_LINE_DTR | + USBHID_CDCACM_CONTROL_LINE_RTS)); + ret = USB_SUCCESS; + break; + } + /* Call the user hook. */ + if (iface_setup_hook) { + uint8 req_copy = request; + iface_setup_hook(USBHID_CDCACM_HOOK_IFACE_SETUP, &req_copy); + } + } + return ret; +} + diff --git a/STM32F1/libraries/USBComposite/usb_serial.h b/STM32F1/libraries/USBComposite/usb_serial.h new file mode 100644 index 0000000..926901b --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_serial.h @@ -0,0 +1,157 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/usb_device.h + * @brief USB Composite with CDC ACM and HID support + * + * IMPORTANT: this API is unstable, and may change without notice. + */ + +#ifndef _USB_SERIAL_H_ +#define _USB_SERIAL_H_ + +#include +#include +#include "usb_generic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern USBCompositePart usbSerialPart; + +/* + * CDC ACM Requests + */ + +#define USBHID_CDCACM_SET_LINE_CODING 0x20 +#define USBHID_CDCACM_GET_LINE_CODING 0x21 +#define USBHID_CDCACM_SET_COMM_FEATURE 0x02 +#define USBHID_CDCACM_SET_CONTROL_LINE_STATE 0x22 +#define USBHID_CDCACM_CONTROL_LINE_DTR (0x01) +#define USBHID_CDCACM_CONTROL_LINE_RTS (0x02) + +#define USBHID_CDCACM_MANAGEMENT_EPSIZE 0x10 +#define USBHID_CDCACM_RX_EPSIZE 0x40 +#define USBHID_CDCACM_TX_EPSIZE 0x40 +/* + * Descriptors, etc. + */ + + + +#define USBHID_CDCACM_CTRL_ENDP 0 + +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +} IADescriptor; + +#define CDC_FUNCTIONAL_DESCRIPTOR_SIZE(DataSize) (3 + DataSize) +#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \ + struct { \ + uint8 bLength; \ + uint8 bDescriptorType; \ + uint8 SubType; \ + uint8 Data[DataSize]; \ + } __packed + +#define USB_DEVICE_CLASS_CDC 0x02 +#define USB_DEVICE_SUBCLASS_CDC 0x00 +#define USB_INTERFACE_CLASS_CDC 0x02 +#define USB_INTERFACE_SUBCLASS_CDC_ACM 0x02 +#define USB_INTERFACE_CLASS_DIC 0x0A + +/* + * CDC ACM interface + */ + +void composite_cdcacm_putc(char ch); +uint32 composite_cdcacm_tx(const uint8* buf, uint32 len); +uint32 composite_cdcacm_rx(uint8* buf, uint32 len); +uint32 composite_cdcacm_peek(uint8* buf, uint32 len); +uint32 composite_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len); + +uint32 composite_cdcacm_data_available(void); /* in RX buffer */ +uint16 composite_cdcacm_get_pending(void); +uint8 usb_is_transmitting(void); + +uint8 composite_cdcacm_get_dtr(void); +uint8 composite_cdcacm_get_rts(void); + +typedef struct composite_cdcacm_line_coding { + uint32 dwDTERate; /* Baud rate */ + +#define USBHID_CDCACM_STOP_BITS_1 0 +#define USBHID_CDCACM_STOP_BITS_1_5 1 +#define USBHID_CDCACM_STOP_BITS_2 2 + uint8 bCharFormat; /* Stop bits */ + +#define USBHID_CDCACM_PARITY_NONE 0 +#define USBHID_CDCACM_PARITY_ODD 1 +#define USBHID_CDCACM_PARITY_EVEN 2 +#define USBHID_CDCACM_PARITY_MARK 3 +#define USBHID_CDCACM_PARITY_SPACE 4 + uint8 bParityType; /* Parity type */ + + uint8 bDataBits; /* Data bits: 5, 6, 7, 8, or 16 */ +} __packed composite_cdcacm_line_coding; + +/* Retrieve a copy of the current line coding structure. */ +void composite_cdcacm_get_line_coding(composite_cdcacm_line_coding*); + +/* Line coding conveniences. */ +int composite_cdcacm_get_baud(void); /* dwDTERate */ +int composite_cdcacm_get_stop_bits(void); /* bCharFormat */ +int composite_cdcacm_get_parity(void); /* bParityType */ +int composite_cdcacm_get_n_data_bits(void); /* bDataBits */ + +/* + * Hack: hooks for bootloader reset signalling + */ + +#define USBHID_CDCACM_HOOK_RX 0x1 +#define USBHID_CDCACM_HOOK_IFACE_SETUP 0x2 + +void composite_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*)); + +static inline __always_inline void composite_cdcacm_remove_hooks(unsigned hook_flags) { + composite_cdcacm_set_hooks(hook_flags, 0); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_setup.cpp b/STM32F1/libraries/USBComposite/usb_setup.cpp new file mode 100644 index 0000000..2136bf0 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_setup.cpp @@ -0,0 +1,61 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +/** + * @file wirish/stm32f1/boards_setup.cpp + * @author Marti Bolivar + * @brief STM32F1 chip setup. + * + * This file controls how init() behaves on the STM32F1. Be very + * careful when changing anything here. Many of these values depend + * upon each other. + */ + +#include "boards_private.h" +#include "USBHID.h" +#include +#include + +#include +#include + +namespace wirish { + namespace priv { + + void board_setup_usb(void) { + //Serial = CompositeSerial; +#ifdef GENERIC_BOOTLOADER + //Reset the USB interface on generic boards - developed by Victor PV + gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_OUTPUT_PP); + gpio_write_bit(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit,0); + + for(volatile unsigned int i=0;i<512;i++);// Only small delay seems to be needed, and USB pins will get configured in Serial.begin + gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_INPUT_FLOATING); +#endif + } + + } +} diff --git a/STM32F1/libraries/USBComposite/usb_x360.c b/STM32F1/libraries/USBComposite/usb_x360.c new file mode 100644 index 0000000..9c5bfd7 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_x360.c @@ -0,0 +1,486 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. + */ + +#include "usb_generic.h" +#include "usb_x360.h" + +#include + +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +typedef enum _HID_REQUESTS +{ + + GET_REPORT = 1, + GET_IDLE, + GET_PROTOCOL, + + SET_REPORT = 9, + SET_IDLE, + SET_PROTOCOL + +} HID_REQUESTS; + +#define USB_ENDPOINT_IN(addr) ((addr) | 0x80) +#define HID_ENDPOINT_INT 1 +#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 + +#define HID_DESCRIPTOR_TYPE 0x21 + +#define REPORT_DESCRIPTOR 0x22 + + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 0x21 + uint8_t versionL; // 0x101 + uint8_t versionH; // 0x101 + uint8_t country; + uint8_t numDesc; + uint8_t desctype; // 0x22 report + uint8_t descLenL; + uint8_t descLenH; +} HIDDescriptor; + +#define X360_INTERFACE_OFFSET 0 +#define X360_INTERFACE_NUMBER (X360_INTERFACE_OFFSET+usbX360Part.startInterface) +#define X360_ENDPOINT_TX 0 +#define X360_ENDPOINT_RX 1 +#define USB_X360_RX_ADDR x360Endpoints[X360_ENDPOINT_RX].pmaAddress +#define USB_X360_TX_ADDR x360Endpoints[X360_ENDPOINT_TX].pmaAddress +#define USB_X360_RX_ENDP x360Endpoints[X360_ENDPOINT_RX].address +#define USB_X360_TX_ENDP x360Endpoints[X360_ENDPOINT_TX].address + +u16 GetEPTxAddr(u8 bEpNum); + +static uint32 ProtocolValue; + +static void x360DataTxCb(void); +static void x360DataRxCb(void); +static void (*x360_rumble_callback)(uint8 left, uint8 right); +static void (*x360_led_callback)(uint8 pattern); + +static void x360Reset(void); +static RESULT x360DataSetup(uint8 request); +static RESULT x360NoDataSetup(uint8 request); +static uint8 *HID_GetProtocolValue(uint16 Length); + +/* + * Descriptors + */ + +#if 0 +const uint8_t hid_report_descriptor[] = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x05, // USAGE (Game Pad) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x3a, // USAGE (Counted Buffer) + 0xa1, 0x02, // COLLECTION (Logical) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x3f, // USAGE (Reserved) + 0x09, 0x3b, // USAGE (Byte Count) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x0c, // USAGE_MINIMUM (Button 12) + 0x29, 0x0f, // USAGE_MAXIMUM (Button 15) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x09, 0x09, // USAGE (Button 9) + 0x09, 0x0a, // USAGE (Button 10) + 0x09, 0x07, // USAGE (Button 7) + 0x09, 0x08, // USAGE (Button 8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x09, 0x05, // USAGE (Button 5) + 0x09, 0x06, // USAGE (Button 6) + 0x09, 0x0b, // USAGE (Button 11) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x04, // USAGE_MAXIMUM (Button 4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x32, // USAGE (Z) + 0x09, 0x35, // USAGE (Rz) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x10, // REPORT_SIZE (16) + 0x16, 0x00, 0x80, // LOGICAL_MINIMUM (-32768) + 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) + 0x36, 0x00, 0x80, // PHYSICAL_MINIMUM (-32768) + 0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x33, // USAGE (Rx) + 0x09, 0x34, // USAGE (Ry) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#endif + +typedef struct { +// usb_descriptor_config_header Config_Header; + usb_descriptor_interface HID_Interface; + uint8 unknown_descriptor1[17]; + usb_descriptor_endpoint DataInEndpoint; + usb_descriptor_endpoint DataOutEndpoint; +} __packed usb_descriptor_config; + + +#define MAX_POWER (100 >> 1) +static const usb_descriptor_config X360Descriptor_Config = +{ +#if 0 + .Config_Header = { + .bLength = sizeof(usb_descriptor_config_header), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = sizeof(usb_descriptor_config),//0, + .bNumInterfaces = 0x01, + .bConfigurationValue = 0x01, + .iConfiguration = 0x00, + .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED), + .bMaxPower = MAX_POWER, + }, +#endif + + .HID_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = X360_INTERFACE_OFFSET, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = 0xFF, + .bInterfaceSubClass = 0x5D, + .bInterfaceProtocol = 0x01, + .iInterface = 0x00, + }, + + .unknown_descriptor1 = { + 17,33,0,1,1,37,129,20,0,0,0,0,19,2,8,0,0, + }, + + .DataInEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | X360_ENDPOINT_TX),//PATCH + .bmAttributes = USB_EP_TYPE_INTERRUPT, + .wMaxPacketSize = 0x20, + .bInterval = 4, + }, + + .DataOutEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | X360_ENDPOINT_RX),//PATCH + .bmAttributes = USB_EP_TYPE_INTERRUPT, + .wMaxPacketSize = 0x20, + .bInterval = 8, + }, +}; + +static USBEndpointInfo x360Endpoints[2] = { + { + .callback = x360DataTxCb, + .bufferSize = 0x20, + .type = USB_EP_EP_TYPE_INTERRUPT, + .tx = 1 + }, + { + .callback = x360DataRxCb, + .bufferSize = 0x20, + .type = USB_EP_EP_TYPE_INTERRUPT, + .tx = 0, + } +}; + +#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s] + +static void getX360PartDescriptor(uint8* out) { + memcpy(out, &X360Descriptor_Config, sizeof(X360Descriptor_Config)); + // patch to reflect where the part goes in the descriptor + OUT_BYTE(X360Descriptor_Config, HID_Interface.bInterfaceNumber) += usbX360Part.startInterface; + OUT_BYTE(X360Descriptor_Config, DataOutEndpoint.bEndpointAddress) += usbX360Part.startEndpoint; + OUT_BYTE(X360Descriptor_Config, DataInEndpoint.bEndpointAddress) += usbX360Part.startEndpoint; +} + +USBCompositePart usbX360Part = { + .numInterfaces = 1, + .numEndpoints = sizeof(x360Endpoints)/sizeof(*x360Endpoints), + .descriptorSize = sizeof(X360Descriptor_Config), + .getPartDescriptor = getX360PartDescriptor, + .usbInit = NULL, + .usbReset = x360Reset, + .usbDataSetup = x360DataSetup, + .usbNoDataSetup = x360NoDataSetup, + .endpoints = x360Endpoints +}; + + +/* + * Etc. + */ + +/* I/O state */ + +/* Received data */ +static volatile uint8 hidBufferRx[USB_X360_RX_EPSIZE]; + + +/* Number of bytes left to transmit */ +static volatile uint32 n_unsent_bytes = 0; +/* Are we currently sending an IN packet? */ +static volatile uint8 transmitting = 0; + + +/* + * HID interface + */ + +void x360_set_rumble_callback(void (*callback)(uint8 left, uint8 right)) { + x360_rumble_callback = callback; +} + +void x360_set_led_callback(void (*callback)(uint8 pattern)) { + x360_led_callback = callback; +} + +/*void x360_disable(void) { + x360_set_rumble_callback(NULL); + x360_set_led_callback(NULL); + usb_generic_disable(); +}*/ + +void x360_putc(char ch) { + while (!x360_tx((uint8*)&ch, 1)) + ; +} + + +/* This function is non-blocking. + * + * It copies data from a usercode buffer into the USB peripheral TX + * buffer, and returns the number of bytes copied. */ +uint32 x360_tx(const uint8* buf, uint32 len) { + /* Last transmission hasn't finished, so abort. */ + if (x360_is_transmitting()) { + return 0; + } + + /* We can only put USB_X360_TX_EPSIZE bytes in the buffer. */ + if (len > USB_X360_TX_EPSIZE) { + len = USB_X360_TX_EPSIZE; + } + + /* Queue bytes for sending. */ + if (len) { + usb_copy_to_pma(buf, len, GetEPTxAddr(USB_X360_TX_ENDP));//USB_X360_TX_ADDR); + } + // We still need to wait for the interrupt, even if we're sending + // zero bytes. (Sending zero-size packets is useful for flushing + // host-side buffers.) + usb_set_ep_tx_count(USB_X360_TX_ENDP, len); + n_unsent_bytes = len; + transmitting = 1; + usb_set_ep_tx_stat(USB_X360_TX_ENDP, USB_EP_STAT_TX_VALID); + + return len; +} + +uint8 x360_is_transmitting(void) { + return transmitting; +} + +uint16 x360_get_pending(void) { + return n_unsent_bytes; +} + +static void x360DataRxCb(void) +{ + uint32 ep_rx_size = usb_get_ep_rx_count(USB_X360_RX_ENDP); + // This copy won't overwrite unread bytes as long as there is + // enough room in the USB Rx buffer for next packet + uint32 *src = usb_pma_ptr(USB_X360_RX_ADDR); + uint16 tmp = 0; + uint8 val; + uint32 i; + for (i = 0; i < ep_rx_size; i++) { + if (i&1) { + val = tmp>>8; + } else { + tmp = *src++; + val = tmp&0xFF; + } + hidBufferRx[i] = val; + } + + if (ep_rx_size == 3) { + if (x360_led_callback != NULL && hidBufferRx[0] == 1 && hidBufferRx[1] == 3) + x360_led_callback(hidBufferRx[2]); + } + else if (ep_rx_size == 8) { + if (x360_rumble_callback != NULL && hidBufferRx[0] == 0 && hidBufferRx[1] == 8) + x360_rumble_callback(hidBufferRx[3],hidBufferRx[4]); + } + usb_set_ep_rx_stat(USB_X360_RX_ENDP, USB_EP_STAT_RX_VALID); +} + +/* + * Callbacks + */ + +static void x360DataTxCb(void) { + n_unsent_bytes = 0; + transmitting = 0; +} + +static RESULT x360DataSetup(uint8 request) { + uint8* (*CopyRoutine)(uint16) = 0; + +#if 0 + if (request == GET_DESCRIPTOR + && pInformation->USBwIndex0 == X360_INTERFACE_NUMBER && + && (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) + && (pInformation->USBwIndex0 == 0)){ + if (pInformation->USBwValue1 == REPORT_DESCRIPTOR){ + CopyRoutine = HID_GetReportDescriptor; + } else + if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE){ + CopyRoutine = HID_GetHIDDescriptor; + } + + } /* End of GET_DESCRIPTOR */ + /*** GET_PROTOCOL ***/ + else +#endif + if(pInformation->USBwIndex0 == X360_INTERFACE_NUMBER && + (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + && request == GET_PROTOCOL){ + CopyRoutine = HID_GetProtocolValue; + } + + if (CopyRoutine == NULL){ + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +static RESULT x360NoDataSetup(uint8 request) { + if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + && (request == SET_PROTOCOL)){ + uint8 wValue0 = pInformation->USBwValue0; + ProtocolValue = wValue0; + return USB_SUCCESS; + }else{ + return USB_UNSUPPORT; + } +} + +static uint8* HID_GetProtocolValue(uint16 Length){ + if (Length == 0){ + pInformation->Ctrl_Info.Usb_wLength = 1; + return NULL; + } else { + return (uint8 *)(&ProtocolValue); + } +} + +static void x360Reset(void) { + /* Reset the RX/TX state */ + n_unsent_bytes = 0; + transmitting = 0; +} \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/usb_x360.h b/STM32F1/libraries/USBComposite/usb_x360.h new file mode 100644 index 0000000..7d2d3e1 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_x360.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#ifndef _USB_X360_H +#define _USB_X360_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Descriptors, etc. + */ + +//extern const uint8_t hid_report_descriptor[]; + +/* + * Endpoint configuration + */ + +#define USB_X360_TX_EPSIZE 0x20 +#define USB_X360_RX_EPSIZE 0x20 + +/* + * HID interface + */ + +extern USBCompositePart usbX360Part; +void x360_enable(); +void x360_disable(); + +void x360_putc(char ch); +uint32 x360_tx(const uint8* buf, uint32 len); +uint32 x360_rx(uint8* buf, uint32 len); +uint32 x360_hid_peek(uint8* buf, uint32 len); +uint32 x360_data_available(void); /* in RX buffer */ +uint16 x360_get_pending(void); +uint8 x360_is_transmitting(void); +void x360_set_rx_callback(void (*callback)(const uint8* buffer, uint32 size)); +void x360_set_rumble_callback(void (*callback)(uint8 left, uint8 right)); +void x360_set_led_callback(void (*callback)(uint8 pattern)); + +#ifdef __cplusplus +} +#endif + +#endif