Subversion Repositories svn.mios32

Rev

Rev 425 | Rev 529 | 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 528 2009-05-17 16:45:51Z 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
  }
528 tk 226
 
227
  return 0; // invalid port
78 tk 228
}
229
 
230
 
231
/////////////////////////////////////////////////////////////////////////////
528 tk 232
//! This function enables/disables running status optimisation for a given
233
//! MIDI OUT port to improve bandwidth if MIDI events with the same
234
//! status byte are sent back-to-back.<BR>
235
//! The optimisation is currently only used for UART based port (enabled by
236
//! default), IIC: TODO, USB: not required).
237
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
238
//! \param[in] enable 0=optimisation disabled, 1=optimisation enabled
239
//! \return -1 if port not available or if it doesn't support running status
240
//! \return 0 on success
241
/////////////////////////////////////////////////////////////////////////////
242
s32 MIOS32_MIDI_RS_OptimisationSet(mios32_midi_port_t port, u8 enable)
243
{
244
  // if default/debug port: select mapped port
245
  if( !(port & 0xf0) ) {
246
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
247
  }
248
 
249
  // branch depending on selected port
250
  switch( port >> 4 ) {
251
    case 1:
252
      return -1; // not required for USB
253
 
254
    case 2:
255
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
256
      return MIOS32_UART_MIDI_RS_OptimisationSet(port & 0xf, enable);
257
#else
258
      return -1; // UART_MIDI has been disabled
259
#endif
260
 
261
    case 3:
262
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
263
      return MIOS32_IIC_MIDI_RS_OptimisationSet(port & 0xf, enable);
264
#else
265
      return -1; // IIC_MIDI has been disabled
266
#endif
267
  }
268
 
269
  return -1; // invalid port
270
}
271
 
272
 
273
/////////////////////////////////////////////////////////////////////////////
274
//! This function returns the running status optimisation enable/disable flag
275
//! for the given MIDI OUT port.
276
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
277
//! \return -1 if port not available or if it doesn't support running status
278
//! \return 0 if optimisation disabled
279
//! \return 1 if optimisation enabled
280
/////////////////////////////////////////////////////////////////////////////
281
s32 MIOS32_MIDI_RS_OptimisationGet(mios32_midi_port_t port)
282
{
283
  // if default/debug port: select mapped port
284
  if( !(port & 0xf0) ) {
285
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
286
  }
287
 
288
  // branch depending on selected port
289
  switch( port >> 4 ) {
290
    case 1:
291
      return -1; // not required for USB
292
 
293
    case 2:
294
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
295
      return MIOS32_UART_MIDI_RS_OptimisationGet(port & 0xf);
296
#else
297
      return -1; // UART_MIDI has been disabled
298
#endif
299
 
300
    case 3:
301
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
302
      return MIOS32_IIC_MIDI_RS_OptimisationGet(port & 0xf);
303
#else
304
      return -1; // IIC_MIDI has been disabled
305
#endif
306
  }
307
 
308
  return -1; // invalid port
309
}
310
 
311
 
312
/////////////////////////////////////////////////////////////////////////////
313
//! This function resets the current running status, so that it will be sent
314
//! again with the next MIDI Out package.
315
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
316
//! \return -1 if port not available or if it doesn't support running status
317
//! \return 0 if optimisation disabled
318
//! \return 1 if optimisation enabled
319
/////////////////////////////////////////////////////////////////////////////
320
s32 MIOS32_MIDI_RS_Reset(mios32_midi_port_t port)
321
{
322
  // if default/debug port: select mapped port
323
  if( !(port & 0xf0) ) {
324
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
325
  }
326
 
327
  // branch depending on selected port
328
  switch( port >> 4 ) {
329
    case 1:
330
      return -1; // not required for USB
331
 
332
    case 2:
333
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
334
      return MIOS32_UART_MIDI_RS_Reset(port & 0xf);
335
#else
336
      return -1; // UART_MIDI has been disabled
337
#endif
338
 
339
    case 3:
340
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
341
      return MIOS32_IIC_MIDI_RS_Reset(port & 0xf);
342
#else
343
      return -1; // IIC_MIDI has been disabled
344
#endif
345
  }
346
 
347
  return -1; // invalid port
348
}
349
 
350
 
351
/////////////////////////////////////////////////////////////////////////////
211 tk 352
//! Sends a package over given port
281 tk 353
//!
211 tk 354
//! This is a low level function. In difference to other MIOS32_MIDI_Send* functions,
355
//! It allows to send packages in non-blocking mode (caller has to retry if -2 is returned)
281 tk 356
//!
357
//! Before the package is forwarded, an optional Tx Callback function will be called
358
//! which allows to filter/monitor/route the package, or extend the MIDI transmitter
359
//! by custom MIDI Output ports (e.g. for internal busses, OSC, AOUT, etc.)
211 tk 360
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
361
//! \param[in] package MIDI package
362
//! \return -1 if port not available
363
//! \return -2 buffer is full
364
//!         caller should retry until buffer is free again
281 tk 365
//! \return -3 Tx Callback reported an error
366
//! \return 1 if package has been filtered by Tx callback
211 tk 367
//! \return 0 on success
110 tk 368
/////////////////////////////////////////////////////////////////////////////
369
s32 MIOS32_MIDI_SendPackage_NonBlocking(mios32_midi_port_t port, mios32_midi_package_t package)
370
{
307 tk 371
  // if default/debug port: select mapped port
110 tk 372
  if( !(port & 0xf0) ) {
307 tk 373
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
110 tk 374
  }
375
 
376
  // insert subport number into package
377
  package.cable = port & 0xf;
378
 
281 tk 379
  // forward to Tx callback function and break if package has been filtered
380
  if( direct_tx_callback_func != NULL ) {
381
    s32 status;
425 tk 382
    if( (status=direct_tx_callback_func(port, package)) )
281 tk 383
      return status;
384
  }
385
 
110 tk 386
  // branch depending on selected port
387
  switch( port >> 4 ) {
388
    case 1:
389
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 390
      return MIOS32_USB_MIDI_PackageSend_NonBlocking(package);
110 tk 391
#else
392
      return -1; // USB has been disabled
393
#endif
394
 
395
    case 2:
396
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
397
      return MIOS32_UART_MIDI_PackageSend_NonBlocking(package.cable, package);
398
#else
399
      return -1; // UART_MIDI has been disabled
400
#endif
401
 
402
    case 3:
403
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
404
      return MIOS32_IIC_MIDI_PackageSend_NonBlocking(package.cable, package);
405
#else
406
      return -1; // IIC_MIDI has been disabled
407
#endif
408
 
409
    case 4:
410
      return -1; // Ethernet not implemented yet
411
 
412
    default:
413
      // invalid port
414
      return -1;
415
  }
416
}
417
 
