Subversion Repositories svn.mios32

Rev

Rev 217 | Rev 230 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
32 tk 1
// $Id: mios32_midi.c 225 2008-12-31 00:50:15Z tk $
211 tk 2
//! \defgroup MIOS32_MIDI
3
//!
4
//! MIDI layer functions for MIOS32
5
//!
6
//! the mios32_midi_package_t format complies with USB MIDI spec (details see there)
7
//! and is used for transfers between other MIDI ports as well.
8
//!
9
//! \{
10
/* ==========================================================================
32 tk 11
 *
12
 *  Copyright (C) 2008 Thorsten Klose (tk@midibox.org)
13
 *  Licensed for personal non-commercial use only.
14
 *  All other rights reserved.
15
 *
16
 * ==========================================================================
17
 */
18
 
19
/////////////////////////////////////////////////////////////////////////////
20
// Include files
21
/////////////////////////////////////////////////////////////////////////////
22
 
23
#include <mios32.h>
24
 
25
// this module can be optionally disabled in a local mios32_config.h file (included from mios32.h)
26
#if !defined(MIOS32_DONT_USE_MIDI)
27
 
28
 
29
/////////////////////////////////////////////////////////////////////////////
30
// Global variables
31
/////////////////////////////////////////////////////////////////////////////
32
 
211 tk 33
//! this global array is read from MIOS32_IIC_MIDI and MIOS32_UART_MIDI to
34
//! determine the number of MIDI bytes which are part of a package
80 tk 35
const u8 mios32_midi_pcktype_num_bytes[16] = {
36
  0, // 0: invalid/reserved event
37
  0, // 1: invalid/reserved event
38
  2, // 2: two-byte system common messages like MTC, Song Select, etc.
39
  3, // 3: three-byte system common messages like SPP, etc.
40
  3, // 4: SysEx starts or continues
41
  1, // 5: Single-byte system common message or sysex sends with following single byte
42
  2, // 6: SysEx sends with following two bytes
43
  3, // 7: SysEx sends with following three bytes
44
  3, // 8: Note Off
45
  3, // 9: Note On
46
  3, // a: Poly-Key Press
47
  3, // b: Control Change
48
  2, // c: Program Change
49
  2, // d: Channel Pressure
50
  3, // e: PitchBend Change
51
  1  // f: single byte
52
};
32 tk 53
 
211 tk 54
//! Number if expected bytes for a common MIDI event - 1
89 tk 55
const u8 mios32_midi_expected_bytes_common[8] = {
56
  2, // Note On
57
  2, // Note Off
58
  2, // Poly Preasure
59
  2, // Controller
60
  1, // Program Change
61
  1, // Channel Preasure
62
  2, // Pitch Bender
63
  0, // System Message - must be zero, so that mios32_midi_expected_bytes_system[] will be used
64
};
80 tk 65
 
211 tk 66
//! Number if expected bytes for a system MIDI event - 1
89 tk 67
const u8 mios32_midi_expected_bytes_system[16] = {
68
  1, // SysEx Begin (endless until SysEx End F7)
69
  1, // MTC Data frame
70
  2, // Song Position
71
  1, // Song Select
72
  0, // Reserved
73
  0, // Reserved
74
  0, // Request Tuning Calibration
75
  0, // SysEx End
76
 
77
  // Note: just only for documentation, Realtime Messages don't change the running status
78
  0, // MIDI Clock
79
  0, // MIDI Tick
80
  0, // MIDI Start
81
  0, // MIDI Continue
82
  0, // MIDI Stop
83
  0, // Reserved
84
  0, // Active Sense
85
  0, // Reset
86
};
87
 
225 tk 88
//! should only be used by MIOS32 internally and by the Bootloader!
89
const u8 mios32_midi_sysex_header[5] = { 0xf0, 0x00, 0x00, 0x7e, 0x32 };
89 tk 90
 
225 tk 91
 
32 tk 92
/////////////////////////////////////////////////////////////////////////////
225 tk 93
// Local types
94
/////////////////////////////////////////////////////////////////////////////
95
 
96
typedef union {
97
  struct {
98
    unsigned ALL:8;
99
  };
100
 
101
  struct {
102
    unsigned CTR:3;
103
    unsigned CMD:1;
104
    unsigned MY_SYSEX:1;
105
  };
106
} sysex_state_t;
107
 
108
 
109
/////////////////////////////////////////////////////////////////////////////
32 tk 110
// Local variables
111
/////////////////////////////////////////////////////////////////////////////
112
 
225 tk 113
static mios32_midi_port_t default_port = MIOS32_MIDI_DEFAULT_PORT;
114
 
155 tk 115
static void (*direct_rx_callback_func)(mios32_midi_port_t port, u8 midi_byte);
116
static void (*direct_tx_callback_func)(mios32_midi_port_t port, u8 midi_byte);
32 tk 117
 
225 tk 118
static sysex_state_t sysex_state;
119
static u8 sysex_device_id;
120
static u8 sysex_cmd;
121
static mios32_midi_port_t last_sysex_port = DEFAULT;
155 tk 122
 
225 tk 123
 
32 tk 124
/////////////////////////////////////////////////////////////////////////////
225 tk 125
// Local prototypes
126
/////////////////////////////////////////////////////////////////////////////
127
 
