Subversion Repositories svn.mios32

Rev

Rev 374 | Rev 397 | 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 376 2009-03-03 00:03:12Z 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
/////////////////////////////////////////////////////////////////////////////
369 tk 601
//! Sends an hex dump (formatted representation of memory content) to the 
602
//! MIOS Terminal in MIOS Studio.
603
//!
604
//! The MIDI port used for debugging (MIDI_DEBUG) can be declared in mios32_config.h:
605
//! \code
606
//!   #define MIOS32_MIDI_DEBUG_PORT USB0
607
//! \endcode
608
//! (USB0 is the default value)
609
//!
610
//! Optionally, the port can be changed during runtime with MIOS32_MIDI_DebugPortSet
611
//! \param[in] *src pointer to memory location which should be dumped
612
//! \param[in] len number of bytes which should be sent
613
//! \return < 0 on errors
614
/////////////////////////////////////////////////////////////////////////////
615
s32 MIOS32_MIDI_SendDebugHexDump(u8 *src, u32 len)
616
{
617
  // check if any byte has to be sent
618
  if( !len )
619
    return 0;
620
 
621
  // send hex dump line by line
370 tk 622
  u8 *src_begin = src;
369 tk 623
  u8 *src_end;
624
  for(src_end=(u8 *)((size_t)src + len - 1); src < src_end;) {
376 tk 625
    u8 buffer[80+5+3+1]; // we need at least 8+2+3*16+2+16+1 chars + 5 for header + 3 for command + F7
369 tk 626
    int i;
627
 
628
    // create SysEx header
629
    u8 *sysex_buffer_ptr = buffer;
630
    for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
631
      *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
632
 
633
    // device ID
634
    *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
635
 
636
    // debug message: ack code
637
    *sysex_buffer_ptr++ = MIOS32_MIDI_SYSEX_DEBUG;
638
 
639
    // command identifier
640
    *sysex_buffer_ptr++ = 0x40; // string
641
 
642
    // build line:
643
    // add source address
374 tk 644
    sprintf((char *)sysex_buffer_ptr, "%08X ", (u32)(src-src_begin));
645
    sysex_buffer_ptr += 9;
369 tk 646
 
647
    // add up to 16 bytes
648
    u8 *src_chars = src; // for later
649
    for(i=0; i<16; ++i) {
374 tk 650
      sprintf((char *)sysex_buffer_ptr, (src <= src_end) ? " %02X" : "   ", *src);
651
      sysex_buffer_ptr += 3;
369 tk 652
 
653
      ++src;
654
    }
655
 
656
    // add two spaces
374 tk 657
    for(i=0; i<2; ++i)
658
      *sysex_buffer_ptr++ = ' ';
369 tk 659
 
660
    // add characters
661
    for(i=0; i<16; ++i) {
662
      if( *src_chars < 32 || *src_chars >= 128 )
374 tk 663
    *sysex_buffer_ptr++ = '.';
369 tk 664
      else
374 tk 665
    *sysex_buffer_ptr++ = *src_chars;
369 tk 666
 
667
      if( src_chars == src_end )
668
    break;
669
 
670
      ++src_chars;
671
    }
672
 
376 tk 673
    // linebreak
674
    *sysex_buffer_ptr++ = '\n';
675
 
369 tk 676
    // add F7
374 tk 677
    *sysex_buffer_ptr++ = 0xf7;
369 tk 678
 
374 tk 679
    s32 status = MIOS32_MIDI_SendSysEx(debug_port, buffer, (u32)(sysex_buffer_ptr-buffer));
369 tk 680
    if( status < 0 )
681
      return status;
682
  }
683
 
684
  return 0; // no error
685
}
686
 
687
 
