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