128
static s32 MIOS32_MIDI_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in);
129
static s32 MIOS32_MIDI_SYSEX_CmdFinished(void);
130
static s32 MIOS32_MIDI_SYSEX_Cmd(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in);
131
static s32 MIOS32_MIDI_SYSEX_Cmd_Reset(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in);
132
static s32 MIOS32_MIDI_SYSEX_Cmd_Ping(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in);
133
static s32 MIOS32_MIDI_SYSEX_SendAck(mios32_midi_port_t port, u8 ack_code, u8 ack_arg);
134
 
135
 
136
/////////////////////////////////////////////////////////////////////////////
211 tk 137
//! Initializes MIDI layer
138
//! \param[in] mode currently only mode 0 supported
139
//! \return < 0 if initialisation failed
32 tk 140
/////////////////////////////////////////////////////////////////////////////
141
s32 MIOS32_MIDI_Init(u32 mode)
142
{
143
  s32 ret = 0;
144
 
110 tk 145
  // currently only mode 0 supported
146
  if( mode != 0 )
32 tk 147
    return -1; // unsupported mode
148
 
225 tk 149
  // set default port as defined in mios32.h/mios32_config.h
150
  default_port = MIOS32_MIDI_DEFAULT_PORT;
151
 
155 tk 152
  // disable Rx/Tx callback functions
153
  direct_rx_callback_func = NULL;
154
  direct_tx_callback_func = NULL;
155
 
156
  // initialize interfaces
101 tk 157
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
110 tk 158
  if( MIOS32_USB_MIDI_Init(0) < 0 )
32 tk 159
    ret |= (1 << 0);
160
#endif
161
 
80 tk 162
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
110 tk 163
  if( MIOS32_UART_MIDI_Init(0) < 0 )
80 tk 164
    ret |= (1 << 1);
165
#endif
166
 
78 tk 167
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
110 tk 168
  if( MIOS32_IIC_MIDI_Init(0) < 0 )
80 tk 169
    ret |= (1 << 2);
78 tk 170
#endif
171
 
225 tk 172
  last_sysex_port = DEFAULT;
173
  sysex_state.ALL = 0;
174
 
175
  // TODO: allow to change device ID (read from flash, resp. BSL based EEPROM emulation)
176
  sysex_device_id = 0x00;
177
 
32 tk 178
  return -ret;
179
}
180
 
181
 
182
/////////////////////////////////////////////////////////////////////////////
211 tk 183
//! This function checks the availability of a MIDI port
184
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
185
//! \return 1: port available
186
//! \return 0: port not available
78 tk 187
/////////////////////////////////////////////////////////////////////////////
188
s32 MIOS32_MIDI_CheckAvailable(mios32_midi_port_t port)
189
{
190
  // if default port: select mapped port
191
  if( !(port & 0xf0) ) {
225 tk 192
    port = default_port;
78 tk 193
  }
194
 
195
  // branch depending on selected port
196
  switch( port >> 4 ) {
197
    case 1:
198
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
199
      return MIOS32_USB_MIDI_CheckAvailable();
200
#else
201
      return 0; // USB has been disabled
202
#endif
203
 
204
    case 2:
80 tk 205
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
206
      return MIOS32_UART_MIDI_CheckAvailable(port & 0xf);
207
#else
208
      return 0; // UART_MIDI has been disabled
209
#endif
78 tk 210
 
211
    case 3:
212
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
213
      return MIOS32_IIC_MIDI_CheckAvailable(port & 0xf);
214
#else
215
      return 0; // IIC_MIDI has been disabled
216
#endif
217
 
218
    case 4:
219
      return 0; // Ethernet not implemented yet
220
 
221
    default:
222
      // invalid port
223
      return 0;
224
  }
225
}
226
 
227
 
228
/////////////////////////////////////////////////////////////////////////////
211 tk 229
//! Sends a package over given port
230
//! This is a low level function. In difference to other MIOS32_MIDI_Send* functions,
231
//! It allows to send packages in non-blocking mode (caller has to retry if -2 is returned)
232
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
233
//! \param[in] package MIDI package
234
//! \return -1 if port not available
235
//! \return -2 buffer is full
236
//!         caller should retry until buffer is free again
237
//! \return 0 on success
110 tk 238
/////////////////////////////////////////////////////////////////////////////
239
s32 MIOS32_MIDI_SendPackage_NonBlocking(mios32_midi_port_t port, mios32_midi_package_t package)
240
{
241
  // if default port: select mapped port
242
  if( !(port & 0xf0) ) {
225 tk 243
    port = default_port;
110 tk 244
  }
245
 
246
  // insert subport number into package
247
  package.cable = port & 0xf;
248
 
249
  // branch depending on selected port
250
  switch( port >> 4 ) {
251
    case 1:
252
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 253
      return MIOS32_USB_MIDI_PackageSend_NonBlocking(package);
110 tk 254
#else
255
      return -1; // USB has been disabled
256
#endif
257
 
258
    case 2:
259
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
260
      return MIOS32_UART_MIDI_PackageSend_NonBlocking(package.cable, package);
261
#else
262
      return -1; // UART_MIDI has been disabled
263
#endif
264
 
265
    case 3:
266
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
267
      return MIOS32_IIC_MIDI_PackageSend_NonBlocking(package.cable, package);
268
#else
269
      return -1; // IIC_MIDI has been disabled
270
#endif
271
 
272
    case 4:
273
      return -1; // Ethernet not implemented yet
274
 
275
    default:
276
      // invalid port
277
      return -1;
278
  }
279
}
280
 
281
 
