1+ // Copyright (c) 2015, Gary Grewal
2+ /*
3+ ** Permission to use, copy, modify, and/or distribute this software for
4+ ** any purpose with or without fee is hereby granted, provided that the
5+ ** above copyright notice and this permission notice appear in all copies.
6+ **
7+ ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
8+ ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
9+ ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
10+ ** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
11+ ** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
12+ ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
13+ ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
14+ ** SOFTWARE.
15+ */
16+ #include " PluggableUSB.h"
17+ #include " MIDIUSB.h"
18+
19+ #define MIDI_BUFFER_SIZE 128
20+
21+
22+ static u8 MIDI_AC_INTERFACE; // MIDI AC Interface
23+ static u8 MIDI_INTERFACE;
24+ static u8 MIDI_FIRST_ENDPOINT;
25+ static u8 MIDI_ENDPOINT_OUT;
26+ static u8 MIDI_ENDPOINT_IN;
27+
28+ #define MIDI_RX MIDI_ENDPOINT_OUT
29+ #define MIDI_TX MIDI_ENDPOINT_IN
30+
31+ struct ring_bufferMIDI
32+ {
33+ midiEventPacket_t midiEvent[MIDI_BUFFER_SIZE];
34+ volatile uint32_t head;
35+ volatile uint32_t tail;
36+ };
37+
38+ ring_bufferMIDI midi_rx_buffer = {{0 ,0 ,0 ,0 }, 0 , 0 };
39+
40+ static MIDIDescriptor _midiInterface;
41+
42+ void WEAK setupUSB () {
43+ MidiUSB.begin ();
44+ }
45+
46+ int8_t WEAK MIDI_GetInterface (uint8_t * interfaceNum)
47+ {
48+ interfaceNum[0 ] += 2 ; // uses 2
49+ return USB_SendControl (0 ,&_midiInterface,sizeof (_midiInterface));
50+ }
51+ bool WEAK MIDI_Setup (Setup& setup, u8 i)
52+ {
53+ // Support requests here if needed. Typically these are optional
54+ return false ;
55+ }
56+
57+ int8_t WEAK MIDI_GetDescriptor (int8_t t)
58+ {
59+ return 0 ;
60+ }
61+
62+ void MIDI_::accept (void )
63+ {
64+ // static uint32_t mguard = 0;
65+
66+ // // synchronized access to guard
67+ // do {
68+ // if (__LDREXW(&mguard) != 0) {
69+ // __CLREX();
70+ // return; // busy
71+ // }
72+ // } while (__STREXW(1, &mguard) != 0); // retry until write succeed
73+
74+ // ring_bufferMIDI *buffer = &midi_rx_buffer;
75+ // uint32_t i = (uint32_t)(buffer->head+1) % MIDI_BUFFER_SIZE;
76+
77+ // // if we should be storing the received character into the location
78+ // // just before the tail (meaning that the head would advance to the
79+ // // current location of the tail), we're about to overflow the buffer
80+ // // and so we don't write the character or advance the head.
81+ // while (i != buffer->tail) {
82+ // int c;
83+ // midiEventPacket_t event;
84+ // if (!USB_Available(MIDI_RX)) {
85+ // udd_ack_fifocon(MIDI_RX);
86+ // break;
87+ // }
88+ // c = USB_Recv(MIDI_RX, &event, sizeof(event) );
89+
90+ // //MIDI paacket has to be 4 bytes
91+ // if(c < 4)
92+ // return;
93+ // buffer->midiEvent[buffer->head] = event;
94+ // buffer->head = i;
95+
96+ // i = (i + 1) % MIDI_BUFFER_SIZE;
97+ // }
98+
99+ // // release the guard
100+ // mguard = 0;
101+ }
102+
103+ uint32_t MIDI_::available (void )
104+ {
105+
106+ ring_bufferMIDI *buffer = &midi_rx_buffer;
107+ return (uint32_t )(MIDI_BUFFER_SIZE + buffer->head - buffer->tail ) % MIDI_BUFFER_SIZE;
108+ }
109+
110+
111+ midiEventPacket_t MIDI_::read (void )
112+ {
113+ ring_bufferMIDI *buffer = &midi_rx_buffer;
114+ midiEventPacket_t c = buffer->midiEvent [buffer->tail ];
115+ c.header = 0 ;
116+ c.byte1 = 0 ;
117+ c.byte2 = 0 ;
118+ c.byte3 = 0 ;
119+
120+ // if the head isn't ahead of the tail, we don't have any characters
121+ if (buffer->head == buffer->tail )
122+ {
123+ return c;
124+ }
125+ else
126+ {
127+ midiEventPacket_t c = buffer->midiEvent [buffer->tail ];
128+ buffer->tail = (uint32_t )(buffer->tail + 1 ) % MIDI_BUFFER_SIZE;
129+ if (USB_Available (MIDI_RX))
130+ accept ();
131+ return c;
132+ }
133+ }
134+
135+ void MIDI_::flush (void )
136+ {
137+ USB_Flush (MIDI_TX);
138+ }
139+
140+ size_t MIDI_::write (const uint8_t *buffer, size_t size)
141+ {
142+ /* only try to send bytes if the high-level MIDI connection itself
143+ is open (not just the pipe) - the OS should set lineState when the port
144+ is opened and clear lineState when the port is closed.
145+ bytes sent before the user opens the connection or after
146+ the connection is closed are lost - just like with a UART. */
147+
148+ // TODO - ZE - check behavior on different OSes and test what happens if an
149+ // open connection isn't broken cleanly (cable is yanked out, host dies
150+ // or locks up, or host virtual serial port hangs)
151+
152+ int r = USB_Send (MIDI_TX, buffer, size);
153+
154+ if (r > 0 )
155+ {
156+ return r;
157+ } else
158+ {
159+ return 0 ;
160+ }
161+ return 0 ;
162+ }
163+
164+ void MIDI_::sendMIDI (midiEventPacket_t event)
165+ {
166+ uint8_t data[4 ];
167+ data[0 ] = event.header ;
168+ data[1 ] = event.byte1 ;
169+ data[2 ] = event.byte2 ;
170+ data[3 ] = event.byte3 ;
171+ write (data, 4 );
172+ }
173+
174+ int8_t MIDI_plug (void )
175+ {
176+ PUSBCallbacks cb;
177+
178+ cb.setup = &MIDI_Setup;
179+ cb.getInterface = &MIDI_GetInterface;
180+ cb.getDescriptor = &MIDI_GetDescriptor;
181+ cb.numEndpoints = 2 ;
182+ cb.endpointType [0 ] = EP_TYPE_BULK_OUT_MIDI; // MIDI_ENDPOINT_OUT
183+ cb.endpointType [1 ] = EP_TYPE_BULK_IN_MIDI; // MIDI_ENDPOINT_IN
184+
185+ MIDI_ENDPOINT_OUT = PUSB_AddFunction (&cb, &MIDI_AC_INTERFACE);
186+ MIDI_ENDPOINT_IN = MIDI_ENDPOINT_OUT + 1 ;
187+ MIDI_INTERFACE = MIDI_AC_INTERFACE + 1 ;
188+
189+ _midiInterface =
190+ {
191+ D_IAD (MIDI_AC_INTERFACE, 2 , MIDI_AUDIO, MIDI_AUDIO_CONTROL, 0 ),
192+ D_INTERFACE (MIDI_AC_INTERFACE,0 ,MIDI_AUDIO,MIDI_AUDIO_CONTROL,0 ),
193+ D_AC_INTERFACE (0x1 , MIDI_INTERFACE),
194+ D_INTERFACE (MIDI_INTERFACE,2 , MIDI_AUDIO,MIDI_STREAMING,0 ),
195+ D_AS_INTERFACE,
196+ D_MIDI_INJACK (MIDI_JACK_EMD, 0x1 ),
197+ D_MIDI_INJACK (MIDI_JACK_EXT, 0x2 ),
198+ D_MIDI_OUTJACK (MIDI_JACK_EMD, 0x3 , 1 , 2 , 1 ),
199+ D_MIDI_OUTJACK (MIDI_JACK_EXT, 0x4 , 1 , 1 , 1 ),
200+ D_MIDI_JACK_EP (USB_ENDPOINT_OUT (MIDI_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,512 ),
201+ D_MIDI_AC_JACK_EP (1 , 1 ),
202+ D_MIDI_JACK_EP (USB_ENDPOINT_IN (MIDI_ENDPOINT_IN),USB_ENDPOINT_TYPE_BULK,512 ),
203+ D_MIDI_AC_JACK_EP (1 , 3 )
204+ };
205+
206+ return MIDI_ENDPOINT_IN;
207+ }
208+
209+ int8_t MIDI_::begin ()
210+ {
211+ return MIDI_plug ();
212+ }
213+
214+
215+ MIDI_ MidiUSB;
0 commit comments