Subversion Repositories svn.mios32

Rev

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