418
 
419
/////////////////////////////////////////////////////////////////////////////
211 tk 420
//! Sends a package over given port
421
//! This is a low level function - use the remaining MIOS32_MIDI_Send* functions
422
//! to send specific MIDI events
423
//! (blocking function)
424
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
425
//! \param[in] package MIDI package
426
//! \return -1 if port not available
427
//! \return 0 on success
32 tk 428
/////////////////////////////////////////////////////////////////////////////
69 tk 429
s32 MIOS32_MIDI_SendPackage(mios32_midi_port_t port, mios32_midi_package_t package)
32 tk 430
{
307 tk 431
  // if default/debug port: select mapped port
80 tk 432
  if( !(port & 0xf0) ) {
307 tk 433
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
80 tk 434
  }
435
 
32 tk 436
  // insert subport number into package
89 tk 437
  package.cable = port & 0xf;
32 tk 438
 
301 tk 439
  // forward to Tx callback function and break if package has been filtered
440
  if( direct_tx_callback_func != NULL ) {
441
    s32 status;
425 tk 442
    if( (status=direct_tx_callback_func(port, package)) )
301 tk 443
      return status;
444
  }
445
 
32 tk 446
  // branch depending on selected port
447
  switch( port >> 4 ) {
80 tk 448
    case 1:
78 tk 449
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 450
      return MIOS32_USB_MIDI_PackageSend(package);
32 tk 451
#else
452
      return -1; // USB has been disabled
453
#endif
454
 
80 tk 455
    case 2:
456
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
457
      return MIOS32_UART_MIDI_PackageSend(package.cable, package);
458
#else
459
      return -1; // UART_MIDI has been disabled
460
#endif
32 tk 461
 
80 tk 462
    case 3:
78 tk 463
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
464
      return MIOS32_IIC_MIDI_PackageSend(package.cable, package);
465
#else
466
      return -1; // IIC_MIDI has been disabled
467
#endif
32 tk 468
 
80 tk 469
    case 4:
32 tk 470
      return -1; // Ethernet not implemented yet
471
 
472
    default:
473
      // invalid port
474
      return -1;
475
  }
476
}
477
 
478
 
479
/////////////////////////////////////////////////////////////////////////////
211 tk 480
//! Sends a MIDI Event
481
//! This function is provided for a more comfortable use model
482
//!    o MIOS32_MIDI_SendNoteOff(port, chn, note, vel)
483
//!    o MIOS32_MIDI_SendNoteOn(port, chn, note, vel)
484
//!    o MIOS32_MIDI_SendPolyAftertouch(port, chn, note, val)
485
//!    o MIOS32_MIDI_SendCC(port, chn, cc, val)
486
//!    o MIOS32_MIDI_SendProgramChange(port, chn, prg)
487
//!    o MIOS32_MIDI_ChannelAftertouch(port, chn, val)
488
//!    o MIOS32_MIDI_PitchBend(port, chn, val)
489
//!
490
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
491
//! \param[in] evnt0 first MIDI byte
225 tk 492
//! \param[in] evnt1 second MIDI byte
493
//! \param[in] evnt2 third MIDI byte
211 tk 494
//! \return -1 if port not available
495
//! \return 0 on success
32 tk 496
/////////////////////////////////////////////////////////////////////////////
69 tk 497
s32 MIOS32_MIDI_SendEvent(mios32_midi_port_t port, u8 evnt0, u8 evnt1, u8 evnt2)
32 tk 498
{
33 tk 499
  mios32_midi_package_t package;
500
 
501
  // MEMO: don't optimize this function by calling MIOS32_MIDI_SendSpecialEvent
502
  // from here, because the 4 * u8 parameter list of this function leads
503
  // to best compile results (4*u8 combined to a single u32)
504
 
505
  package.type  = evnt0 >> 4;
506
  package.evnt0 = evnt0;
507
  package.evnt1 = evnt1;
508
  package.evnt2 = evnt2;
509
  return MIOS32_MIDI_SendPackage(port, package);
32 tk 510
}
511
 
69 tk 512
s32 MIOS32_MIDI_SendNoteOff(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 vel)
136 tk 513
{ return MIOS32_MIDI_SendEvent(port, 0x80 | chn, note, vel); }
32 tk 514
 
69 tk 515
s32 MIOS32_MIDI_SendNoteOn(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 vel)
136 tk 516
{ return MIOS32_MIDI_SendEvent(port, 0x90 | chn, note, vel); }
69 tk 517
 
518
s32 MIOS32_MIDI_SendPolyPressure(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 val)
136 tk 519
{ return MIOS32_MIDI_SendEvent(port, 0xa0 | chn, note, val); }
69 tk 520
 
521
s32 MIOS32_MIDI_SendCC(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 cc, u8 val)
136 tk 522
{ return MIOS32_MIDI_SendEvent(port, 0xb0 | chn, cc,   val); }
69 tk 523
 
524
s32 MIOS32_MIDI_SendProgramChange(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 prg)
136 tk 525
{ return MIOS32_MIDI_SendEvent(port, 0xc0 | chn, prg,  0x00); }
69 tk 526
 
527
s32 MIOS32_MIDI_SendAftertouch(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 val)
136 tk 528
{ return MIOS32_MIDI_SendEvent(port, 0xd0 | chn, val,  0x00); }
69 tk 529
 
530
s32 MIOS32_MIDI_SendPitchBend(mios32_midi_port_t port, mios32_midi_chn_t chn, u16 val)
136 tk 531
{ return MIOS32_MIDI_SendEvent(port, 0xe0 | chn, val & 0x7f, val >> 7); }
69 tk 532
 
533
 