282
/////////////////////////////////////////////////////////////////////////////
211 tk 283
//! Sends a package over given port
284
//! This is a low level function - use the remaining MIOS32_MIDI_Send* functions
285
//! to send specific MIDI events
286
//! (blocking function)
287
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
288
//! \param[in] package MIDI package
289
//! \return -1 if port not available
290
//! \return 0 on success
32 tk 291
/////////////////////////////////////////////////////////////////////////////
69 tk 292
s32 MIOS32_MIDI_SendPackage(mios32_midi_port_t port, mios32_midi_package_t package)
32 tk 293
{
80 tk 294
  // if default port: select mapped port
295
  if( !(port & 0xf0) ) {
225 tk 296
    port = default_port;
80 tk 297
  }
298
 
32 tk 299
  // insert subport number into package
89 tk 300
  package.cable = port & 0xf;
32 tk 301
 
302
  // branch depending on selected port
303
  switch( port >> 4 ) {
80 tk 304
    case 1:
78 tk 305
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 306
      return MIOS32_USB_MIDI_PackageSend(package);
32 tk 307
#else
308
      return -1; // USB has been disabled
309
#endif
310
 
80 tk 311
    case 2:
312
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
313
      return MIOS32_UART_MIDI_PackageSend(package.cable, package);
314
#else
315
      return -1; // UART_MIDI has been disabled
316
#endif
32 tk 317
 
80 tk 318
    case 3:
78 tk 319
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
320
      return MIOS32_IIC_MIDI_PackageSend(package.cable, package);
321
#else
322
      return -1; // IIC_MIDI has been disabled
323
#endif
32 tk 324
 
80 tk 325
    case 4:
32 tk 326
      return -1; // Ethernet not implemented yet
327
 
328
    default:
329
      // invalid port
330
      return -1;
331
  }
332
}
333
 
334
 
335
/////////////////////////////////////////////////////////////////////////////
211 tk 336
//! Sends a MIDI Event
337
//! This function is provided for a more comfortable use model
338
//!    o MIOS32_MIDI_SendNoteOff(port, chn, note, vel)
339
//!    o MIOS32_MIDI_SendNoteOn(port, chn, note, vel)
340
//!    o MIOS32_MIDI_SendPolyAftertouch(port, chn, note, val)
341
//!    o MIOS32_MIDI_SendCC(port, chn, cc, val)
342
//!    o MIOS32_MIDI_SendProgramChange(port, chn, prg)
343
//!    o MIOS32_MIDI_ChannelAftertouch(port, chn, val)
344
//!    o MIOS32_MIDI_PitchBend(port, chn, val)
345
//!
346
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
347
//! \param[in] evnt0 first MIDI byte
225 tk 348
//! \param[in] evnt1 second MIDI byte
349
//! \param[in] evnt2 third MIDI byte
211 tk 350
//! \return -1 if port not available
351
//! \return 0 on success
32 tk 352
/////////////////////////////////////////////////////////////////////////////
69 tk 353
s32 MIOS32_MIDI_SendEvent(mios32_midi_port_t port, u8 evnt0, u8 evnt1, u8 evnt2)
32 tk 354
{
33 tk 355
  mios32_midi_package_t package;
356
 
357
  // MEMO: don't optimize this function by calling MIOS32_MIDI_SendSpecialEvent
358
  // from here, because the 4 * u8 parameter list of this function leads
359
  // to best compile results (4*u8 combined to a single u32)
360
 
361
  package.type  = evnt0 >> 4;
362
  package.evnt0 = evnt0;
363
  package.evnt1 = evnt1;
364
  package.evnt2 = evnt2;
365
  return MIOS32_MIDI_SendPackage(port, package);
32 tk 366
}
367
 
69 tk 368
s32 MIOS32_MIDI_SendNoteOff(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 vel)
136 tk 369
{ return MIOS32_MIDI_SendEvent(port, 0x80 | chn, note, vel); }
32 tk 370
 
69 tk 371
s32 MIOS32_MIDI_SendNoteOn(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 vel)
136 tk 372
{ return MIOS32_MIDI_SendEvent(port, 0x90 | chn, note, vel); }
69 tk 373
 
374
s32 MIOS32_MIDI_SendPolyPressure(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 val)
136 tk 375
{ return MIOS32_MIDI_SendEvent(port, 0xa0 | chn, note, val); }
69 tk 376
 
377
s32 MIOS32_MIDI_SendCC(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 cc, u8 val)
136 tk 378
{ return MIOS32_MIDI_SendEvent(port, 0xb0 | chn, cc,   val); }
69 tk 379
 
380
s32 MIOS32_MIDI_SendProgramChange(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 prg)
136 tk 381
{ return MIOS32_MIDI_SendEvent(port, 0xc0 | chn, prg,  0x00); }
69 tk 382
 
383
s32 MIOS32_MIDI_SendAftertouch(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 val)
136 tk 384
{ return MIOS32_MIDI_SendEvent(port, 0xd0 | chn, val,  0x00); }
69 tk 385
 
386
s32 MIOS32_MIDI_SendPitchBend(mios32_midi_port_t port, mios32_midi_chn_t chn, u16 val)
136 tk 387
{ return MIOS32_MIDI_SendEvent(port, 0xe0 | chn, val & 0x7f, val >> 7); }
69 tk 388
 
389
 