688
/////////////////////////////////////////////////////////////////////////////
211 tk 689
//! Checks for incoming MIDI messages, calls either the callback_event or
690
//! callback_sysex function with following parameters:
691
//! \code
692
//!    callback_event(mios32_midi_port_t port, mios32_midi_package_t midi_package)
693
//!    callback_sysex(mios32_midi_port_t port, u8 sysex_byte)
694
//! \endcode
695
//! \return < 0 on errors
33 tk 696
/////////////////////////////////////////////////////////////////////////////
697
s32 MIOS32_MIDI_Receive_Handler(void *_callback_event, void *_callback_sysex)
698
{
699
  u8 port;
700
  mios32_midi_package_t package;
701
 
69 tk 702
  void (*callback_event)(mios32_midi_port_t port, mios32_midi_package_t midi_package) = _callback_event;
703
  void (*callback_sysex)(mios32_midi_port_t port, u8 sysex_byte) = _callback_sysex;
33 tk 704
 
78 tk 705
  u8 intf = 0; // interface to be checked
706
  u8 total_packages_forwarded = 0; // number of forwards - stop after 10 forwards to yield some CPU time for other tasks
707
  u8 packages_forwarded = 0;
708
  u8 again = 1;
33 tk 709
  do {
78 tk 710
    // Round Robin
711
    // TODO: maybe a list based approach would be better
712
    // it would allow to add/remove interfaces dynamically
713
    // this would also allow to give certain ports a higher priority (to add them multiple times to the list)
714
    // it would also improve this spagetthi code ;)
715
    s32 error = -1;
716
    switch( intf++ ) {
717
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 718
      case 0: error = MIOS32_USB_MIDI_PackageReceive(&package); port = USB0 + package.cable; break;
78 tk 719
#else
720
      case 0: error = -1; break;
721
#endif
126 tk 722
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART0_ASSIGNMENT == 1
80 tk 723
      case 1: error = MIOS32_UART_MIDI_PackageReceive(0, &package); port = UART0; break;
78 tk 724
#else
725
      case 1: error = -1; break;
726
#endif
126 tk 727
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART1_ASSIGNMENT == 1
80 tk 728
      case 2: error = MIOS32_UART_MIDI_PackageReceive(1, &package); port = UART1; break;
78 tk 729
#else
730
      case 2: error = -1; break;
731
#endif
732
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 733
      case 3: error = MIOS32_IIC_MIDI_PackageReceive(0, &package); port = IIC0; break;
78 tk 734
#else
735
      case 3: error = -1; break;
736
#endif
737
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 738
      case 4: error = MIOS32_IIC_MIDI_PackageReceive(1, &package); port = IIC1; break;
78 tk 739
#else
740
      case 4: error = -1; break;
741
#endif
742
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 743
      case 5: error = MIOS32_IIC_MIDI_PackageReceive(2, &package); port = IIC2; break;
78 tk 744
#else
745
      case 5: error = -1; break;
746
#endif
747
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 748
      case 6: error = MIOS32_IIC_MIDI_PackageReceive(3, &package); port = IIC3; break;
78 tk 749
#else
750
      case 6: error = -1; break;
751
#endif
752
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 753
      case 7: error = MIOS32_IIC_MIDI_PackageReceive(4, &package); port = IIC4; break;
78 tk 754
#else
755
      case 7: error = -1; break;
756
#endif
757
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 758
      case 8: error = MIOS32_IIC_MIDI_PackageReceive(5, &package); port = IIC5; break;
78 tk 759
#else
760
      case 8: error = -1; break;
761
#endif
80 tk 762
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
763
      case 9: error = MIOS32_IIC_MIDI_PackageReceive(6, &package); port = IIC6; break;
764
#else
765
      case 9: error = -1; break;
766
#endif
767
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
768
      case 10: error = MIOS32_IIC_MIDI_PackageReceive(7, &package); port = IIC7; break;
769
#else
770
      case 10: error = -1; break;
771
#endif
78 tk 772
      default:
773
    // allow 10 forwards maximum to yield some CPU time for other tasks
774
    if( packages_forwarded && total_packages_forwarded < 10 ) {
775
      intf = 0; // restart with USB
776
      packages_forwarded = 0; // for checking, if packages still have been forwarded in next round
777
    } else {
778
      again = 0; // no more interfaces to be processed
779
    }
780
    error = -1; // empty round - no message
781
    }
33 tk 782
 
78 tk 783
    // message received?
784
    if( error >= 0 ) {
785
      // notify that a package has been forwarded
786
      ++packages_forwarded;
787
      ++total_packages_forwarded;
33 tk 788
 
78 tk 789
      // remove cable number from package (MIOS32_MIDI passes it's own port number)
69 tk 790
      package.cable = 0;
33 tk 791
 
78 tk 792
      // branch depending on package type
33 tk 793
      if( package.type >= 0x8 ) {
217 tk 794
    if( callback_event != NULL )
795
      callback_event(port, package);
33 tk 796
      } else {
797
    switch( package.type ) {
798
    case 0x0: // reserved, ignore
799
    case 0x1: // cable events, ignore
800
      break;
801
 
802
    case 0x2: // Two-byte System Common messages like MTC, SongSelect, etc. 
803
    case 0x3: // Three-byte System Common messages like SPP, etc. 
217 tk 804
      if( callback_event != NULL )
805
        callback_event(port, package); // -> forwarded as event
33 tk 806
      break;
807
    case 0x4: // SysEx starts or continues (3 bytes)
217 tk 808
      if( callback_sysex != NULL ) {
809
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
810
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
811
        callback_sysex(port, package.evnt2); // -> forwarded as SysEx
812
      }
225 tk 813
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
814
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
815
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt2); // -> forward to MIOS32 SysEx Parser
33 tk 816
      break;
817
    case 0x5: // Single-byte System Common Message or SysEx ends with following single byte. 
217 tk 818
      if( package.evnt0 >= 0xf8 ) {
819
        if( callback_event != NULL )
820
          callback_event(port, package); // -> forwarded as event
821
      } else {
822
        if( callback_sysex != NULL )
823
          callback_sysex(port, package.evnt0); // -> forwarded as SysEx
225 tk 824
        MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
217 tk 825
      }
33 tk 826
      break;
827
    case 0x6: // SysEx ends with following two bytes.
217 tk 828
      if( callback_sysex != NULL ) {
829
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
830
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
831
      }
225 tk 832
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
833
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
33 tk 834
      break;
835
    case 0x7: // SysEx ends with following three bytes.
217 tk 836
      if( callback_sysex != NULL ) {
837
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
838
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
839
        callback_sysex(port, package.evnt2); // -> forwarded as SysEx
840
      }
225 tk 841
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
842
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
843
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt2); // -> forward to MIOS32 SysEx Parser
33 tk 844
      break;
845
    }
846
      }
847
    }