33 tk 534
/////////////////////////////////////////////////////////////////////////////
211 tk 535
//! Sends a special type MIDI Event
536
//! This function is provided for a more comfortable use model
537
//! It is aliased to following functions
538
//!    o MIOS32_MIDI_SendMTC(port, val)
539
//!    o MIOS32_MIDI_SendSongPosition(port, val)
540
//!    o MIOS32_MIDI_SendSongSelect(port, val)
541
//!    o MIOS32_MIDI_SendTuneRequest()
542
//!    o MIOS32_MIDI_SendClock()
543
//!    o MIOS32_MIDI_SendTick()
544
//!    o MIOS32_MIDI_SendStart()
545
//!    o MIOS32_MIDI_SendStop()
546
//!    o MIOS32_MIDI_SendContinue()
547
//!    o MIOS32_MIDI_SendActiveSense()
548
//!    o MIOS32_MIDI_SendReset()
549
//!
550
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
551
//! \param[in] type the event type
552
//! \param[in] evnt0 first MIDI byte
225 tk 553
//! \param[in] evnt1 second MIDI byte
554
//! \param[in] evnt2 third MIDI byte
211 tk 555
//! \return -1 if port not available
556
//! \return 0 on success
33 tk 557
/////////////////////////////////////////////////////////////////////////////
69 tk 558
s32 MIOS32_MIDI_SendSpecialEvent(mios32_midi_port_t port, u8 type, u8 evnt0, u8 evnt1, u8 evnt2)
33 tk 559
{
560
  mios32_midi_package_t package;
561
 
562
  package.type  = type;
563
  package.evnt0 = evnt0;
564
  package.evnt1 = evnt1;
565
  package.evnt2 = evnt2;
566
  return MIOS32_MIDI_SendPackage(port, package);
567
}
568
 
569
 
69 tk 570
s32 MIOS32_MIDI_SendMTC(mios32_midi_port_t port, u8 val)
136 tk 571
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x2, 0xf1, val, 0x00); }
69 tk 572
 
573
s32 MIOS32_MIDI_SendSongPosition(mios32_midi_port_t port, u16 val)
136 tk 574
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x3, 0xf2, val & 0x7f, val >> 7); }
69 tk 575
 
576
s32 MIOS32_MIDI_SendSongSelect(mios32_midi_port_t port, u8 val)
136 tk 577
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x2, 0xf3, val, 0x00); }
69 tk 578
 
579
s32 MIOS32_MIDI_SendTuneRequest(mios32_midi_port_t port)
136 tk 580
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf6, 0x00, 0x00); }
69 tk 581
 
582
s32 MIOS32_MIDI_SendClock(mios32_midi_port_t port)
136 tk 583
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf8, 0x00, 0x00); }
69 tk 584
 
585
s32 MIOS32_MIDI_SendTick(mios32_midi_port_t port)
136 tk 586
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf9, 0x00, 0x00); }
69 tk 587
 
588
s32 MIOS32_MIDI_SendStart(mios32_midi_port_t port)
136 tk 589
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfa, 0x00, 0x00); }
69 tk 590
 
397 stryd_one 591
s32 MIOS32_MIDI_SendContinue(mios32_midi_port_t port)
136 tk 592
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfb, 0x00, 0x00); }
69 tk 593
 
397 stryd_one 594
s32 MIOS32_MIDI_SendStop(mios32_midi_port_t port)
136 tk 595
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfc, 0x00, 0x00); }
69 tk 596
 
597
s32 MIOS32_MIDI_SendActiveSense(mios32_midi_port_t port)
136 tk 598
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfe, 0x00, 0x00); }
69 tk 599
 
600
s32 MIOS32_MIDI_SendReset(mios32_midi_port_t port)
136 tk 601
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xff, 0x00, 0x00); }
69 tk 602
 
603
 
33 tk 604
/////////////////////////////////////////////////////////////////////////////
211 tk 605
//! Sends a SysEx Stream
307 tk 606
//!
211 tk 607
//! This function is provided for a more comfortable use model
608
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
609
//! \param[in] stream pointer to SysEx stream
610
//! \param[in] count number of bytes
611
//! \return -1 if port not available
612
//! \return 0 on success
33 tk 613
/////////////////////////////////////////////////////////////////////////////
69 tk 614
s32 MIOS32_MIDI_SendSysEx(mios32_midi_port_t port, u8 *stream, u32 count)
33 tk 615
{
616
  s32 res;
617
  u32 offset;
618
  mios32_midi_package_t package;
619
 
620
  // MEMO: have a look into the project.lss file - gcc optimizes this code pretty well :)
621
 
622
  for(offset=0; offset<count;) {
623
    // package type depends on number of remaining bytes
624
    switch( count-offset ) {
625
      case 1:
626
    package.type = 0x5; // SysEx ends with following single byte. 
627
    package.evnt0 = stream[offset++];
628
    package.evnt1 = 0x00;
629
    package.evnt2 = 0x00;
630
    break;
631
      case 2:
632
    package.type = 0x6; // SysEx ends with following two bytes.
633
    package.evnt0 = stream[offset++];
634
    package.evnt1 = stream[offset++];
635
    package.evnt2 = 0x00;
636
    break;
637
      case 3:
638
    package.type = 0x7; // SysEx ends with following three bytes. 
639
    package.evnt0 = stream[offset++];
640
    package.evnt1 = stream[offset++];
641
    package.evnt2 = stream[offset++];
642
    break;
643
      default:
644
    package.type = 0x4; // SysEx starts or continues
645
    package.evnt0 = stream[offset++];
646
    package.evnt1 = stream[offset++];
647
    package.evnt2 = stream[offset++];
648
    }
649
 
110 tk 650
    res=MIOS32_MIDI_SendPackage(port, package);
33 tk 651
 
110 tk 652
    // expection? (e.g., port not available)
33 tk 653
    if( res < 0 )
654
      return res;
655
  }
656
 
657
  return 0;
658
}
659
 
660
 
661
/////////////////////////////////////////////////////////////////////////////
307 tk 662
//! Sends a formatted Debug Message to the MIOS Terminal in MIOS Studio.
663
//!
664
//! Formatting parameters are like known from printf, e.g.
665
//! \code
666
//!   MIOS32_MIDI_SendDebugMessage("Button %d %s\n", button, value ? "depressed" : "pressed");
667
//! \endcode
668
//!
669
//! The MIDI port used for debugging (MIDI_DEBUG) can be declared in mios32_config.h:
670
//! \code
671
//!   #define MIOS32_MIDI_DEBUG_PORT USB0
672
//! \endcode
673
//! (USB0 is the default value)
674
//!
675
//! Optionally, the port can be changed during runtime with MIOS32_MIDI_DebugPortSet
676
//! \param[in] *format zero-terminated format string - 128 characters supported maximum!
677
//! \param ... additional arguments
678
//! \return < 0 on errors
679
/////////////////////////////////////////////////////////////////////////////
680
s32 MIOS32_MIDI_SendDebugMessage(char *format, ...)
681
{
682
  u8 buffer[128+5+3+1]; // 128 chars allowed + 5 for header + 3 for command + F7
683
  va_list args;
684
  int i;
685
 
686
  // transform formatted string into string
687
  va_start(args, format);
688
  vsprintf((char *)((size_t)buffer+sizeof(mios32_midi_sysex_header)+3), format, args);
689
 
690
  u8 *sysex_buffer_ptr = buffer;
691
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
692
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
693
 
694
  // device ID
695
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
696
 
697
  // debug message: ack code
698
  *sysex_buffer_ptr++ = MIOS32_MIDI_SYSEX_DEBUG;
699
 
700
  // command identifier
701
  *sysex_buffer_ptr++ = 0x40; // string
702
 
703
  // search end of string and determine length
704
  u16 len = sizeof(mios32_midi_sysex_header) + 3;
705
  for(i=0; i<128 && (*sysex_buffer_ptr != 0); ++i) {
706
    *sysex_buffer_ptr++ &= 0x7f; // ensure that MIDI protocol won't be violated
707
    ++len;
708
  }
709
 
710
  // send footer
711
  *sysex_buffer_ptr++ = 0xf7;
712
  ++len;
713
 
714
  return MIOS32_MIDI_SendSysEx(debug_port, buffer, len);
715
}
716
 
