Subversion Repositories svn.mios32

Rev

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