848
  } while( again );
849
 
850
  return 0;
851
}
852
 
853
 
155 tk 854
/////////////////////////////////////////////////////////////////////////////
281 tk 855
//! Installs the Tx callback function which is executed by
856
//! MIOS32_MIDI_SendPackage_NonBlocking() before the MIDI package will be
857
//! forwarded to the physical interface.
858
//!
859
//! The callback allows following usecases:
860
//! <UL>
282 tk 861
//!   <LI>package filter
281 tk 862
//!   <LI>duplicating/routing packages
863
//!   <LI>monitoring packages (sniffer)
864
//!   <LI>create virtual busses; loopbacks
282 tk 865
//!   <LI>extend available ports (e.g. by an OSC or AOUT port)<BR>
866
//!       It is recommented to give port extensions a port number >= 0x80 to
867
//!       avoid incompatibility with future MIOS32 port extensions.
281 tk 868
//! </UL>
869
//! \param[in] *callback_tx pointer to callback function:<BR>
211 tk 870
//! \code
281 tk 871
//!    s32 callback_tx(mios32_midi_port_t port, mios32_midi_package_t package);
211 tk 872
//! \endcode
281 tk 873
//! The package will be forwarded to the physical interface if the function 
874
//! returns 0.<BR>
875
//! Should return 1 to filter a package.
876
//! Should return -2 to initiate a retry (function will be called again)
877
//! Should return -3 to report any other error.
878
//! These error codes comply with MIOS32_MIDI_SendPackage_NonBlocking()
211 tk 879
//! \return < 0 on errors
281 tk 880
//! \note Please use the filtering capabilities with special care - if a port
881
//! is filtered which is also used for code upload, you won't be able to exchange
882
//! the erroneous code w/o starting the bootloader in hold mode after power-on.
155 tk 883
/////////////////////////////////////////////////////////////////////////////
281 tk 884
s32 MIOS32_MIDI_DirectTxCallback_Init(void *callback_tx)
155 tk 885
{
886
  direct_tx_callback_func = callback_tx;
157 tk 887
 
888
  return 0; // no error
155 tk 889
}
890
 
891
 