717
 
718
/////////////////////////////////////////////////////////////////////////////
369 tk 719
//! Sends an hex dump (formatted representation of memory content) to the 
720
//! MIOS Terminal in MIOS Studio.
721
//!
722
//! The MIDI port used for debugging (MIDI_DEBUG) can be declared in mios32_config.h:
723
//! \code
724
//!   #define MIOS32_MIDI_DEBUG_PORT USB0
725
//! \endcode
726
//! (USB0 is the default value)
727
//!
728
//! Optionally, the port can be changed during runtime with MIOS32_MIDI_DebugPortSet
729
//! \param[in] *src pointer to memory location which should be dumped
730
//! \param[in] len number of bytes which should be sent
731
//! \return < 0 on errors
732
/////////////////////////////////////////////////////////////////////////////
733
s32 MIOS32_MIDI_SendDebugHexDump(u8 *src, u32 len)
734
{
735
  // check if any byte has to be sent
736
  if( !len )
737
    return 0;
738
 
739
  // send hex dump line by line
370 tk 740
  u8 *src_begin = src;
369 tk 741
  u8 *src_end;
742
  for(src_end=(u8 *)((size_t)src + len - 1); src < src_end;) {
376 tk 743
    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 744
    int i;
745
 
746
    // create SysEx header
747
    u8 *sysex_buffer_ptr = buffer;
748
    for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
749
      *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
750
 
751
    // device ID
752
    *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
753
 
754
    // debug message: ack code
755
    *sysex_buffer_ptr++ = MIOS32_MIDI_SYSEX_DEBUG;
756
 
757
    // command identifier
758
    *sysex_buffer_ptr++ = 0x40; // string
759
 
760
    // build line:
761
    // add source address
374 tk 762
    sprintf((char *)sysex_buffer_ptr, "%08X ", (u32)(src-src_begin));
763
    sysex_buffer_ptr += 9;
369 tk 764
 
765
    // add up to 16 bytes
766
    u8 *src_chars = src; // for later
767
    for(i=0; i<16; ++i) {
374 tk 768
      sprintf((char *)sysex_buffer_ptr, (src <= src_end) ? " %02X" : "   ", *src);
769
      sysex_buffer_ptr += 3;
369 tk 770
 
771
      ++src;
772
    }
773
 
774
    // add two spaces
374 tk 775
    for(i=0; i<2; ++i)
776
      *sysex_buffer_ptr++ = ' ';
369 tk 777
 
778
    // add characters
779
    for(i=0; i<16; ++i) {
780
      if( *src_chars < 32 || *src_chars >= 128 )
374 tk 781
    *sysex_buffer_ptr++ = '.';
369 tk 782
      else
374 tk 783
    *sysex_buffer_ptr++ = *src_chars;
369 tk 784
 
785
      if( src_chars == src_end )
786
    break;
787
 
788
      ++src_chars;
789
    }
790
 
376 tk 791
    // linebreak
792
    *sysex_buffer_ptr++ = '\n';
793
 
369 tk 794
    // add F7
374 tk 795
    *sysex_buffer_ptr++ = 0xf7;
369 tk 796
 
374 tk 797
    s32 status = MIOS32_MIDI_SendSysEx(debug_port, buffer, (u32)(sysex_buffer_ptr-buffer));
369 tk 798
    if( status < 0 )
799
      return status;
800
  }
801
 
802
  return 0; // no error
803
}
804
 
805
 