33 tk 390
/////////////////////////////////////////////////////////////////////////////
211 tk 391
//! Sends a special type MIDI Event
392
//! This function is provided for a more comfortable use model
393
//! It is aliased to following functions
394
//!    o MIOS32_MIDI_SendMTC(port, val)
395
//!    o MIOS32_MIDI_SendSongPosition(port, val)
396
//!    o MIOS32_MIDI_SendSongSelect(port, val)
397
//!    o MIOS32_MIDI_SendTuneRequest()
398
//!    o MIOS32_MIDI_SendClock()
399
//!    o MIOS32_MIDI_SendTick()
400
//!    o MIOS32_MIDI_SendStart()
401
//!    o MIOS32_MIDI_SendStop()
402
//!    o MIOS32_MIDI_SendContinue()
403
//!    o MIOS32_MIDI_SendActiveSense()
404
//!    o MIOS32_MIDI_SendReset()
405
//!
406
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
407
//! \param[in] type the event type
408
//! \param[in] evnt0 first MIDI byte
225 tk 409
//! \param[in] evnt1 second MIDI byte
410
//! \param[in] evnt2 third MIDI byte
211 tk 411
//! \return -1 if port not available
412
//! \return 0 on success
33 tk 413
/////////////////////////////////////////////////////////////////////////////
69 tk 414
s32 MIOS32_MIDI_SendSpecialEvent(mios32_midi_port_t port, u8 type, u8 evnt0, u8 evnt1, u8 evnt2)
33 tk 415
{
416
  mios32_midi_package_t package;
417
 
418
  package.type  = type;
419
  package.evnt0 = evnt0;
420
  package.evnt1 = evnt1;
421
  package.evnt2 = evnt2;
422
  return MIOS32_MIDI_SendPackage(port, package);
423
}
424
 
425
 
69 tk 426
s32 MIOS32_MIDI_SendMTC(mios32_midi_port_t port, u8 val)
136 tk 427
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x2, 0xf1, val, 0x00); }
69 tk 428
 
429
s32 MIOS32_MIDI_SendSongPosition(mios32_midi_port_t port, u16 val)
136 tk 430
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x3, 0xf2, val & 0x7f, val >> 7); }
69 tk 431
 
432
s32 MIOS32_MIDI_SendSongSelect(mios32_midi_port_t port, u8 val)
136 tk 433
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x2, 0xf3, val, 0x00); }
69 tk 434
 
435
s32 MIOS32_MIDI_SendTuneRequest(mios32_midi_port_t port)
136 tk 436
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf6, 0x00, 0x00); }
69 tk 437
 
438
s32 MIOS32_MIDI_SendClock(mios32_midi_port_t port)
136 tk 439
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf8, 0x00, 0x00); }
69 tk 440
 
441
s32 MIOS32_MIDI_SendTick(mios32_midi_port_t port)
136 tk 442
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf9, 0x00, 0x00); }
69 tk 443
 
444
s32 MIOS32_MIDI_SendStart(mios32_midi_port_t port)
136 tk 445
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfa, 0x00, 0x00); }
69 tk 446
 
447
s32 MIOS32_MIDI_SendStop(mios32_midi_port_t port)
136 tk 448
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfb, 0x00, 0x00); }
69 tk 449
 
450
s32 MIOS32_MIDI_SendContinue(mios32_midi_port_t port)
136 tk 451
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfc, 0x00, 0x00); }
69 tk 452
 
453
s32 MIOS32_MIDI_SendActiveSense(mios32_midi_port_t port)
136 tk 454
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfe, 0x00, 0x00); }
69 tk 455
 
456
s32 MIOS32_MIDI_SendReset(mios32_midi_port_t port)
136 tk 457
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xff, 0x00, 0x00); }
69 tk 458
 
459
 
33 tk 460
/////////////////////////////////////////////////////////////////////////////
211 tk 461
//! Sends a SysEx Stream
462
//! This function is provided for a more comfortable use model
463
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
464
//! \param[in] stream pointer to SysEx stream
465
//! \param[in] count number of bytes
466
//! \return -1 if port not available
467
//! \return 0 on success
33 tk 468
/////////////////////////////////////////////////////////////////////////////
69 tk 469
s32 MIOS32_MIDI_SendSysEx(mios32_midi_port_t port, u8 *stream, u32 count)
33 tk 470
{
471
  s32 res;
472
  u32 offset;
473
  mios32_midi_package_t package;
474
 
475
  // MEMO: have a look into the project.lss file - gcc optimizes this code pretty well :)
476
 
477
  for(offset=0; offset<count;) {
478
    // package type depends on number of remaining bytes
479
    switch( count-offset ) {
480
      case 1:
481
    package.type = 0x5; // SysEx ends with following single byte. 
482
    package.evnt0 = stream[offset++];
483
    package.evnt1 = 0x00;
484
    package.evnt2 = 0x00;
485
    break;
486
      case 2:
487
    package.type = 0x6; // SysEx ends with following two bytes.
488
    package.evnt0 = stream[offset++];
489
    package.evnt1 = stream[offset++];
490
    package.evnt2 = 0x00;
491
    break;
492
      case 3:
493
    package.type = 0x7; // SysEx ends with following three bytes. 
494
    package.evnt0 = stream[offset++];
495
    package.evnt1 = stream[offset++];
496
    package.evnt2 = stream[offset++];
497
    break;
498
      default:
499
    package.type = 0x4; // SysEx starts or continues
500
    package.evnt0 = stream[offset++];
501
    package.evnt1 = stream[offset++];
502
    package.evnt2 = stream[offset++];
503
    }
504
 
110 tk 505
    res=MIOS32_MIDI_SendPackage(port, package);
33 tk 506
 
110 tk 507
    // expection? (e.g., port not available)
33 tk 508
    if( res < 0 )
509
      return res;
510
  }
511
 
512
  return 0;
513
}
514
 
