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