892
/////////////////////////////////////////////////////////////////////////////
281 tk 893
//! Installs the Rx callback function which is executed immediately on each
894
//! incoming/outgoing MIDI byte, partly from interrupt handlers.
895
//!
896
//! This function should be executed so fast as possible. It can be used
897
//! to trigger MIDI Rx LEDs or to trigger on MIDI clock events. In order to
898
//! avoid MIDI buffer overruns, the max. recommented execution time is 100 uS!
899
//!
900
//! It is possible to filter incoming MIDI bytes with the return value of the
901
//! callback function.<BR>
902
//! \param[in] *callback_rx pointer to callback function:<BR>
903
//! \code
904
//!    s32 callback_rx(mios32_midi_port_t port, u8 midi_byte);
905
//! \endcode
906
//! The byte will be forwarded into the MIDI Rx queue if the function returns 0.<BR>
907
//! It will be filtered out if the callback returns != 0 (e.g. 1 for "filter", 
908
//! or -1 for "error").
909
//! \return < 0 on errors
910
//! \note Please use the filtering capabilities with special care - if a port
911
//! is filtered which is also used for code upload, you won't be able to exchange
912
//! the erroneous code w/o starting the bootloader in hold mode after power-on.
155 tk 913
/////////////////////////////////////////////////////////////////////////////
281 tk 914
s32 MIOS32_MIDI_DirectRxCallback_Init(void *callback_rx)
155 tk 915
{
281 tk 916
  direct_rx_callback_func = callback_rx;
155 tk 917
 
157 tk 918
  return 0; // no error
155 tk 919
}
920
 
281 tk 921
 
155 tk 922
/////////////////////////////////////////////////////////////////////////////
211 tk 923
//! This function is used by MIOS32 internal functions to forward received
281 tk 924
//! MIDI bytes to the Rx Callback routine.
925
//!
926
//! It shouldn't be used by applications.
211 tk 927
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
281 tk 928
//! \param[in] midi_byte received MIDI byte
211 tk 929
//! \return < 0 on errors
155 tk 930
/////////////////////////////////////////////////////////////////////////////
281 tk 931
s32 MIOS32_MIDI_SendByteToRxCallback(mios32_midi_port_t port, u8 midi_byte)
155 tk 932
{
933
  // note: here we could filter the user hook execution on special situations
281 tk 934
  if( direct_rx_callback_func != NULL )
935
    return direct_rx_callback_func(port, midi_byte);
157 tk 936
  return 0; // no error
155 tk 937
}
938
 
939
/////////////////////////////////////////////////////////////////////////////
211 tk 940
//! This function is used by MIOS32 internal functions to forward received
281 tk 941
//! MIDI packages to the Rx Callback routine (byte by byte)
942
//!
943
//! It shouldn't be used by applications.
211 tk 944
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
281 tk 945
//! \param[in] midi_package received MIDI package
211 tk 946
//! \return < 0 on errors
155 tk 947
/////////////////////////////////////////////////////////////////////////////
281 tk 948
s32 MIOS32_MIDI_SendPackageToRxCallback(mios32_midi_port_t port, mios32_midi_package_t midi_package)
155 tk 949
{
950
  // note: here we could filter the user hook execution on special situations
281 tk 951
  if( direct_rx_callback_func != NULL ) {
155 tk 952
    u8 buffer[3] = {midi_package.evnt0, midi_package.evnt1, midi_package.evnt2};
953
    int len = mios32_midi_pcktype_num_bytes[midi_package.cin];
954
    int i;
283 tk 955
    s32 status = 0;
155 tk 956
    for(i=0; i<len; ++i)
281 tk 957
      status |= direct_rx_callback_func(port, buffer[i]);
958
    return status;
155 tk 959
  }
157 tk 960
  return 0; // no error
155 tk 961
}
962
 
225 tk 963
 
964
/////////////////////////////////////////////////////////////////////////////
965
//! This function allows to change the DEFAULT port.<BR>
966
//! The preset which will be used after application reset can be set in
967
//! mios32_config.h via "#define MIOS32_MIDI_DEFAULT_PORT <port>".<BR>
968
//! It's set to USB0 so long not overruled in mios32_config.h
969
//! \param[in] port MIDI port (USB0..USB7, UART0..UART1, IIC0..IIC7)
970
//! \return < 0 on errors
971
/////////////////////////////////////////////////////////////////////////////
972
s32 MIOS32_MIDI_DefaultPortSet(mios32_midi_port_t port)
973
{
974
  if( port == DEFAULT ) // avoid recursion
975
    return -1;
976
 
977
  default_port = port;
978
 
979
  return 0; // no error
980
}
981
 
982
/////////////////////////////////////////////////////////////////////////////
983
//! This function returns the DEFAULT port
984
//! \return the default port
985
/////////////////////////////////////////////////////////////////////////////
986
mios32_midi_port_t MIOS32_MIDI_DefaultPortGet(void)
987
{
988
  return default_port;
989
}
990
 