515
 
516
/////////////////////////////////////////////////////////////////////////////
211 tk 517
//! Checks for incoming MIDI messages, calls either the callback_event or
518
//! callback_sysex function with following parameters:
519
//! \code
520
//!    callback_event(mios32_midi_port_t port, mios32_midi_package_t midi_package)
521
//!    callback_sysex(mios32_midi_port_t port, u8 sysex_byte)
522
//! \endcode
523
//! \return < 0 on errors
33 tk 524
/////////////////////////////////////////////////////////////////////////////
525
s32 MIOS32_MIDI_Receive_Handler(void *_callback_event, void *_callback_sysex)
526
{
527
  u8 port;
528
  mios32_midi_package_t package;
529
 
69 tk 530
  void (*callback_event)(mios32_midi_port_t port, mios32_midi_package_t midi_package) = _callback_event;
531
  void (*callback_sysex)(mios32_midi_port_t port, u8 sysex_byte) = _callback_sysex;
33 tk 532
 
78 tk 533
  u8 intf = 0; // interface to be checked
534
  u8 total_packages_forwarded = 0; // number of forwards - stop after 10 forwards to yield some CPU time for other tasks
535
  u8 packages_forwarded = 0;
536
  u8 again = 1;
33 tk 537
  do {
78 tk 538
    // Round Robin
539
    // TODO: maybe a list based approach would be better
540
    // it would allow to add/remove interfaces dynamically
541
    // this would also allow to give certain ports a higher priority (to add them multiple times to the list)
542
    // it would also improve this spagetthi code ;)
543
    s32 error = -1;
544
    switch( intf++ ) {
545
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 546
      case 0: error = MIOS32_USB_MIDI_PackageReceive(&package); port = USB0 + package.cable; break;
78 tk 547
#else
548
      case 0: error = -1; break;
549
#endif
126 tk 550
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART0_ASSIGNMENT == 1
80 tk 551
      case 1: error = MIOS32_UART_MIDI_PackageReceive(0, &package); port = UART0; break;
78 tk 552
#else
553
      case 1: error = -1; break;
554
#endif
126 tk 555
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART1_ASSIGNMENT == 1
80 tk 556
      case 2: error = MIOS32_UART_MIDI_PackageReceive(1, &package); port = UART1; break;
78 tk 557
#else
558
      case 2: error = -1; break;
559
#endif
560
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 561
      case 3: error = MIOS32_IIC_MIDI_PackageReceive(0, &package); port = IIC0; break;
78 tk 562
#else
563
      case 3: error = -1; break;
564
#endif
565
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 566
      case 4: error = MIOS32_IIC_MIDI_PackageReceive(1, &package); port = IIC1; break;
78 tk 567
#else
568
      case 4: error = -1; break;
569
#endif
570
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 571
      case 5: error = MIOS32_IIC_MIDI_PackageReceive(2, &package); port = IIC2; break;
78 tk 572
#else
573
      case 5: error = -1; break;
574
#endif
575
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 576
      case 6: error = MIOS32_IIC_MIDI_PackageReceive(3, &package); port = IIC3; break;
78 tk 577
#else
578
      case 6: error = -1; break;
579
#endif
580
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 581
      case 7: error = MIOS32_IIC_MIDI_PackageReceive(4, &package); port = IIC4; break;
78 tk 582
#else
583
      case 7: error = -1; break;
584
#endif
585
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 586
      case 8: error = MIOS32_IIC_MIDI_PackageReceive(5, &package); port = IIC5; break;
78 tk 587
#else
588
      case 8: error = -1; break;
589
#endif
80 tk 590
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
591
      case 9: error = MIOS32_IIC_MIDI_PackageReceive(6, &package); port = IIC6; break;
592
#else
593
      case 9: error = -1; break;
594
#endif
595
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
596
      case 10: error = MIOS32_IIC_MIDI_PackageReceive(7, &package); port = IIC7; break;
597
#else
598
      case 10: error = -1; break;
599
#endif
78 tk 600
      default:
601
    // allow 10 forwards maximum to yield some CPU time for other tasks
602
    if( packages_forwarded && total_packages_forwarded < 10 ) {
603
      intf = 0; // restart with USB
604
      packages_forwarded = 0; // for checking, if packages still have been forwarded in next round
605
    } else {
606
      again = 0; // no more interfaces to be processed
607
    }
608
    error = -1; // empty round - no message
609
    }
33 tk 610
 
78 tk 611
    // message received?
612
    if( error >= 0 ) {
613
      // notify that a package has been forwarded
614
      ++packages_forwarded;
615
      ++total_packages_forwarded;
33 tk 616
 
78 tk 617
      // remove cable number from package (MIOS32_MIDI passes it's own port number)
69 tk 618
      package.cable = 0;
33 tk 619
 
78 tk 620
      // branch depending on package type
33 tk 621
      if( package.type >= 0x8 ) {
217 tk 622
    if( callback_event != NULL )
623
      callback_event(port, package);
33 tk 624
      } else {
625
    switch( package.type ) {
626
    case 0x0: // reserved, ignore
627
    case 0x1: // cable events, ignore
628
      break;
629
 
630
    case 0x2: // Two-byte System Common messages like MTC, SongSelect, etc. 
631
    case 0x3: // Three-byte System Common messages like SPP, etc. 
217 tk 632
      if( callback_event != NULL )
633
        callback_event(port, package); // -> forwarded as event
33 tk 634
      break;
635
    case 0x4: // SysEx starts or continues (3 bytes)
217 tk 636
      if( callback_sysex != NULL ) {
637
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
638
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
639
        callback_sysex(port, package.evnt2); // -> forwarded as SysEx
640
      }
225 tk 641
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
642
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
643
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt2); // -> forward to MIOS32 SysEx Parser
33 tk 644
      break;
645
    case 0x5: // Single-byte System Common Message or SysEx ends with following single byte. 
217 tk 646
      if( package.evnt0 >= 0xf8 ) {
647
        if( callback_event != NULL )
648
          callback_event(port, package); // -> forwarded as event
649
      } else {
650
        if( callback_sysex != NULL )
651
          callback_sysex(port, package.evnt0); // -> forwarded as SysEx
225 tk 652
        MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
217 tk 653
      }
33 tk 654
      break;
655
    case 0x6: // SysEx ends with following two bytes.
217 tk 656
      if( callback_sysex != NULL ) {
657
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
658
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
659
      }
225 tk 660
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
661
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
33 tk 662
      break;
663
    case 0x7: // SysEx ends with following three bytes.
217 tk 664
      if( callback_sysex != NULL ) {
665
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
666
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
667
        callback_sysex(port, package.evnt2); // -> forwarded as SysEx
668
      }
225 tk 669
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
670
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
671
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt2); // -> forward to MIOS32 SysEx Parser
33 tk 672
      break;
673
    }
674
      }
675
    }