806
/////////////////////////////////////////////////////////////////////////////
211 tk 807
//! Checks for incoming MIDI messages, calls either the callback_event or
808
//! callback_sysex function with following parameters:
809
//! \code
810
//!    callback_event(mios32_midi_port_t port, mios32_midi_package_t midi_package)
811
//!    callback_sysex(mios32_midi_port_t port, u8 sysex_byte)
812
//! \endcode
528 tk 813
//!
814
//! Not for use in an application - this function is called by
815
//! by a task in the programming model!
211 tk 816
//! \return < 0 on errors
33 tk 817
/////////////////////////////////////////////////////////////////////////////
818
s32 MIOS32_MIDI_Receive_Handler(void *_callback_event, void *_callback_sysex)
819
{
820
  u8 port;
821
  mios32_midi_package_t package;
822
 
69 tk 823
  void (*callback_event)(mios32_midi_port_t port, mios32_midi_package_t midi_package) = _callback_event;
824
  void (*callback_sysex)(mios32_midi_port_t port, u8 sysex_byte) = _callback_sysex;
33 tk 825
 
78 tk 826
  u8 intf = 0; // interface to be checked
827
  u8 total_packages_forwarded = 0; // number of forwards - stop after 10 forwards to yield some CPU time for other tasks
828
  u8 packages_forwarded = 0;
829
  u8 again = 1;
33 tk 830
  do {
78 tk 831
    // Round Robin
832
    // TODO: maybe a list based approach would be better
833
    // it would allow to add/remove interfaces dynamically
834
    // this would also allow to give certain ports a higher priority (to add them multiple times to the list)
835
    // it would also improve this spagetthi code ;)
836
    s32 error = -1;
837
    switch( intf++ ) {
838
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 839
      case 0: error = MIOS32_USB_MIDI_PackageReceive(&package); port = USB0 + package.cable; break;
78 tk 840
#else
841
      case 0: error = -1; break;
842
#endif
126 tk 843
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART0_ASSIGNMENT == 1
80 tk 844
      case 1: error = MIOS32_UART_MIDI_PackageReceive(0, &package); port = UART0; break;
78 tk 845
#else
846
      case 1: error = -1; break;
847
#endif
126 tk 848
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART1_ASSIGNMENT == 1
80 tk 849
      case 2: error = MIOS32_UART_MIDI_PackageReceive(1, &package); port = UART1; break;
78 tk 850
#else
851
      case 2: error = -1; break;
852
#endif
853
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 854
      case 3: error = MIOS32_IIC_MIDI_PackageReceive(0, &package); port = IIC0; break;
78 tk 855
#else
856
      case 3: error = -1; break;
857
#endif
858
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 859
      case 4: error = MIOS32_IIC_MIDI_PackageReceive(1, &package); port = IIC1; break;
78 tk 860
#else
861
      case 4: error = -1; break;
862
#endif
863
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 864
      case 5: error = MIOS32_IIC_MIDI_PackageReceive(2, &package); port = IIC2; break;
78 tk 865
#else
866
      case 5: error = -1; break;
867
#endif
868
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 869
      case 6: error = MIOS32_IIC_MIDI_PackageReceive(3, &package); port = IIC3; break;
78 tk 870
#else
871
      case 6: error = -1; break;
872
#endif
873
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 874
      case 7: error = MIOS32_IIC_MIDI_PackageReceive(4, &package); port = IIC4; break;
78 tk 875
#else
876
      case 7: error = -1; break;
877
#endif
878
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 879
      case 8: error = MIOS32_IIC_MIDI_PackageReceive(5, &package); port = IIC5; break;
78 tk 880
#else
881
      case 8: error = -1; break;
882
#endif
80 tk 883
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
884
      case 9: error = MIOS32_IIC_MIDI_PackageReceive(6, &package); port = IIC6; break;
885
#else
886
      case 9: error = -1; break;
887
#endif
888
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
889
      case 10: error = MIOS32_IIC_MIDI_PackageReceive(7, &package); port = IIC7; break;
890
#else
891
      case 10: error = -1; break;
892
#endif
78 tk 893
      default:
894
    // allow 10 forwards maximum to yield some CPU time for other tasks
895
    if( packages_forwarded && total_packages_forwarded < 10 ) {
896
      intf = 0; // restart with USB
897
      packages_forwarded = 0; // for checking, if packages still have been forwarded in next round
898
    } else {
899
      again = 0; // no more interfaces to be processed
900
    }
901
    error = -1; // empty round - no message
902
    }
33 tk 903
 
78 tk 904
    // message received?
905
    if( error >= 0 ) {
906
      // notify that a package has been forwarded
907
      ++packages_forwarded;
908
      ++total_packages_forwarded;
33 tk 909
 
78 tk 910
      // remove cable number from package (MIOS32_MIDI passes it's own port number)
69 tk 911
      package.cable = 0;
33 tk 912
 
78 tk 913
      // branch depending on package type
33 tk 914
      if( package.type >= 0x8 ) {
217 tk 915
    if( callback_event != NULL )
916
      callback_event(port, package);
33 tk 917
      } else {
918
    switch( package.type ) {
919
    case 0x0: // reserved, ignore
920
    case 0x1: // cable events, ignore
921
      break;
922
 
923
    case 0x2: // Two-byte System Common messages like MTC, SongSelect, etc. 
924
    case 0x3: // Three-byte System Common messages like SPP, etc. 
217 tk 925
      if( callback_event != NULL )
926
        callback_event(port, package); // -> forwarded as event
33 tk 927
      break;
928
    case 0x4: // SysEx starts or continues (3 bytes)
217 tk 929
      if( callback_sysex != NULL ) {
930
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
931
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
932
        callback_sysex(port, package.evnt2); // -> forwarded as SysEx
933
      }
225 tk 934
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
935
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
936
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt2); // -> forward to MIOS32 SysEx Parser
33 tk 937
      break;
938
    case 0x5: // Single-byte System Common Message or SysEx ends with following single byte. 
217 tk 939
      if( package.evnt0 >= 0xf8 ) {
940
        if( callback_event != NULL )
941
          callback_event(port, package); // -> forwarded as event
942
      } else {
943
        if( callback_sysex != NULL )
944
          callback_sysex(port, package.evnt0); // -> forwarded as SysEx
225 tk 945
        MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
217 tk 946
      }
33 tk 947
      break;
948
    case 0x6: // SysEx ends with following two bytes.
217 tk 949
      if( callback_sysex != NULL ) {
950
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
951
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
952
      }
225 tk 953
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
954
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
33 tk 955
      break;
956
    case 0x7: // SysEx ends with following three bytes.
217 tk 957
      if( callback_sysex != NULL ) {
958
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
959
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
960
        callback_sysex(port, package.evnt2); // -> forwarded as SysEx
961
      }
225 tk 962
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
963
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
964
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt2); // -> forward to MIOS32 SysEx Parser
33 tk 965
      break;
966
    }
967
      }
968
    }
969
  } while( again );
970
 
971
  return 0;
972
}
973
 
974
 
155 tk 975
/////////////////////////////////////////////////////////////////////////////
528 tk 976
//! This function should be called periodically each mS to handle timeout
977
//! and expire counters.
978
//!
979
//! Not for use in an application - this function is called by
980
//! by a task in the programming model!
981
//! 
982
//! \param[in] uart_port UART number (0..1)
983
//! \return < 0 on errors
984
/////////////////////////////////////////////////////////////////////////////
985
s32 MIOS32_MIDI_Periodic_mS(void)
986
{
987
  s32 status = 0;
988
 
989
#ifndef MIOS32_DONT_USE_USB_MIDI
990
  status |= MIOS32_USB_MIDI_Periodic_mS();
991
#endif
992
 
993
#ifndef MIOS32_DONT_USE_UART_MIDI
994
  status |= MIOS32_UART_MIDI_Periodic_mS();
995
#endif
996
 
997
#ifndef MIOS32_DONT_USE_IIC_MIDI
998
  status |= MIOS32_IIC_MIDI_Periodic_mS();
999
#endif
1000
 
1001
  return status;
1002
}
1003
 
1004
 