991
 
992
/////////////////////////////////////////////////////////////////////////////
307 tk 993
//! This function allows to change the MIDI_DEBUG port.<BR>
994
//! The preset which will be used after application reset can be set in
995
//! mios32_config.h via "#define MIOS32_MIDI_DEBUG_PORT <port>".<BR>
996
//! It's set to USB0 so long not overruled in mios32_config.h
997
//! \param[in] port MIDI port (USB0..USB7, UART0..UART1, IIC0..IIC7)
998
//! \return < 0 on errors
999
/////////////////////////////////////////////////////////////////////////////
1000
s32 MIOS32_MIDI_DebugPortSet(mios32_midi_port_t port)
1001
{
1002
  if( port == MIDI_DEBUG ) // avoid recursion
1003
    return -1;
1004
 
1005
  debug_port = port;
1006
 
1007
  return 0; // no error
1008
}
1009
 
1010
/////////////////////////////////////////////////////////////////////////////
1011
//! This function returns the MIDI_DEBUG port
1012
//! \return the debug port
1013
/////////////////////////////////////////////////////////////////////////////
1014
mios32_midi_port_t MIOS32_MIDI_DebugPortGet(void)
1015
{
1016
  return debug_port;
1017
}
1018
 
1019
 
1020
/////////////////////////////////////////////////////////////////////////////
225 tk 1021
//! This function sets the SysEx Device ID, which is used during parsing
1022
//! incoming SysEx Requests to MIOS32<BR>
1023
//! It can also be used by an application for additional parsing with the same ID.<BR>
1024
//! ID changes will get lost after reset. It can be changed permanently by the
1025
//! user via Bootloader Command 0x0c
1026
//! \param[in] device_id a new (temporary) device ID (0x00..0x7f)
1027
//! \return < 0 on errors
1028
/////////////////////////////////////////////////////////////////////////////
1029
s32 MIOS32_MIDI_DeviceIDSet(u8 device_id)
1030
{
1031
  sysex_device_id = device_id & 0x7f;
1032
  return 0; // no error
1033
}
1034
 
1035
/////////////////////////////////////////////////////////////////////////////
1036
//! This function returns the SysEx Device ID, which is used during parsing
1037
//! incoming SysEx Requests to MIOS32<BR>
1038
//! It can also be used by an application for additional parsing with the same ID.<BR>
1039
//! The initial ID is stored inside the BSL range and will be recovered after
1040
//! reset. It can be changed by the user via Bootloader Command 0x0c
1041
//! \return SysEx device ID (0x00..0x7f)
1042
//! \todo store device ID via BSL based EEPROM emulation
1043
/////////////////////////////////////////////////////////////////////////////
1044
u8 MIOS32_MIDI_DeviceIDGet(void)
1045
{
1046
  return sysex_device_id;
1047
}
1048
 
1049
 
1050
/////////////////////////////////////////////////////////////////////////////
1051
// This function parses an incoming sysex stream for MIOS32 commands
1052
/////////////////////////////////////////////////////////////////////////////
1053
static s32 MIOS32_MIDI_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in)
1054
{
1055
  // ignore realtime messages (see MIDI spec - realtime messages can
1056
  // always be injected into events/streams, and don't change the running status)
1057
  if( midi_in >= 0xf8 )
1058
    return 0;
1059
 
1060
  // TODO: here we could send an error notification, that multiple devices are trying to access the device
1061
  if( sysex_state.MY_SYSEX && port != last_sysex_port )
1062
    return -1;
1063
 
1064
  last_sysex_port = port;
1065
 
1066
  // branch depending on state
1067
  if( !sysex_state.MY_SYSEX ) {
1068
    if( (sysex_state.CTR < sizeof(mios32_midi_sysex_header) && midi_in != mios32_midi_sysex_header[sysex_state.CTR]) ||
1069
    (sysex_state.CTR == sizeof(mios32_midi_sysex_header) && midi_in != sysex_device_id) ) {
1070
      // incoming byte doesn't match
1071
      MIOS32_MIDI_SYSEX_CmdFinished();
1072
    } else {
1073
      if( ++sysex_state.CTR > sizeof(mios32_midi_sysex_header) ) {
1074
    // complete header received, waiting for data
1075
    sysex_state.MY_SYSEX = 1;
1076
      }
1077
    }
1078
  } else {
1079
    // check for end of SysEx message or invalid status byte
1080
    if( midi_in >= 0x80 ) {
1081
      if( midi_in == 0xf7 && sysex_state.CMD ) {
1082
        MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_END, midi_in);
1083
      }
1084
      MIOS32_MIDI_SYSEX_CmdFinished();
1085
    } else {
1086
      // check if command byte has been received
1087
      if( !sysex_state.CMD ) {
1088
    sysex_state.CMD = 1;
1089
    sysex_cmd = midi_in;
1090
    MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN, midi_in);
1091
      }
1092
      else
1093
    MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_CONT, midi_in);