676
  } while( again );
677
 
678
  return 0;
679
}
680
 
681
 
155 tk 682
/////////////////////////////////////////////////////////////////////////////
211 tk 683
//! Installs Rx/Tx callback functions which are executed immediately on each
684
//! incoming/outgoing MIDI byte, partly from interrupt handlers with following
685
//! parameters:
686
//! \code
687
//!    callback_rx(mios32_midi_port_t port, u8 midi_byte);
688
//!    callback_tx(mios32_midi_port_t port, u8 midi_byte);
689
//! \endcode
690
//!
691
//! These functions should be executed so fast as possible. They can be used
692
//! to trigger MIDI Rx/Tx LEDs or to trigger on MIDI clock events. In order to
693
//! avoid MIDI buffer overruns, the max. recommented execution time is 100 uS!
694
//! \return < 0 on errors
155 tk 695
/////////////////////////////////////////////////////////////////////////////
696
s32 MIOS32_MIDI_DirectRxTxCallback_Init(void *callback_rx, void *callback_tx)
697
{
698
  direct_rx_callback_func = callback_rx;
699
  direct_tx_callback_func = callback_tx;
157 tk 700
 
701
  return 0; // no error
155 tk 702
}
703
 
704
 
705
/////////////////////////////////////////////////////////////////////////////
211 tk 706
//! This function is used by MIOS32 internal functions to forward received
707
//! MIDI bytes to the Rx Callback routine
155 tk 708
/////////////////////////////////////////////////////////////////////////////
709
s32 MIOS32_MIDI_SendByteToRxCallback(mios32_midi_port_t port, u8 midi_byte)
710
{
711
  // note: here we could filter the user hook execution on special situations
712
  if( direct_rx_callback_func != NULL )
713
    direct_rx_callback_func(port, midi_byte);
157 tk 714
  return 0; // no error
155 tk 715
}
716
 
717
/////////////////////////////////////////////////////////////////////////////
211 tk 718
//! This function is used by MIOS32 internal functions to forward received
719
//! MIDI packages to the Rx Callback routine (byte by byte)
720
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
212 tk 721
//! \param[in] midi_package MIDI package
211 tk 722
//! \return < 0 on errors
155 tk 723
/////////////////////////////////////////////////////////////////////////////
724
s32 MIOS32_MIDI_SendPackageToRxCallback(mios32_midi_port_t port, mios32_midi_package_t midi_package)
725
{
726
  // note: here we could filter the user hook execution on special situations
727
  if( direct_rx_callback_func != NULL ) {
728
    u8 buffer[3] = {midi_package.evnt0, midi_package.evnt1, midi_package.evnt2};
729
    int len = mios32_midi_pcktype_num_bytes[midi_package.cin];
730
    int i;
731
    for(i=0; i<len; ++i)
732
      direct_rx_callback_func(port, buffer[i]);
733
  }
157 tk 734
  return 0; // no error
155 tk 735
}
736
 
737
/////////////////////////////////////////////////////////////////////////////
211 tk 738
//! This function is used by MIOS32 internal functions to forward received
739
//! MIDI bytes to the Tx Callback routine
740
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
741
//! \param[in] midi_byte MIDI byte
742
//! \return < 0 on errors
155 tk 743
/////////////////////////////////////////////////////////////////////////////
744
s32 MIOS32_MIDI_SendByteToTxCallback(mios32_midi_port_t port, u8 midi_byte)
745
{
746
  // note: here we could filter the user hook execution on special situations
747
  if( direct_tx_callback_func != NULL )
748
    direct_tx_callback_func(port, midi_byte);
157 tk 749
  return 0; // no error
155 tk 750
}
751
 