1005
/////////////////////////////////////////////////////////////////////////////
281 tk 1006
//! Installs the Tx callback function which is executed by
1007
//! MIOS32_MIDI_SendPackage_NonBlocking() before the MIDI package will be
1008
//! forwarded to the physical interface.
1009
//!
1010
//! The callback allows following usecases:
1011
//! <UL>
282 tk 1012
//!   <LI>package filter
281 tk 1013
//!   <LI>duplicating/routing packages
1014
//!   <LI>monitoring packages (sniffer)
1015
//!   <LI>create virtual busses; loopbacks
282 tk 1016
//!   <LI>extend available ports (e.g. by an OSC or AOUT port)<BR>
1017
//!       It is recommented to give port extensions a port number >= 0x80 to
1018
//!       avoid incompatibility with future MIOS32 port extensions.
281 tk 1019
//! </UL>
1020
//! \param[in] *callback_tx pointer to callback function:<BR>
211 tk 1021
//! \code
281 tk 1022
//!    s32 callback_tx(mios32_midi_port_t port, mios32_midi_package_t package);
211 tk 1023
//! \endcode
281 tk 1024
//! The package will be forwarded to the physical interface if the function 
1025
//! returns 0.<BR>
1026
//! Should return 1 to filter a package.
1027
//! Should return -2 to initiate a retry (function will be called again)
1028
//! Should return -3 to report any other error.
1029
//! These error codes comply with MIOS32_MIDI_SendPackage_NonBlocking()
211 tk 1030
//! \return < 0 on errors
281 tk 1031
//! \note Please use the filtering capabilities with special care - if a port
1032
//! is filtered which is also used for code upload, you won't be able to exchange
1033
//! the erroneous code w/o starting the bootloader in hold mode after power-on.
155 tk 1034
/////////////////////////////////////////////////////////////////////////////
281 tk 1035
s32 MIOS32_MIDI_DirectTxCallback_Init(void *callback_tx)
155 tk 1036
{
1037
  direct_tx_callback_func = callback_tx;
157 tk 1038
 
1039
  return 0; // no error
155 tk 1040
}
1041
 
1042
 
1043
/////////////////////////////////////////////////////////////////////////////
281 tk 1044
//! Installs the Rx callback function which is executed immediately on each
1045
//! incoming/outgoing MIDI byte, partly from interrupt handlers.
1046
//!
1047
//! This function should be executed so fast as possible. It can be used
1048
//! to trigger MIDI Rx LEDs or to trigger on MIDI clock events. In order to
1049
//! avoid MIDI buffer overruns, the max. recommented execution time is 100 uS!
1050
//!
1051
//! It is possible to filter incoming MIDI bytes with the return value of the
1052
//! callback function.<BR>
1053
//! \param[in] *callback_rx pointer to callback function:<BR>
1054
//! \code
1055
//!    s32 callback_rx(mios32_midi_port_t port, u8 midi_byte);
1056
//! \endcode
1057
//! The byte will be forwarded into the MIDI Rx queue if the function returns 0.<BR>
1058
//! It will be filtered out if the callback returns != 0 (e.g. 1 for "filter", 
1059
//! or -1 for "error").
1060
//! \return < 0 on errors
1061
//! \note Please use the filtering capabilities with special care - if a port
1062
//! is filtered which is also used for code upload, you won't be able to exchange
1063
//! the erroneous code w/o starting the bootloader in hold mode after power-on.
155 tk 1064
/////////////////////////////////////////////////////////////////////////////
281 tk 1065
s32 MIOS32_MIDI_DirectRxCallback_Init(void *callback_rx)
155 tk 1066
{
281 tk 1067
  direct_rx_callback_func = callback_rx;
155 tk 1068
 
157 tk 1069
  return 0; // no error
155 tk 1070
}
1071
 
281 tk 1072
 
155 tk 1073
/////////////////////////////////////////////////////////////////////////////
211 tk 1074
//! This function is used by MIOS32 internal functions to forward received
281 tk 1075
//! MIDI bytes to the Rx Callback routine.
1076
//!
1077
//! It shouldn't be used by applications.
211 tk 1078
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
281 tk 1079
//! \param[in] midi_byte received MIDI byte
211 tk 1080
//! \return < 0 on errors
155 tk 1081
/////////////////////////////////////////////////////////////////////////////
281 tk 1082
s32 MIOS32_MIDI_SendByteToRxCallback(mios32_midi_port_t port, u8 midi_byte)
155 tk 1083
{
1084
  // note: here we could filter the user hook execution on special situations
281 tk 1085
  if( direct_rx_callback_func != NULL )
1086
    return direct_rx_callback_func(port, midi_byte);
157 tk 1087
  return 0; // no error
155 tk 1088
}
1089
 
1090
/////////////////////////////////////////////////////////////////////////////
211 tk 1091
//! This function is used by MIOS32 internal functions to forward received
281 tk 1092
//! MIDI packages to the Rx Callback routine (byte by byte)
1093
//!
1094
//! It shouldn't be used by applications.
211 tk 1095
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
281 tk 1096
//! \param[in] midi_package received MIDI package
211 tk 1097
//! \return < 0 on errors
155 tk 1098
/////////////////////////////////////////////////////////////////////////////
281 tk 1099
s32 MIOS32_MIDI_SendPackageToRxCallback(mios32_midi_port_t port, mios32_midi_package_t midi_package)
155 tk 1100
{
1101
  // note: here we could filter the user hook execution on special situations
281 tk 1102
  if( direct_rx_callback_func != NULL ) {
155 tk 1103
    u8 buffer[3] = {midi_package.evnt0, midi_package.evnt1, midi_package.evnt2};
1104
    int len = mios32_midi_pcktype_num_bytes[midi_package.cin];
1105
    int i;
283 tk 1106
    s32 status = 0;
155 tk 1107
    for(i=0; i<len; ++i)
281 tk 1108
      status |= direct_rx_callback_func(port, buffer[i]);
1109
    return status;
155 tk 1110
  }
157 tk 1111
  return 0; // no error
155 tk 1112
}
1113
 
225 tk 1114
 
1115
/////////////////////////////////////////////////////////////////////////////
1116
//! This function allows to change the DEFAULT port.<BR>
1117
//! The preset which will be used after application reset can be set in
1118
//! mios32_config.h via "#define MIOS32_MIDI_DEFAULT_PORT <port>".<BR>
1119
//! It's set to USB0 so long not overruled in mios32_config.h
1120
//! \param[in] port MIDI port (USB0..USB7, UART0..UART1, IIC0..IIC7)
1121
//! \return < 0 on errors
1122
/////////////////////////////////////////////////////////////////////////////
1123
s32 MIOS32_MIDI_DefaultPortSet(mios32_midi_port_t port)
1124
{
1125
  if( port == DEFAULT ) // avoid recursion
1126
    return -1;
1127
 
1128
  default_port = port;
1129
 
1130
  return 0; // no error
1131
}
1132
 
1133
/////////////////////////////////////////////////////////////////////////////
1134
//! This function returns the DEFAULT port
1135
//! \return the default port
1136
/////////////////////////////////////////////////////////////////////////////
1137
mios32_midi_port_t MIOS32_MIDI_DefaultPortGet(void)
1138
{
1139
  return default_port;
1140
}
1141
 