1094
    }
1095
  }
1096
 
1097
  return 0; // no error
1098
}
1099
 
1100
 
1101
/////////////////////////////////////////////////////////////////////////////
1102
// This function is called at the end of a sysex command or on 
1103
// an invalid message
1104
/////////////////////////////////////////////////////////////////////////////
1105
static s32 MIOS32_MIDI_SYSEX_CmdFinished(void)
1106
{
1107
  // clear all status variables
1108
  sysex_state.ALL = 0;
1109
  sysex_cmd = 0;
1110
 
1111
  return 0; // no error
1112
}
1113
 
1114
/////////////////////////////////////////////////////////////////////////////
1115
// This function handles the sysex commands
1116
/////////////////////////////////////////////////////////////////////////////
1117
static s32 MIOS32_MIDI_SYSEX_Cmd(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
1118
{
238 tk 1119
#if MIOS32_MIDI_BSL_ENHANCEMENTS
1120
  // this compile switch should only be activated for the bootloader!
1121
  if( BSL_SYSEX_Cmd(port, cmd_state, midi_in, sysex_cmd) >= 0 )
1122
    return 0; // BSL has serviced this command - no error
1123
#endif
225 tk 1124
  switch( sysex_cmd ) {
1125
    case 0x00:
230 tk 1126
      MIOS32_MIDI_SYSEX_Cmd_Query(port, cmd_state, midi_in);
225 tk 1127
      break;
1128
    case 0x0f:
1129
      MIOS32_MIDI_SYSEX_Cmd_Ping(port, cmd_state, midi_in);
1130
      break;
1131
    default:
1132
      // unknown command
1133
      // TODO: send 0xf7 if merger enabled
1134
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_INVALID_COMMAND);
1135
      MIOS32_MIDI_SYSEX_CmdFinished();      
1136
  }
1137
 
1138
  return 0; // no error
1139
}
1140
 
1141
 
1142
 
1143
/////////////////////////////////////////////////////////////////////////////
230 tk 1144
// Command 00: Query core informations and request BSL entry
225 tk 1145
/////////////////////////////////////////////////////////////////////////////
230 tk 1146
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 1147
{
230 tk 1148
  static u8 query_req = 0;
1149
  char str_buffer[40];
225 tk 1150
 
1151
  switch( cmd_state ) {
1152
 
1153
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
230 tk 1154
      query_req = 0;
225 tk 1155
      break;
1156
 
1157
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
230 tk 1158
      query_req = midi_in;
1159
      break;
1160
 
1161
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
1162
      switch( query_req ) {
1163
        case 0x01: // operating system
1164
      MIOS32_MIDI_SYSEX_SendAckStr(port, "MIOS32");
225 tk 1165
      break;
237 tk 1166
        case 0x02: // Board
230 tk 1167
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_BOARD_STR);
225 tk 1168
      break;
230 tk 1169
        case 0x03: // Core Family
1170
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_FAMILY_STR);
225 tk 1171
      break;
230 tk 1172
        case 0x04: // Chip ID
1173
      sprintf(str_buffer, "%08x", MIOS32_SYS_ChipIDGet());
1174
      MIOS32_MIDI_SYSEX_SendAckStr(port, (char *)str_buffer);
1175
      break;
1176
        case 0x05: // Serial Number
1177
      if( MIOS32_SYS_SerialNumberGet((char *)str_buffer) >= 0 )
1178
        MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1179
      else
1180
        MIOS32_MIDI_SYSEX_SendAckStr(port, "?");
1181
      break;
1182
        case 0x06: // Flash Memory Size
1183
      sprintf(str_buffer, "%d", MIOS32_SYS_FlashSizeGet());
1184
      MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1185
      break;
1186
        case 0x07: // RAM Memory Size
1187
      sprintf(str_buffer, "%d", MIOS32_SYS_RAMSizeGet());
1188
      MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1189
      break;
1190
        case 0x08: // Application Name Line #1
1191
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_LCD_BOOT_MSG_LINE1);
1192
      break;