752
/////////////////////////////////////////////////////////////////////////////
211 tk 753
//! This function is used by MIOS32 internal functions to forward received
754
//! MIDI packages to the Tx Callback routine (byte by byte)
755
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
212 tk 756
//! \param[in] midi_package MIDI package
211 tk 757
//! \return < 0 on errors
155 tk 758
/////////////////////////////////////////////////////////////////////////////
759
s32 MIOS32_MIDI_SendPackageToTxCallback(mios32_midi_port_t port, mios32_midi_package_t midi_package)
760
{
761
  // note: here we could filter the user hook execution on special situations
762
  if( direct_tx_callback_func != NULL ) {
763
    u8 buffer[3] = {midi_package.evnt0, midi_package.evnt1, midi_package.evnt2};
764
    int len = mios32_midi_pcktype_num_bytes[midi_package.cin];
765
    int i;
766
    for(i=0; i<len; ++i)
767
      direct_tx_callback_func(port, buffer[i]);
768
  }
157 tk 769
  return 0; // no error
155 tk 770
}
771
 
225 tk 772
 
773
/////////////////////////////////////////////////////////////////////////////
774
//! This function allows to change the DEFAULT port.<BR>
775
//! The preset which will be used after application reset can be set in
776
//! mios32_config.h via "#define MIOS32_MIDI_DEFAULT_PORT <port>".<BR>
777
//! It's set to USB0 so long not overruled in mios32_config.h
778
//! \param[in] port MIDI port (USB0..USB7, UART0..UART1, IIC0..IIC7)
779
//! \return < 0 on errors
780
/////////////////////////////////////////////////////////////////////////////
781
s32 MIOS32_MIDI_DefaultPortSet(mios32_midi_port_t port)
782
{
783
  if( port == DEFAULT ) // avoid recursion
784
    return -1;
785
 
786
  default_port = port;
787
 
788
  return 0; // no error
789
}
790
 
791
/////////////////////////////////////////////////////////////////////////////
792
//! This function returns the DEFAULT port
793
//! \return the default port
794
/////////////////////////////////////////////////////////////////////////////
795
mios32_midi_port_t MIOS32_MIDI_DefaultPortGet(void)
796
{
797
  return default_port;
798
}
799
 
800
 
801
/////////////////////////////////////////////////////////////////////////////
802
//! This function sets the SysEx Device ID, which is used during parsing
803
//! incoming SysEx Requests to MIOS32<BR>
804
//! It can also be used by an application for additional parsing with the same ID.<BR>
805
//! ID changes will get lost after reset. It can be changed permanently by the
806
//! user via Bootloader Command 0x0c
807
//! \param[in] device_id a new (temporary) device ID (0x00..0x7f)
808
//! \return < 0 on errors
809
/////////////////////////////////////////////////////////////////////////////
810
s32 MIOS32_MIDI_DeviceIDSet(u8 device_id)
811
{
812
  sysex_device_id = device_id & 0x7f;
813
  return 0; // no error
814
}
815
 
816
/////////////////////////////////////////////////////////////////////////////
817
//! This function returns the SysEx Device ID, which is used during parsing
818
//! incoming SysEx Requests to MIOS32<BR>
819
//! It can also be used by an application for additional parsing with the same ID.<BR>
820
//! The initial ID is stored inside the BSL range and will be recovered after
821
//! reset. It can be changed by the user via Bootloader Command 0x0c
822
//! \return SysEx device ID (0x00..0x7f)
823
//! \todo store device ID via BSL based EEPROM emulation
824
/////////////////////////////////////////////////////////////////////////////
825
u8 MIOS32_MIDI_DeviceIDGet(void)
826
{
827
  return sysex_device_id;
828
}
829
 
830
 
831
/////////////////////////////////////////////////////////////////////////////
832
// This function parses an incoming sysex stream for MIOS32 commands
833
/////////////////////////////////////////////////////////////////////////////
834
static s32 MIOS32_MIDI_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in)
835
{
836
  // ignore realtime messages (see MIDI spec - realtime messages can
837
  // always be injected into events/streams, and don't change the running status)
838
  if( midi_in >= 0xf8 )
839
    return 0;
840
 
841
  // TODO: here we could send an error notification, that multiple devices are trying to access the device
842
  if( sysex_state.MY_SYSEX && port != last_sysex_port )
843
    return -1;
844
 
845
  last_sysex_port = port;
846
 
847
  // branch depending on state
848
  if( !sysex_state.MY_SYSEX ) {
849
    if( (sysex_state.CTR < sizeof(mios32_midi_sysex_header) && midi_in != mios32_midi_sysex_header[sysex_state.CTR]) ||
850
    (sysex_state.CTR == sizeof(mios32_midi_sysex_header) && midi_in != sysex_device_id) ) {
851
      // incoming byte doesn't match
852
      MIOS32_MIDI_SYSEX_CmdFinished();
853
    } else {
854
      if( ++sysex_state.CTR > sizeof(mios32_midi_sysex_header) ) {
855
    // complete header received, waiting for data
856
    sysex_state.MY_SYSEX = 1;
857
      }
858
    }
859
  } else {
860
    // check for end of SysEx message or invalid status byte
861
    if( midi_in >= 0x80 ) {
862
      if( midi_in == 0xf7 && sysex_state.CMD ) {
863
        MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_END, midi_in);
864
      }
865
      MIOS32_MIDI_SYSEX_CmdFinished();
866
    } else {
867
      // check if command byte has been received
868
      if( !sysex_state.CMD ) {
869
    sysex_state.CMD = 1;
870
    sysex_cmd = midi_in;
871
    MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN, midi_in);
872
      }
873
      else
874
    MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_CONT, midi_in);