1142
 
1143
/////////////////////////////////////////////////////////////////////////////
307 tk 1144
//! This function allows to change the MIDI_DEBUG port.<BR>
1145
//! The preset which will be used after application reset can be set in
1146
//! mios32_config.h via "#define MIOS32_MIDI_DEBUG_PORT <port>".<BR>
1147
//! It's set to USB0 so long not overruled in mios32_config.h
1148
//! \param[in] port MIDI port (USB0..USB7, UART0..UART1, IIC0..IIC7)
1149
//! \return < 0 on errors
1150
/////////////////////////////////////////////////////////////////////////////
1151
s32 MIOS32_MIDI_DebugPortSet(mios32_midi_port_t port)
1152
{
1153
  if( port == MIDI_DEBUG ) // avoid recursion
1154
    return -1;
1155
 
1156
  debug_port = port;
1157
 
1158
  return 0; // no error
1159
}
1160
 
1161
/////////////////////////////////////////////////////////////////////////////
1162
//! This function returns the MIDI_DEBUG port
1163
//! \return the debug port
1164
/////////////////////////////////////////////////////////////////////////////
1165
mios32_midi_port_t MIOS32_MIDI_DebugPortGet(void)
1166
{
1167
  return debug_port;
1168
}
1169
 
1170
 
1171
/////////////////////////////////////////////////////////////////////////////
225 tk 1172
//! This function sets the SysEx Device ID, which is used during parsing
1173
//! incoming SysEx Requests to MIOS32<BR>
1174
//! It can also be used by an application for additional parsing with the same ID.<BR>
1175
//! ID changes will get lost after reset. It can be changed permanently by the
1176
//! user via Bootloader Command 0x0c
1177
//! \param[in] device_id a new (temporary) device ID (0x00..0x7f)
1178
//! \return < 0 on errors
1179
/////////////////////////////////////////////////////////////////////////////
1180
s32 MIOS32_MIDI_DeviceIDSet(u8 device_id)
1181
{
1182
  sysex_device_id = device_id & 0x7f;
1183
  return 0; // no error
1184
}
1185
 
1186
/////////////////////////////////////////////////////////////////////////////
1187
//! This function returns the SysEx Device ID, which is used during parsing
1188
//! incoming SysEx Requests to MIOS32<BR>
1189
//! It can also be used by an application for additional parsing with the same ID.<BR>
1190
//! The initial ID is stored inside the BSL range and will be recovered after
1191
//! reset. It can be changed by the user via Bootloader Command 0x0c
1192
//! \return SysEx device ID (0x00..0x7f)
1193
//! \todo store device ID via BSL based EEPROM emulation
1194
/////////////////////////////////////////////////////////////////////////////
1195
u8 MIOS32_MIDI_DeviceIDGet(void)
1196
{
1197
  return sysex_device_id;
1198
}
1199
 
1200
 
1201
/////////////////////////////////////////////////////////////////////////////
1202
// This function parses an incoming sysex stream for MIOS32 commands
1203
/////////////////////////////////////////////////////////////////////////////
1204
static s32 MIOS32_MIDI_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in)
1205
{
1206
  // ignore realtime messages (see MIDI spec - realtime messages can
1207
  // always be injected into events/streams, and don't change the running status)
1208
  if( midi_in >= 0xf8 )
1209
    return 0;
1210
 
1211
  // TODO: here we could send an error notification, that multiple devices are trying to access the device
1212
  if( sysex_state.MY_SYSEX && port != last_sysex_port )
1213
    return -1;
1214
 
1215
  last_sysex_port = port;
1216
 
1217
  // branch depending on state
1218
  if( !sysex_state.MY_SYSEX ) {
1219
    if( (sysex_state.CTR < sizeof(mios32_midi_sysex_header) && midi_in != mios32_midi_sysex_header[sysex_state.CTR]) ||
1220
    (sysex_state.CTR == sizeof(mios32_midi_sysex_header) && midi_in != sysex_device_id) ) {
1221
      // incoming byte doesn't match
1222
      MIOS32_MIDI_SYSEX_CmdFinished();
1223
    } else {
1224
      if( ++sysex_state.CTR > sizeof(mios32_midi_sysex_header) ) {
1225
    // complete header received, waiting for data
1226
    sysex_state.MY_SYSEX = 1;
1227
      }
1228
    }
1229
  } else {
1230
    // check for end of SysEx message or invalid status byte
1231
    if( midi_in >= 0x80 ) {
1232
      if( midi_in == 0xf7 && sysex_state.CMD ) {
1233
        MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_END, midi_in);
1234
      }
1235
      MIOS32_MIDI_SYSEX_CmdFinished();
1236
    } else {
1237
      // check if command byte has been received
1238
      if( !sysex_state.CMD ) {
1239
    sysex_state.CMD = 1;
1240
    sysex_cmd = midi_in;
1241
    MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN, midi_in);
1242
      }
1243
      else
1244
    MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_CONT, midi_in);
1245
    }
1246
  }
1247
 
1248
  return 0; // no error
1249
}
1250
 
1251
 
1252
/////////////////////////////////////////////////////////////////////////////
1253
// This function is called at the end of a sysex command or on 
1254
// an invalid message
1255
/////////////////////////////////////////////////////////////////////////////
1256
static s32 MIOS32_MIDI_SYSEX_CmdFinished(void)
1257
{
1258
  // clear all status variables
1259
  sysex_state.ALL = 0;
1260
  sysex_cmd = 0;
1261
 
1262
  return 0; // no error
1263
}
1264
 
1265
/////////////////////////////////////////////////////////////////////////////
1266
// This function handles the sysex commands
1267
/////////////////////////////////////////////////////////////////////////////
1268
static s32 MIOS32_MIDI_SYSEX_Cmd(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
1269
{
238 tk 1270
#if MIOS32_MIDI_BSL_ENHANCEMENTS
1271
  // this compile switch should only be activated for the bootloader!
1272
  if( BSL_SYSEX_Cmd(port, cmd_state, midi_in, sysex_cmd) >= 0 )
1273
    return 0; // BSL has serviced this command - no error
1274
#endif
225 tk 1275
  switch( sysex_cmd ) {
1276
    case 0x00:
230 tk 1277
      MIOS32_MIDI_SYSEX_Cmd_Query(port, cmd_state, midi_in);
225 tk 1278
      break;
1279
    case 0x0f:
1280
      MIOS32_MIDI_SYSEX_Cmd_Ping(port, cmd_state, midi_in);
1281
      break;
1282
    default:
1283
      // unknown command
1284
      // TODO: send 0xf7 if merger enabled
1285
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_INVALID_COMMAND);
1286
      MIOS32_MIDI_SYSEX_CmdFinished();      
1287
  }
1288
 
1289
  return 0; // no error
1290
}
1291
 