1193
        case 0x09: // Application Name Line #2
1194
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_LCD_BOOT_MSG_LINE2);
1195
      break;
1196
        case 0x7f:
231 tk 1197
#if MIOS32_MIDI_BSL_ENHANCEMENTS
1198
      // release halt state (or sending upload request) instead of reseting the core
1199
      BSL_SYSEX_ReleaseHaltState();
1200
#else
230 tk 1201
      // reset core (this will send an upload request)
1202
      MIOS32_SYS_Reset();
1203
      // at least on STM32 we will never reach this point
1204
      // but other core families could contain an empty stumb!
231 tk 1205
#endif
230 tk 1206
      break;
1207
        default:
1208
      // unknown query
1209
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_UNKNOWN_QUERY);
225 tk 1210
      }
1211
  }
1212
 
1213
  return 0; // no error
1214
}
1215
 
1216
/////////////////////////////////////////////////////////////////////////////
1217
// Command 0F: Ping (just send back acknowledge)
1218
/////////////////////////////////////////////////////////////////////////////
1219
static s32 MIOS32_MIDI_SYSEX_Cmd_Ping(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
1220
{
1221
  switch( cmd_state ) {
1222
 
1223
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
1224
      // nothing to do
1225
      break;
1226
 
1227
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
1228
      // nothing to do
1229
      break;
1230
 
1231
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
1232
      // TODO: send 0xf7 if merger enabled
1233
 
1234
      // send acknowledge
1235
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_ACK, 0x00);
1236
 
1237
      break;
1238
  }
1239
 
1240
  return 0; // no error
1241
}
1242
 
1243
/////////////////////////////////////////////////////////////////////////////
1244
// This function sends a SysEx acknowledge to notify the user about the received command
1245
// expects acknowledge code (e.g. 0x0f for good, 0x0e for error) and additional argument
1246
/////////////////////////////////////////////////////////////////////////////
1247
static s32 MIOS32_MIDI_SYSEX_SendAck(mios32_midi_port_t port, u8 ack_code, u8 ack_arg)
1248
{
1249
  u8 sysex_buffer[32]; // should be enough?
1250
  u8 *sysex_buffer_ptr = &sysex_buffer[0];
1251
  int i;
1252
 
1253
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
1254
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
1255
 
1256
  // device ID
1257
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
1258
 
1259
  // send ack code and argument
1260
  *sysex_buffer_ptr++ = ack_code;
1261
  *sysex_buffer_ptr++ = ack_arg;
1262
 
1263
  // send footer
1264
  *sysex_buffer_ptr++ = 0xf7;
1265
 
1266
  // finally send SysEx stream
1267
  return MIOS32_MIDI_SendSysEx(port, (u8 *)sysex_buffer, (u32)sysex_buffer_ptr - ((u32)&sysex_buffer[0]));
1268
}
1269
 
230 tk 1270
/////////////////////////////////////////////////////////////////////////////
1271
// This function sends an SysEx acknowledge with a string (used on queries)
1272
/////////////////////////////////////////////////////////////////////////////
1273
static s32 MIOS32_MIDI_SYSEX_SendAckStr(mios32_midi_port_t port, char *str)
1274
{
1275
  u8 sysex_buffer[128]; // should be enough?
1276
  u8 *sysex_buffer_ptr = &sysex_buffer[0];
1277
  int i;
225 tk 1278
 
230 tk 1279
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
1280
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
155 tk 1281
 
230 tk 1282
  // device ID
1283
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
1284
 
1285
  // send ack code
1286
  *sysex_buffer_ptr++ = MIOS32_MIDI_SYSEX_ACK;
1287
 
1288
  // send string
307 tk 1289
  for(i=0; i<100 && (str[i] != 0); ++i)
230 tk 1290
    *sysex_buffer_ptr++ = str[i];
1291
 
1292
  // send footer
1293
  *sysex_buffer_ptr++ = 0xf7;
1294
 
1295
  // finally send SysEx stream
1296
  return MIOS32_MIDI_SendSysEx(port, (u8 *)sysex_buffer, (u32)sysex_buffer_ptr - ((u32)&sysex_buffer[0]));
1297
}
1298
 
32 tk 1299
#endif /* MIOS32_DONT_USE_MIDI */