My Fork of F401RE-USBHost. Add USBHostMIDI functions (originaled by Kaoru Shoji http://mbed.org/users/kshoji/code/USBHostMIDI/)
Dependents: F401RE-USBHostMIDI_RecieveExample
Fork of F401RE-USBHost by
Revision 18:bac56d0365e1, committed 2014-06-25
- Comitter:
- hsgw
- Date:
- Wed Jun 25 20:48:01 2014 +0000
- Parent:
- 17:4a710e2ba162
- Child:
- 21:b2ca8a816174
- Commit message:
- Add USBHostMIDI(porting https://mbed.org/users/kshoji/code/USBHostMIDI/)
Changed in this revision
--- a/USBHost/USBHostConf.h Mon Jun 23 20:48:53 2014 +0900 +++ b/USBHost/USBHostConf.h Wed Jun 25 20:48:01 2014 +0000 @@ -59,6 +59,11 @@ #define USBHOST_3GMODULE 1 /* +* Enable USBHostMIDI +*/ +#define USBHOST_MIDI 1 + +/* * Maximum number of interfaces of a usb device */ #define MAX_INTF 4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostMIDI/CircBuffer.h Wed Jun 25 20:48:01 2014 +0000 @@ -0,0 +1,80 @@ +/* USBHostMidi library + * Originaled by k.shoji + * porting by Takuya Urakawa + */ + +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CIRCBUFFER_H +#define CIRCBUFFER_H + +#include "stdint.h" + +//circular buffer +template<typename T, int size> +class CircBuffer { +public: + + CircBuffer() { + write = 0; + read = 0; + } + + bool isFull() { + bool r = (((write + 1) % size) == read); + return r; + } + + bool isEmpty() { + bool r = (read == write); + return r; + } + + void flush() { + write = 0; + read = 0; + } + + void queue(T k) { + while (((write + 1) % size) == read) { + wait_ms(10); + } + buf[write++] = k; + write %= size; + } + + uint16_t available() { + uint16_t a = (write >= read) ? (write - read) : (size - read + write); + return a; + } + + bool dequeue(T * c) { + bool empty = (read == write); + if (!empty) { + *c = buf[read++]; + read %= size; + } + return (!empty); + } + +private: + volatile uint16_t write; + volatile uint16_t read; + volatile T buf[size]; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostMIDI/USBHostMIDI.cpp Wed Jun 25 20:48:01 2014 +0000 @@ -0,0 +1,258 @@ +/* USBHostMidi library + * Originaled by k.shoji + * porting by Takuya Urakawa + */ + +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBHostMIDI.h" + +#if USBHOST_MIDI + +#include "dbg.h" + +#define SET_LINE_CODING 0x20 + +USBHostMIDI::USBHostMIDI(): circ_buf() { + host = USBHost::getHostInst(); + size_bulk_in = 0; + size_bulk_out = 0; + init(); +} + +void USBHostMIDI::init() { + dev = NULL; + bulk_in = NULL; + bulk_out = NULL; + dev_connected = false; + midi_intf = -1; + midi_device_found = false; + circ_buf.flush(); +} + +bool USBHostMIDI::connected() +{ + return dev_connected; +} + +bool USBHostMIDI::connect() { + + if (dev_connected) { + return true; + } + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + + USB_DBG("Trying to connect MIDI device\r\n"); + + if(host->enumerate(dev, this)) + break; + + if (midi_device_found) { + bulk_in = dev->getEndpoint(midi_intf, BULK_ENDPOINT, IN); + bulk_out = dev->getEndpoint(midi_intf, BULK_ENDPOINT, OUT); + + if (!bulk_in || !bulk_out) + break; + + USB_INFO("New MIDI device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, midi_intf); + dev->setName("MIDI", midi_intf); + host->registerDriver(dev, midi_intf, this, &USBHostMIDI::init); + + size_bulk_in = bulk_in->getSize(); + size_bulk_out = bulk_out->getSize(); + + bulk_in->attach(this, &USBHostMIDI::rxHandler); + + host->bulkRead(dev, bulk_in, buf, size_bulk_in, false); + dev_connected = true; + return true; + } + } + } + init(); + return false; +} + +void USBHostMIDI::rxHandler() { + uint8_t pos = 0; + uint8_t midi[4]; + if (bulk_in) { + int len = bulk_in->getLengthTransferred(); + if (bulk_in->getState() == USB_TYPE_IDLE || bulk_in->getState() == USB_TYPE_FREE) { + for (int i = 0; i < len; i++) { + circ_buf.queue(buf[i]); + } + + // MIDI event handling + while (!circ_buf.isEmpty()) { + // read each four bytes + circ_buf.dequeue(&midi[pos++]); + if (pos == 4) { + pos = 0; + + // process MIDI message + // switch by code index number + switch (midi[0] & 0xf) { + case 8: + noteOff(midi[1] & 0xf, midi[2], midi[3]); + break; + case 9: + if (midi[3]) { + noteOn(midi[1] & 0xf, midi[2], midi[3]); + } else { + noteOff(midi[1] & 0xf, midi[2], midi[3]); + } + break; + case 11: + controlChange(midi[1] & 0xf, midi[2], midi[3]); + break; + case 12: + programChange(midi[1] & 0xf, midi[2]); + break; + case 14: + pitchBend(midi[1] & 0xf, midi[2] | (midi[3] << 7)); + break; + default: + break; + } + } + } + + host->bulkRead(dev, bulk_in, buf, size_bulk_in, false); + } + } +} + +int USBHostMIDI::sendNoteOn(unsigned char channel, unsigned char note, unsigned char velocity) { + uint8_t midi[4]; + + if (bulk_out) { + midi[0] = 9; + midi[1] = channel & 0xf; + midi[2] = note & 0x7f; + midi[3] = velocity & 0x7f; + if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { + return 1; + } + } + return -1; +} + +int USBHostMIDI::sendNoteOff(unsigned char channel, unsigned char note, unsigned char velocity) { + uint8_t midi[4]; + + if (bulk_out) { + midi[0] = 8; + midi[1] = channel & 0xf; + midi[2] = note & 0x7f; + midi[3] = velocity & 0x7f; + if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { + return 1; + } + } + return -1; +} + +int USBHostMIDI::sendControlChange(unsigned char channel, unsigned char key, unsigned char value) { + uint8_t midi[4]; + + if (bulk_out) { + midi[0] = 11; + midi[1] = channel & 0xf; + midi[2] = key & 0x7f; + midi[3] = value & 0x7f; + if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { + return 1; + } + } + return -1; +} + +int USBHostMIDI::sendProgramChange(unsigned char channel, unsigned char program) { + uint8_t midi[4]; + + if (bulk_out) { + midi[0] = 12; + midi[1] = channel & 0xf; + midi[2] = program & 0x7f; + midi[3] = 0; + if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { + return 1; + } + } + return -1; +} + +int USBHostMIDI::sendPitchBend(unsigned char channel, unsigned int value) { + uint8_t midi[4]; + + if (bulk_out) { + midi[0] = 14; + midi[1] = channel & 0xf; + midi[2] = value & 0x7f; + midi[3] = (value >> 7) & 0x7f; + if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { + return 1; + } + } + return -1; +} + +void USBHostMIDI::poll() +{ + host->poll(); +} + +/*virtual*/ void USBHostMIDI::setVidPid(uint16_t vid, uint16_t pid) +{ + // we don't check VID/PID for this driver +} + +/*virtual*/ bool USBHostMIDI::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + // USB MIDI class/subclass + if ((midi_intf == -1) && + (intf_class == AUDIO_CLASS) && + (intf_subclass == 0x03)) { + midi_intf = intf_nb; + return true; + } + + // vendor specific device + if ((midi_intf == -1) && + (intf_class == 0xff) && + (intf_subclass == 0x03)) { + midi_intf = intf_nb; + return true; + } + + return false; +} + +/*virtual*/ bool USBHostMIDI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + if (intf_nb == midi_intf) { + if (type == BULK_ENDPOINT) { + midi_device_found = true; + return true; + } + } + return false; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostMIDI/USBHostMIDI.h Wed Jun 25 20:48:01 2014 +0000 @@ -0,0 +1,159 @@ +/* USBHostMidi library + * Originaled by k.shoji + * porting by Takuya Urakawa + */ + +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBHOSTMIDI_H +#define USBHOSTMIDI_H + +#include "USBHostConf.h" + +#if USBHOST_MIDI + +#include "USBHost.h" + +// STM nucleo boards do not support mbed-rtos +//#include "MtxCircBuffer.h" +#include "CircBuffer.h" + +/** + * A class to communicate a USB MIDI device + */ +class USBHostMIDI : public IUSBEnumerator { +public: + /** + * Constructor + */ + USBHostMIDI(); + + /** + * Check if a USB MIDI device is connected + * + * @returns true if a midi device is connected + */ + bool connected(); + + /** + * Try to connect a midi device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * Attach a callback called when note on is received + * + * @param ptr function pointer + */ + inline void attachNoteOn(void (*fn)(unsigned char, unsigned char, unsigned char)) { + if (fn != NULL) { + noteOn = fn; + } + } + + /** + * Attach a callback called when note off is received + * + * @param ptr function pointer + */ + inline void attachNoteOff(void (*fn)(unsigned char, unsigned char, unsigned char)) { + if (fn != NULL) { + noteOff = fn; + } + } + + /** + * Attach a callback called when control change is received + * + * @param ptr function pointer + */ + inline void attachControlChange(void (*fn)(unsigned char, unsigned char, unsigned char)) { + if (fn != NULL) { + controlChange = fn; + } + } + + /** + * Attach a callback called when program change is received + * + * @param ptr function pointer + */ + inline void attachProgramChange(void (*fn)(unsigned char, unsigned char)) { + if (fn != NULL) { + programChange = fn; + } + } + + /** + * Attach a callback called when pitch bend is received + * + * @param ptr function pointer + */ + inline void attachPitchBend(void (*fn)(unsigned char, unsigned int)) { + if (fn != NULL) { + pitchBend = fn; + } + } + + int sendNoteOn(unsigned char channel, unsigned char note, unsigned char velocity); + int sendNoteOff(unsigned char channel, unsigned char note, unsigned char velocity); + int sendControlChange(unsigned char channel, unsigned char key, unsigned char value); + int sendProgramChange(unsigned char channel, unsigned char program); + int sendPitchBend(unsigned char channel, unsigned int value); + + void poll(); + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + USBHost * host; + USBDeviceConnected * dev; + USBEndpoint * bulk_in; + USBEndpoint * bulk_out; + uint32_t size_bulk_in; + uint32_t size_bulk_out; + + bool dev_connected; + + void init(); + + CircBuffer<uint8_t, 128> circ_buf; + + uint8_t buf[128]; + + void rxHandler(); + + void (*noteOn)(unsigned char, unsigned char, unsigned char); + void (*noteOff)(unsigned char, unsigned char, unsigned char); + void (*controlChange)(unsigned char, unsigned char, unsigned char); + void (*programChange)(unsigned char, unsigned char); + void (*pitchBend)(unsigned char, unsigned int); + + int midi_intf; + bool midi_device_found; + +}; + +#endif + +#endif