875
    }
876
  }
877
 
878
  return 0; // no error
879
}
880
 
881
 
882
/////////////////////////////////////////////////////////////////////////////
883
// This function is called at the end of a sysex command or on 
884
// an invalid message
885
/////////////////////////////////////////////////////////////////////////////
886
static s32 MIOS32_MIDI_SYSEX_CmdFinished(void)
887
{
888
  // clear all status variables
889
  sysex_state.ALL = 0;
890
  sysex_cmd = 0;
891
 
892
  return 0; // no error
893
}
894
 
895
/////////////////////////////////////////////////////////////////////////////
896
// This function handles the sysex commands
897
/////////////////////////////////////////////////////////////////////////////
898
static s32 MIOS32_MIDI_SYSEX_Cmd(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
899
{
900
  // enter the commands here
901
  switch( sysex_cmd ) {
902
    case 0x00:
903
      MIOS32_MIDI_SYSEX_Cmd_Reset(port, cmd_state, midi_in);
904
      break;
905
    case 0x0f:
906
      MIOS32_MIDI_SYSEX_Cmd_Ping(port, cmd_state, midi_in);
907
      break;
908
    default:
909
#if MIOS32_MIDI_BSL_ENHANCEMENTS
910
      // this compile switch should only be activated for the bootloader!
911
      if( BSL_SYSEX_Cmd(port, cmd_state, midi_in, sysex_cmd) >= 0 )
912
    return 0; // BSL has serviced this command - no error
913
#endif
914
      // unknown command
915
      // TODO: send 0xf7 if merger enabled
916
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_INVALID_COMMAND);
917
      MIOS32_MIDI_SYSEX_CmdFinished();      
918
  }
919
 
920
  return 0; // no error
921
}
922
 
923
 
924
 
925
/////////////////////////////////////////////////////////////////////////////
926
// Command 00: Reset Core
927
/////////////////////////////////////////////////////////////////////////////
928
static s32 MIOS32_MIDI_SYSEX_Cmd_Reset(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
929
{
930
  static u8 unlock_seq_state = 0;
931
 
932
  switch( cmd_state ) {
933
 
934
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
935
      unlock_seq_state = 1;
936
      break;
937
 
938
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
939
      switch( unlock_seq_state ) {
940
        case 1:
941
      unlock_seq_state = (midi_in == 0x55) ? 2 : 0;
942
      break;
943
        case 2:
944
      unlock_seq_state = (midi_in == 0x1a) ? 3 : 0;
945
      break;
946
        case 3:
947
      unlock_seq_state = (midi_in == 0x42) ? 4 : 0;
948
      break;
949
        default:
950
      // too many bytes or wrong sequence... wait for F7
951
      unlock_seq_state = 0;
952
      }
953
      break;
954
 
955
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
956
      // TODO: send 0xf7 if merger enabled
957
 
958
      if( unlock_seq_state != 4 ) {
959
    // wrong unlock sequence received
960
    MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_WRONG_UNLOCK_SEQ);
961
      } else {
962
    // reset core (this will send an upload request)
963
    MIOS32_SYS_Reset();
964
    // at least on STM32 we will never reach this point
965
    // but other core families could contain an empty stumb!
966
      }
967
      break;
968
  }
969
 
970
  return 0; // no error
971
}
972
 
973
/////////////////////////////////////////////////////////////////////////////
974
// Command 0F: Ping (just send back acknowledge)
975
/////////////////////////////////////////////////////////////////////////////
976
static s32 MIOS32_MIDI_SYSEX_Cmd_Ping(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
977
{
978
  switch( cmd_state ) {
979
 
980
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
981
      // nothing to do
982
      break;
983
 
984
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
985
      // nothing to do
986
      break;
987
 
988
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
989
      // TODO: send 0xf7 if merger enabled
990
 
991
      // send acknowledge
992
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_ACK, 0x00);
993
 
994
      break;
995
  }
996
 
997
  return 0; // no error
998
}
999
 
1000
/////////////////////////////////////////////////////////////////////////////
1001
// This function sends a SysEx acknowledge to notify the user about the received command
1002
// expects acknowledge code (e.g. 0x0f for good, 0x0e for error) and additional argument
1003
/////////////////////////////////////////////////////////////////////////////
1004
static s32 MIOS32_MIDI_SYSEX_SendAck(mios32_midi_port_t port, u8 ack_code, u8 ack_arg)
1005
{
1006
  u8 sysex_buffer[32]; // should be enough?
1007
  u8 *sysex_buffer_ptr = &sysex_buffer[0];
1008
  int i;
1009
 
1010
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
1011
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
1012
 
1013
  // device ID
1014
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
1015
 
1016
  // send ack code and argument
1017
  *sysex_buffer_ptr++ = ack_code;
1018
  *sysex_buffer_ptr++ = ack_arg;
1019
 
1020
  // send footer
1021
  *sysex_buffer_ptr++ = 0xf7;
1022
 
1023
  // finally send SysEx stream
1024
  return MIOS32_MIDI_SendSysEx(port, (u8 *)sysex_buffer, (u32)sysex_buffer_ptr - ((u32)&sysex_buffer[0]));
1025
}
1026
 
1027
 
211 tk 1028
//! \}
155 tk 1029
 
32 tk 1030
#endif /* MIOS32_DONT_USE_MIDI */