1292
 
1293
 
1294
/////////////////////////////////////////////////////////////////////////////
230 tk 1295
// Command 00: Query core informations and request BSL entry
225 tk 1296
/////////////////////////////////////////////////////////////////////////////
230 tk 1297
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 1298
{
230 tk 1299
  static u8 query_req = 0;
1300
  char str_buffer[40];
225 tk 1301
 
1302
  switch( cmd_state ) {
1303
 
1304
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
230 tk 1305
      query_req = 0;
225 tk 1306
      break;
1307
 
1308
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
230 tk 1309
      query_req = midi_in;
1310
      break;
1311
 
1312
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
1313
      switch( query_req ) {
1314
        case 0x01: // operating system
1315
      MIOS32_MIDI_SYSEX_SendAckStr(port, "MIOS32");
225 tk 1316
      break;
237 tk 1317
        case 0x02: // Board
230 tk 1318
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_BOARD_STR);
225 tk 1319
      break;
230 tk 1320
        case 0x03: // Core Family
1321
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_FAMILY_STR);
225 tk 1322
      break;
230 tk 1323
        case 0x04: // Chip ID
1324
      sprintf(str_buffer, "%08x", MIOS32_SYS_ChipIDGet());
1325
      MIOS32_MIDI_SYSEX_SendAckStr(port, (char *)str_buffer);
1326
      break;
1327
        case 0x05: // Serial Number
1328
      if( MIOS32_SYS_SerialNumberGet((char *)str_buffer) >= 0 )
1329
        MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1330
      else
1331
        MIOS32_MIDI_SYSEX_SendAckStr(port, "?");
1332
      break;
1333
        case 0x06: // Flash Memory Size
1334
      sprintf(str_buffer, "%d", MIOS32_SYS_FlashSizeGet());
1335
      MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1336
      break;
1337
        case 0x07: // RAM Memory Size
1338
      sprintf(str_buffer, "%d", MIOS32_SYS_RAMSizeGet());
1339
      MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1340
      break;
1341
        case 0x08: // Application Name Line #1
1342
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_LCD_BOOT_MSG_LINE1);
1343
      break;
1344
        case 0x09: // Application Name Line #2
1345
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_LCD_BOOT_MSG_LINE2);
1346
      break;
1347
        case 0x7f:
231 tk 1348
#if MIOS32_MIDI_BSL_ENHANCEMENTS
1349
      // release halt state (or sending upload request) instead of reseting the core
1350
      BSL_SYSEX_ReleaseHaltState();
1351
#else
230 tk 1352
      // reset core (this will send an upload request)
1353
      MIOS32_SYS_Reset();
1354
      // at least on STM32 we will never reach this point
1355
      // but other core families could contain an empty stumb!
231 tk 1356
#endif
230 tk 1357
      break;
1358
        default:
1359
      // unknown query
1360
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_UNKNOWN_QUERY);
225 tk 1361
      }
1362
  }
1363
 
1364
  return 0; // no error
1365
}
1366
 
1367
/////////////////////////////////////////////////////////////////////////////
1368
// Command 0F: Ping (just send back acknowledge)
1369
/////////////////////////////////////////////////////////////////////////////
1370
static s32 MIOS32_MIDI_SYSEX_Cmd_Ping(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
1371
{
1372
  switch( cmd_state ) {
1373
 
1374
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
1375
      // nothing to do
1376
      break;
1377
 
1378
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
1379
      // nothing to do
1380
      break;
1381
 
1382
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
1383
      // TODO: send 0xf7 if merger enabled
1384
 
1385
      // send acknowledge
1386
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_ACK, 0x00);
1387
 
1388
      break;
1389
  }
1390
 
1391
  return 0; // no error
1392
}
1393
 
1394
/////////////////////////////////////////////////////////////////////////////
1395
// This function sends a SysEx acknowledge to notify the user about the received command
1396
// expects acknowledge code (e.g. 0x0f for good, 0x0e for error) and additional argument
1397
/////////////////////////////////////////////////////////////////////////////
1398
static s32 MIOS32_MIDI_SYSEX_SendAck(mios32_midi_port_t port, u8 ack_code, u8 ack_arg)
1399
{
1400
  u8 sysex_buffer[32]; // should be enough?
1401
  u8 *sysex_buffer_ptr = &sysex_buffer[0];
1402
  int i;
1403
 
1404
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
1405
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
1406
 
1407
  // device ID
1408
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
1409
 
1410
  // send ack code and argument
1411
  *sysex_buffer_ptr++ = ack_code;
1412
  *sysex_buffer_ptr++ = ack_arg;
1413
 
1414
  // send footer
1415
  *sysex_buffer_ptr++ = 0xf7;
1416
 
1417
  // finally send SysEx stream
1418
  return MIOS32_MIDI_SendSysEx(port, (u8 *)sysex_buffer, (u32)sysex_buffer_ptr - ((u32)&sysex_buffer[0]));
1419
}
1420
 
230 tk 1421
/////////////////////////////////////////////////////////////////////////////
1422
// This function sends an SysEx acknowledge with a string (used on queries)
1423
/////////////////////////////////////////////////////////////////////////////
1424
static s32 MIOS32_MIDI_SYSEX_SendAckStr(mios32_midi_port_t port, char *str)
1425
{
1426
  u8 sysex_buffer[128]; // should be enough?
1427
  u8 *sysex_buffer_ptr = &sysex_buffer[0];
1428
  int i;
225 tk 1429
 
230 tk 1430
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
1431
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
155 tk 1432
 
230 tk 1433
  // device ID
1434
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
1435
 
1436
  // send ack code
1437
  *sysex_buffer_ptr++ = MIOS32_MIDI_SYSEX_ACK;
1438
 
1439
  // send string
307 tk 1440
  for(i=0; i<100 && (str[i] != 0); ++i)
230 tk 1441
    *sysex_buffer_ptr++ = str[i];
1442
 
1443
  // send footer
1444
  *sysex_buffer_ptr++ = 0xf7;
1445
 
1446
  // finally send SysEx stream
1447
  return MIOS32_MIDI_SendSysEx(port, (u8 *)sysex_buffer, (u32)sysex_buffer_ptr - ((u32)&sysex_buffer[0]));
1448
}
1449
 
32 tk 1450
#endif /* MIOS32_DONT_USE_MIDI */