Subversion Repositories svn.mios32

Rev

Rev 1328 | Rev 1541 | 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 1477 2012-05-01 18:40:34Z 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;
624 tk 105
    unsigned MY_SYSEX:1;
225 tk 106
    unsigned CMD:1;
107
  };
623 tk 108
 
109
  struct {
110
    unsigned CTR:3;
624 tk 111
    unsigned MY_SYSEX:1;
623 tk 112
    unsigned CMD:1;
113
    unsigned PING_BYTE_RECEIVED;
114
  };
225 tk 115
} sysex_state_t;
116
 
117
 
550 tk 118
typedef union {
119
  struct {
120
    unsigned ALL:32;
121
  };
122
 
123
  struct {
124
    unsigned usb_receives:16;
125
    unsigned iic_receives:16;
126
  };
127
} sysex_timeout_ctr_flags_t;
128
 
129
 
225 tk 130
/////////////////////////////////////////////////////////////////////////////
32 tk 131
// Local variables
132
/////////////////////////////////////////////////////////////////////////////
133
 
225 tk 134
static mios32_midi_port_t default_port = MIOS32_MIDI_DEFAULT_PORT;
307 tk 135
static mios32_midi_port_t debug_port   = MIOS32_MIDI_DEBUG_PORT;
225 tk 136
 
281 tk 137
static s32 (*direct_rx_callback_func)(mios32_midi_port_t port, u8 midi_byte);
138
static s32 (*direct_tx_callback_func)(mios32_midi_port_t port, mios32_midi_package_t package);
674 tk 139
static s32 (*sysex_callback_func)(mios32_midi_port_t port, u8 sysex_byte);
529 tk 140
static s32 (*timeout_callback_func)(mios32_midi_port_t port);
582 tk 141
static s32 (*debug_command_callback_func)(mios32_midi_port_t port, char c);
32 tk 142
 
225 tk 143
static sysex_state_t sysex_state;
144
static u8 sysex_device_id;
145
static u8 sysex_cmd;
146
static mios32_midi_port_t last_sysex_port = DEFAULT;
155 tk 147
 
225 tk 148
 
550 tk 149
// SysEx timeout counter: in order to save memory and execution time, we only
150
// protect a single SysEx stream for packet oriented interfaces.
151
// Serial interfaces (UART) are protected separately -> see MIOS32_UART_MIDI_PackageReceive
152
// Approach: the first interface which sends F0 resets the timeout counter.
153
// The flag is reset with F7
154
// Once one second has passed, and the flag is still set, MIOS32_MIDI_TimeOut() will
155
// be called to notify the failure.
156
// Drawback: if another interface starts a SysEx transfer at the same time, the stream
157
// will be ignored, and a timeout won't be detected.
158
// It's unlikely that this is an issue in practice, especially if SysEx parsers only
159
// take streams of the first interface which sends F0 like MIOS32_MIDI_SYSEX_Parser()...
160
//
161
// If a stronger protection is desired (SysEx parser handles streams of multiple interfaces),
162
// it's recommented to implement a separate timeout mechanism at application side.
163
static u16 sysex_timeout_ctr;
164
static sysex_timeout_ctr_flags_t sysex_timeout_ctr_flags;
165
 
166
 
32 tk 167
/////////////////////////////////////////////////////////////////////////////
225 tk 168
// Local prototypes
169
/////////////////////////////////////////////////////////////////////////////
170
 
171
static s32 MIOS32_MIDI_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in);
172
static s32 MIOS32_MIDI_SYSEX_CmdFinished(void);
173
static s32 MIOS32_MIDI_SYSEX_Cmd(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in);
230 tk 174
static s32 MIOS32_MIDI_SYSEX_Cmd_Query(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in);
582 tk 175
static s32 MIOS32_MIDI_SYSEX_Cmd_Debug(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in);
225 tk 176
static s32 MIOS32_MIDI_SYSEX_Cmd_Ping(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in);
177
static s32 MIOS32_MIDI_SYSEX_SendAck(mios32_midi_port_t port, u8 ack_code, u8 ack_arg);
230 tk 178
static s32 MIOS32_MIDI_SYSEX_SendAckStr(mios32_midi_port_t port, char *str);
529 tk 179
static s32 MIOS32_MIDI_TimeOut(mios32_midi_port_t port);
225 tk 180
 
181
 
182
/////////////////////////////////////////////////////////////////////////////
211 tk 183
//! Initializes MIDI layer
184
//! \param[in] mode currently only mode 0 supported
185
//! \return < 0 if initialisation failed
32 tk 186
/////////////////////////////////////////////////////////////////////////////
187
s32 MIOS32_MIDI_Init(u32 mode)
188
{
189
  s32 ret = 0;
190
 
110 tk 191
  // currently only mode 0 supported
192
  if( mode != 0 )
32 tk 193
    return -1; // unsupported mode
194
 
307 tk 195
  // set default/debug port as defined in mios32.h/mios32_config.h
225 tk 196
  default_port = MIOS32_MIDI_DEFAULT_PORT;
307 tk 197
  debug_port = MIOS32_MIDI_DEBUG_PORT;
225 tk 198
 
582 tk 199
  // disable callback functions
155 tk 200
  direct_rx_callback_func = NULL;
201
  direct_tx_callback_func = NULL;
674 tk 202
  sysex_callback_func = NULL;
203
  timeout_callback_func = NULL;
582 tk 204
  debug_command_callback_func = NULL;
529 tk 205
 
155 tk 206
  // initialize interfaces
101 tk 207
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
110 tk 208
  if( MIOS32_USB_MIDI_Init(0) < 0 )
32 tk 209
    ret |= (1 << 0);
210
#endif
211
 
80 tk 212
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
110 tk 213
  if( MIOS32_UART_MIDI_Init(0) < 0 )
80 tk 214
    ret |= (1 << 1);
215
#endif
216
 
78 tk 217
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
110 tk 218
  if( MIOS32_IIC_MIDI_Init(0) < 0 )
80 tk 219
    ret |= (1 << 2);
78 tk 220
#endif
221
 
225 tk 222
  last_sysex_port = DEFAULT;
223
  sysex_state.ALL = 0;
224
 
225
  sysex_device_id = 0x00;
1307 tk 226
#ifdef MIOS32_SYS_ADDR_BSL_INFO_BEGIN
227
  // read from bootloader info range
228
  u8 *device_id_confirm = (u8 *)MIOS32_SYS_ADDR_DEVICE_ID_CONFIRM;
229
  u8 *device_id = (u8 *)MIOS32_SYS_ADDR_DEVICE_ID;
230
  if( *device_id_confirm == 0x42 && *device_id < 0x80 )
1300 tk 231
    sysex_device_id = *device_id;
232
#endif
225 tk 233
 
550 tk 234
  // SysEx timeout mechanism
235
  sysex_timeout_ctr = 0;
236
  sysex_timeout_ctr_flags.ALL = 0;
237
 
32 tk 238
  return -ret;
239
}
240
 
241
 
242
/////////////////////////////////////////////////////////////////////////////
211 tk 243
//! This function checks the availability of a MIDI port
1328 tk 244
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
211 tk 245
//! \return 1: port available
246
//! \return 0: port not available
78 tk 247
/////////////////////////////////////////////////////////////////////////////
248
s32 MIOS32_MIDI_CheckAvailable(mios32_midi_port_t port)
249
{
307 tk 250
  // if default/debug port: select mapped port
78 tk 251
  if( !(port & 0xf0) ) {
307 tk 252
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
78 tk 253
  }
254
 
255
  // branch depending on selected port
550 tk 256
  switch( port & 0xf0 ) {
257
    case USB0://..15
78 tk 258
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
1259 tk 259
      return MIOS32_USB_MIDI_CheckAvailable(port & 0xf);
78 tk 260
#else
261
      return 0; // USB has been disabled
262
#endif
263
 
550 tk 264
    case UART0://..15
80 tk 265
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
266
      return MIOS32_UART_MIDI_CheckAvailable(port & 0xf);
267
#else
268
      return 0; // UART_MIDI has been disabled
269
#endif
78 tk 270
 
550 tk 271
    case IIC0://..15
78 tk 272
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
273
      return MIOS32_IIC_MIDI_CheckAvailable(port & 0xf);
274
#else
275
      return 0; // IIC_MIDI has been disabled
276
#endif
277
  }
528 tk 278
 
279
  return 0; // invalid port
78 tk 280
}
281
 
282
 
283
/////////////////////////////////////////////////////////////////////////////
528 tk 284
//! This function enables/disables running status optimisation for a given
285
//! MIDI OUT port to improve bandwidth if MIDI events with the same
286
//! status byte are sent back-to-back.<BR>
287
//! The optimisation is currently only used for UART based port (enabled by
288
//! default), IIC: TODO, USB: not required).
1328 tk 289
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
528 tk 290
//! \param[in] enable 0=optimisation disabled, 1=optimisation enabled
291
//! \return -1 if port not available or if it doesn't support running status
292
//! \return 0 on success
293
/////////////////////////////////////////////////////////////////////////////
294
s32 MIOS32_MIDI_RS_OptimisationSet(mios32_midi_port_t port, u8 enable)
295
{
296
  // if default/debug port: select mapped port
297
  if( !(port & 0xf0) ) {
298
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
299
  }
300
 
301
  // branch depending on selected port
550 tk 302
  switch( port & 0xf0 ) {
303
    case USB0://..15
528 tk 304
      return -1; // not required for USB
305
 
550 tk 306
    case UART0://..15
528 tk 307
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
308
      return MIOS32_UART_MIDI_RS_OptimisationSet(port & 0xf, enable);
309
#else
310
      return -1; // UART_MIDI has been disabled
311
#endif
312
 
550 tk 313
    case IIC0://..15
528 tk 314
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
315
      return MIOS32_IIC_MIDI_RS_OptimisationSet(port & 0xf, enable);
316
#else
317
      return -1; // IIC_MIDI has been disabled
318
#endif
319
  }
320
 
321
  return -1; // invalid port
322
}
323
 
324
 
325
/////////////////////////////////////////////////////////////////////////////
326
//! This function returns the running status optimisation enable/disable flag
327
//! for the given MIDI OUT port.
1328 tk 328
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
528 tk 329
//! \return -1 if port not available or if it doesn't support running status
330
//! \return 0 if optimisation disabled
331
//! \return 1 if optimisation enabled
332
/////////////////////////////////////////////////////////////////////////////
333
s32 MIOS32_MIDI_RS_OptimisationGet(mios32_midi_port_t port)
334
{
335
  // if default/debug port: select mapped port
336
  if( !(port & 0xf0) ) {
337
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
338
  }
339
 
340
  // branch depending on selected port
550 tk 341
  switch( port & 0xf0 ) {
342
    case USB0://..15
528 tk 343
      return -1; // not required for USB
344
 
550 tk 345
    case UART0://..15
528 tk 346
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
347
      return MIOS32_UART_MIDI_RS_OptimisationGet(port & 0xf);
348
#else
349
      return -1; // UART_MIDI has been disabled
350
#endif
351
 
550 tk 352
    case IIC0://..15
528 tk 353
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
354
      return MIOS32_IIC_MIDI_RS_OptimisationGet(port & 0xf);
355
#else
356
      return -1; // IIC_MIDI has been disabled
357
#endif
358
  }
359
 
360
  return -1; // invalid port
361
}
362
 
363
 
364
/////////////////////////////////////////////////////////////////////////////
365
//! This function resets the current running status, so that it will be sent
366
//! again with the next MIDI Out package.
1328 tk 367
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
528 tk 368
//! \return -1 if port not available or if it doesn't support running status
369
//! \return 0 if optimisation disabled
370
//! \return 1 if optimisation enabled
371
/////////////////////////////////////////////////////////////////////////////
372
s32 MIOS32_MIDI_RS_Reset(mios32_midi_port_t port)
373
{
374
  // if default/debug port: select mapped port
375
  if( !(port & 0xf0) ) {
376
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
377
  }
378
 
379
  // branch depending on selected port
550 tk 380
  switch( port & 0xf0 ) {
381
    case USB0://..15
528 tk 382
      return -1; // not required for USB
383
 
550 tk 384
    case UART0://..15
528 tk 385
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
386
      return MIOS32_UART_MIDI_RS_Reset(port & 0xf);
387
#else
388
      return -1; // UART_MIDI has been disabled
389
#endif
390
 
550 tk 391
    case IIC0://..15
528 tk 392
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
393
      return MIOS32_IIC_MIDI_RS_Reset(port & 0xf);
394
#else
395
      return -1; // IIC_MIDI has been disabled
396
#endif
397
  }
398
 
399
  return -1; // invalid port
400
}
401
 
402
 
403
/////////////////////////////////////////////////////////////////////////////
211 tk 404
//! Sends a package over given port
281 tk 405
//!
211 tk 406
//! This is a low level function. In difference to other MIOS32_MIDI_Send* functions,
407
//! It allows to send packages in non-blocking mode (caller has to retry if -2 is returned)
281 tk 408
//!
409
//! Before the package is forwarded, an optional Tx Callback function will be called
410
//! which allows to filter/monitor/route the package, or extend the MIDI transmitter
411
//! by custom MIDI Output ports (e.g. for internal busses, OSC, AOUT, etc.)
1328 tk 412
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
211 tk 413
//! \param[in] package MIDI package
414
//! \return -1 if port not available
415
//! \return -2 buffer is full
416
//!         caller should retry until buffer is free again
281 tk 417
//! \return -3 Tx Callback reported an error
418
//! \return 1 if package has been filtered by Tx callback
211 tk 419
//! \return 0 on success
110 tk 420
/////////////////////////////////////////////////////////////////////////////
421
s32 MIOS32_MIDI_SendPackage_NonBlocking(mios32_midi_port_t port, mios32_midi_package_t package)
422
{
307 tk 423
  // if default/debug port: select mapped port
110 tk 424
  if( !(port & 0xf0) ) {
307 tk 425
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
110 tk 426
  }
427
 
428
  // insert subport number into package
429
  package.cable = port & 0xf;
430
 
281 tk 431
  // forward to Tx callback function and break if package has been filtered
432
  if( direct_tx_callback_func != NULL ) {
433
    s32 status;
425 tk 434
    if( (status=direct_tx_callback_func(port, package)) )
281 tk 435
      return status;
436
  }
437
 
110 tk 438
  // branch depending on selected port
550 tk 439
  switch( port & 0xf0 ) {
440
    case USB0://..15
110 tk 441
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 442
      return MIOS32_USB_MIDI_PackageSend_NonBlocking(package);
110 tk 443
#else
444
      return -1; // USB has been disabled
445
#endif
446
 
550 tk 447
    case UART0://..15
110 tk 448
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
449
      return MIOS32_UART_MIDI_PackageSend_NonBlocking(package.cable, package);
450
#else
451
      return -1; // UART_MIDI has been disabled
452
#endif
453
 
550 tk 454
    case IIC0://..15
110 tk 455
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
456
      return MIOS32_IIC_MIDI_PackageSend_NonBlocking(package.cable, package);
457
#else
458
      return -1; // IIC_MIDI has been disabled
459
#endif
460
 
461
    default:
462
      // invalid port
463
      return -1;
464
  }
465
}
466
 
467
 
468
/////////////////////////////////////////////////////////////////////////////
211 tk 469
//! Sends a package over given port
470
//! This is a low level function - use the remaining MIOS32_MIDI_Send* functions
471
//! to send specific MIDI events
472
//! (blocking function)
1328 tk 473
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
211 tk 474
//! \param[in] package MIDI package
475
//! \return -1 if port not available
476
//! \return 0 on success
32 tk 477
/////////////////////////////////////////////////////////////////////////////
69 tk 478
s32 MIOS32_MIDI_SendPackage(mios32_midi_port_t port, mios32_midi_package_t package)
32 tk 479
{
307 tk 480
  // if default/debug port: select mapped port
80 tk 481
  if( !(port & 0xf0) ) {
307 tk 482
    port = (port == MIDI_DEBUG) ? debug_port : default_port;
80 tk 483
  }
484
 
32 tk 485
  // insert subport number into package
89 tk 486
  package.cable = port & 0xf;
32 tk 487
 
301 tk 488
  // forward to Tx callback function and break if package has been filtered
489
  if( direct_tx_callback_func != NULL ) {
490
    s32 status;
425 tk 491
    if( (status=direct_tx_callback_func(port, package)) )
301 tk 492
      return status;
493
  }
494
 
32 tk 495
  // branch depending on selected port
550 tk 496
  switch( port & 0xf0 ) {
497
    case USB0://..15
78 tk 498
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 499
      return MIOS32_USB_MIDI_PackageSend(package);
32 tk 500
#else
501
      return -1; // USB has been disabled
502
#endif
503
 
550 tk 504
    case UART0://..15
80 tk 505
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
506
      return MIOS32_UART_MIDI_PackageSend(package.cable, package);
507
#else
508
      return -1; // UART_MIDI has been disabled
509
#endif
32 tk 510
 
550 tk 511
    case IIC0://..15
78 tk 512
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
513
      return MIOS32_IIC_MIDI_PackageSend(package.cable, package);
514
#else
515
      return -1; // IIC_MIDI has been disabled
516
#endif
32 tk 517
 
518
    default:
519
      // invalid port
520
      return -1;
521
  }
522
}
523
 
524
 
525
/////////////////////////////////////////////////////////////////////////////
211 tk 526
//! Sends a MIDI Event
527
//! This function is provided for a more comfortable use model
528
//!    o MIOS32_MIDI_SendNoteOff(port, chn, note, vel)
529
//!    o MIOS32_MIDI_SendNoteOn(port, chn, note, vel)
530
//!    o MIOS32_MIDI_SendPolyAftertouch(port, chn, note, val)
531
//!    o MIOS32_MIDI_SendCC(port, chn, cc, val)
532
//!    o MIOS32_MIDI_SendProgramChange(port, chn, prg)
533
//!    o MIOS32_MIDI_ChannelAftertouch(port, chn, val)
534
//!    o MIOS32_MIDI_PitchBend(port, chn, val)
535
//!
1328 tk 536
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
211 tk 537
//! \param[in] evnt0 first MIDI byte
225 tk 538
//! \param[in] evnt1 second MIDI byte
539
//! \param[in] evnt2 third MIDI byte
211 tk 540
//! \return -1 if port not available
541
//! \return 0 on success
32 tk 542
/////////////////////////////////////////////////////////////////////////////
69 tk 543
s32 MIOS32_MIDI_SendEvent(mios32_midi_port_t port, u8 evnt0, u8 evnt1, u8 evnt2)
32 tk 544
{
33 tk 545
  mios32_midi_package_t package;
546
 
547
  // MEMO: don't optimize this function by calling MIOS32_MIDI_SendSpecialEvent
548
  // from here, because the 4 * u8 parameter list of this function leads
549
  // to best compile results (4*u8 combined to a single u32)
550
 
551
  package.type  = evnt0 >> 4;
552
  package.evnt0 = evnt0;
553
  package.evnt1 = evnt1;
554
  package.evnt2 = evnt2;
555
  return MIOS32_MIDI_SendPackage(port, package);
32 tk 556
}
557
 
69 tk 558
s32 MIOS32_MIDI_SendNoteOff(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 vel)
136 tk 559
{ return MIOS32_MIDI_SendEvent(port, 0x80 | chn, note, vel); }
32 tk 560
 
69 tk 561
s32 MIOS32_MIDI_SendNoteOn(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 vel)
136 tk 562
{ return MIOS32_MIDI_SendEvent(port, 0x90 | chn, note, vel); }
69 tk 563
 
564
s32 MIOS32_MIDI_SendPolyPressure(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 val)
136 tk 565
{ return MIOS32_MIDI_SendEvent(port, 0xa0 | chn, note, val); }
69 tk 566
 
681 tk 567
s32 MIOS32_MIDI_SendCC(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 cc_number, u8 val)
568
{ return MIOS32_MIDI_SendEvent(port, 0xb0 | chn, cc_number,   val); }
69 tk 569
 
570
s32 MIOS32_MIDI_SendProgramChange(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 prg)
136 tk 571
{ return MIOS32_MIDI_SendEvent(port, 0xc0 | chn, prg,  0x00); }
69 tk 572
 
573
s32 MIOS32_MIDI_SendAftertouch(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 val)
136 tk 574
{ return MIOS32_MIDI_SendEvent(port, 0xd0 | chn, val,  0x00); }
69 tk 575
 
576
s32 MIOS32_MIDI_SendPitchBend(mios32_midi_port_t port, mios32_midi_chn_t chn, u16 val)
136 tk 577
{ return MIOS32_MIDI_SendEvent(port, 0xe0 | chn, val & 0x7f, val >> 7); }
69 tk 578
 
579
 
33 tk 580
/////////////////////////////////////////////////////////////////////////////
211 tk 581
//! Sends a special type MIDI Event
582
//! This function is provided for a more comfortable use model
583
//! It is aliased to following functions
584
//!    o MIOS32_MIDI_SendMTC(port, val)
585
//!    o MIOS32_MIDI_SendSongPosition(port, val)
586
//!    o MIOS32_MIDI_SendSongSelect(port, val)
587
//!    o MIOS32_MIDI_SendTuneRequest()
588
//!    o MIOS32_MIDI_SendClock()
589
//!    o MIOS32_MIDI_SendTick()
590
//!    o MIOS32_MIDI_SendStart()
591
//!    o MIOS32_MIDI_SendStop()
592
//!    o MIOS32_MIDI_SendContinue()
593
//!    o MIOS32_MIDI_SendActiveSense()
594
//!    o MIOS32_MIDI_SendReset()
595
//!
1328 tk 596
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
211 tk 597
//! \param[in] type the event type
598
//! \param[in] evnt0 first MIDI byte
225 tk 599
//! \param[in] evnt1 second MIDI byte
600
//! \param[in] evnt2 third MIDI byte
211 tk 601
//! \return -1 if port not available
602
//! \return 0 on success
33 tk 603
/////////////////////////////////////////////////////////////////////////////
69 tk 604
s32 MIOS32_MIDI_SendSpecialEvent(mios32_midi_port_t port, u8 type, u8 evnt0, u8 evnt1, u8 evnt2)
33 tk 605
{
606
  mios32_midi_package_t package;
607
 
608
  package.type  = type;
609
  package.evnt0 = evnt0;
610
  package.evnt1 = evnt1;
611
  package.evnt2 = evnt2;
612
  return MIOS32_MIDI_SendPackage(port, package);
613
}
614
 
615
 
69 tk 616
s32 MIOS32_MIDI_SendMTC(mios32_midi_port_t port, u8 val)
136 tk 617
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x2, 0xf1, val, 0x00); }
69 tk 618
 
619
s32 MIOS32_MIDI_SendSongPosition(mios32_midi_port_t port, u16 val)
136 tk 620
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x3, 0xf2, val & 0x7f, val >> 7); }
69 tk 621
 
622
s32 MIOS32_MIDI_SendSongSelect(mios32_midi_port_t port, u8 val)
136 tk 623
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x2, 0xf3, val, 0x00); }
69 tk 624
 
625
s32 MIOS32_MIDI_SendTuneRequest(mios32_midi_port_t port)
136 tk 626
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf6, 0x00, 0x00); }
69 tk 627
 
628
s32 MIOS32_MIDI_SendClock(mios32_midi_port_t port)
136 tk 629
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf8, 0x00, 0x00); }
69 tk 630
 
631
s32 MIOS32_MIDI_SendTick(mios32_midi_port_t port)
136 tk 632
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf9, 0x00, 0x00); }
69 tk 633
 
634
s32 MIOS32_MIDI_SendStart(mios32_midi_port_t port)
136 tk 635
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfa, 0x00, 0x00); }
69 tk 636
 
397 stryd_one 637
s32 MIOS32_MIDI_SendContinue(mios32_midi_port_t port)
136 tk 638
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfb, 0x00, 0x00); }
69 tk 639
 
397 stryd_one 640
s32 MIOS32_MIDI_SendStop(mios32_midi_port_t port)
136 tk 641
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfc, 0x00, 0x00); }
69 tk 642
 
643
s32 MIOS32_MIDI_SendActiveSense(mios32_midi_port_t port)
136 tk 644
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfe, 0x00, 0x00); }
69 tk 645
 
646
s32 MIOS32_MIDI_SendReset(mios32_midi_port_t port)
136 tk 647
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xff, 0x00, 0x00); }
69 tk 648
 
649
 
33 tk 650
/////////////////////////////////////////////////////////////////////////////
211 tk 651
//! Sends a SysEx Stream
307 tk 652
//!
211 tk 653
//! This function is provided for a more comfortable use model
1328 tk 654
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
211 tk 655
//! \param[in] stream pointer to SysEx stream
656
//! \param[in] count number of bytes
657
//! \return -1 if port not available
658
//! \return 0 on success
33 tk 659
/////////////////////////////////////////////////////////////////////////////
69 tk 660
s32 MIOS32_MIDI_SendSysEx(mios32_midi_port_t port, u8 *stream, u32 count)
33 tk 661
{
662
  s32 res;
663
  u32 offset;
664
  mios32_midi_package_t package;
665
 
666
  // MEMO: have a look into the project.lss file - gcc optimizes this code pretty well :)
667
 
668
  for(offset=0; offset<count;) {
669
    // package type depends on number of remaining bytes
670
    switch( count-offset ) {
671
      case 1:
672
    package.type = 0x5; // SysEx ends with following single byte. 
673
    package.evnt0 = stream[offset++];
674
    package.evnt1 = 0x00;
675
    package.evnt2 = 0x00;
676
    break;
677
      case 2:
678
    package.type = 0x6; // SysEx ends with following two bytes.
679
    package.evnt0 = stream[offset++];
680
    package.evnt1 = stream[offset++];
681
    package.evnt2 = 0x00;
682
    break;
683
      case 3:
684
    package.type = 0x7; // SysEx ends with following three bytes. 
685
    package.evnt0 = stream[offset++];
686
    package.evnt1 = stream[offset++];
687
    package.evnt2 = stream[offset++];
688
    break;
689
      default:
690
    package.type = 0x4; // SysEx starts or continues
691
    package.evnt0 = stream[offset++];
692
    package.evnt1 = stream[offset++];
693
    package.evnt2 = stream[offset++];
694
    }
695
 
110 tk 696
    res=MIOS32_MIDI_SendPackage(port, package);
33 tk 697
 
110 tk 698
    // expection? (e.g., port not available)
33 tk 699
    if( res < 0 )
700
      return res;
701
  }
702
 
703
  return 0;
704
}
705
 
706
 
707
/////////////////////////////////////////////////////////////////////////////
307 tk 708
//! Sends a formatted Debug Message to the MIOS Terminal in MIOS Studio.
709
//!
710
//! Formatting parameters are like known from printf, e.g.
711
//! \code
712
//!   MIOS32_MIDI_SendDebugMessage("Button %d %s\n", button, value ? "depressed" : "pressed");
713
//! \endcode
714
//!
715
//! The MIDI port used for debugging (MIDI_DEBUG) can be declared in mios32_config.h:
716
//! \code
717
//!   #define MIOS32_MIDI_DEBUG_PORT USB0
718
//! \endcode
719
//! (USB0 is the default value)
720
//!
721
//! Optionally, the port can be changed during runtime with MIOS32_MIDI_DebugPortSet
550 tk 722
//!
723
//! Please note that the resulting string shouldn't be longer than 128 characters!<BR>
724
//! If the *format string is already longer than 100 characters an error message will
725
//! be sent to notify about the programming error.<BR>
726
//! The limit is set to save allocated stack memory! Just reduce the formated string to
727
//! print out the intended message.
307 tk 728
//! \param[in] *format zero-terminated format string - 128 characters supported maximum!
729
//! \param ... additional arguments
730
//! \return < 0 on errors
731
/////////////////////////////////////////////////////////////////////////////
732
s32 MIOS32_MIDI_SendDebugMessage(char *format, ...)
733
{
1275 tk 734
#ifdef MIOS32_MIDI_DISABLE_DEBUG_MESSAGE
735
  // for bootloader to save memory
736
  return -1;
737
#else
307 tk 738
  u8 buffer[128+5+3+1]; // 128 chars allowed + 5 for header + 3 for command + F7
739
  va_list args;
740
  int i;
741
 
550 tk 742
  // failsave: if format string is longer than 100 chars, break here
743
  // note that this is a weak protection: if %s is used, or a lot of other format tokens,
744
  // the resulting string could still lead to a buffer overflow
745
  // other the other hand we don't want to allocate too many byte for buffer[] to save stack
746
  char *str = (char *)((size_t)buffer+sizeof(mios32_midi_sysex_header)+3);
747
  if( strlen(format) > 100 ) {
1477 tk 748
    // exit with less costly message
749
    return MIOS32_MIDI_SendDebugString("(ERROR: string passed to MIOS32_MIDI_SendDebugMessage() is longer than 100 chars!\n");
550 tk 750
  } else {
751
    // transform formatted string into string
752
    va_start(args, format);
753
    vsprintf(str, format, args);
754
  }
307 tk 755
 
756
  u8 *sysex_buffer_ptr = buffer;
757
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
758
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
759
 
760
  // device ID
761
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
762
 
763
  // debug message: ack code
764
  *sysex_buffer_ptr++ = MIOS32_MIDI_SYSEX_DEBUG;
765
 
766
  // command identifier
582 tk 767
  *sysex_buffer_ptr++ = 0x40; // output string
307 tk 768
 
769
  // search end of string and determine length
770
  u16 len = sizeof(mios32_midi_sysex_header) + 3;
771
  for(i=0; i<128 && (*sysex_buffer_ptr != 0); ++i) {
772
    *sysex_buffer_ptr++ &= 0x7f; // ensure that MIDI protocol won't be violated
773
    ++len;
774
  }
775
 
776
  // send footer
777
  *sysex_buffer_ptr++ = 0xf7;
778
  ++len;
779
 
780
  return MIOS32_MIDI_SendSysEx(debug_port, buffer, len);
1275 tk 781
#endif
307 tk 782
}
783
 
784
 
785
/////////////////////////////////////////////////////////////////////////////
1477 tk 786
//! Sends a string to the MIOS Terminal in MIOS Studio.
787
//!
788
//! In distance to MIOS32_MIDI_SendDebugMessage this version is less costly (it
789
//! doesn't consume so much stack space), but the string must already be prepared.
790
//!
791
//! Example:
792
//! \code
793
//!   MIOS32_MIDI_SendDebugString("ERROR: something strange happened in myFunction()!");
794
//! \endcode
795
//!
796
//! The string size isn't limited.
797
//!
798
//! \return < 0 on errors
799
/////////////////////////////////////////////////////////////////////////////
800
s32 MIOS32_MIDI_SendDebugString(char *str)
801
{
802
#ifdef MIOS32_MIDI_DISABLE_DEBUG_MESSAGE
803
  // for bootloader to save memory
804
  return -1;
805
#else
806
  s32 status = 0;
807
  mios32_midi_package_t package;
808
 
809
// unfortunately doesn't work, and runtime check would be unnecessary costly
810
//#if sizeof(mios32_midi_sysex_header) != 5
811
//# error "Please adapt MIOS32_MIDI_SendDebugString"
812
//#endif
813
 
814
  package.type = 0x4; // SysEx starts or continues
815
  package.evnt0 = mios32_midi_sysex_header[0];
816
  package.evnt1 = mios32_midi_sysex_header[1];
817
  package.evnt2 = mios32_midi_sysex_header[2];
818
  status |= MIOS32_MIDI_SendPackage(debug_port, package);
819
 
820
  package.type = 0x4; // SysEx starts or continues
821
  package.evnt0 = mios32_midi_sysex_header[3];
822
  package.evnt1 = mios32_midi_sysex_header[4];
823
  package.evnt2 = MIOS32_MIDI_DeviceIDGet();
824
  status |= MIOS32_MIDI_SendPackage(debug_port, package);
825
 
826
  package.type = 0x4; // SysEx starts or continues
827
  package.evnt0 = MIOS32_MIDI_SYSEX_DEBUG;
828
  package.evnt1 = 0x40; // output string
829
  package.evnt2 = str[0]; // will be 0x00 if string already ends (""), thats ok, MIOS Studio can handle this
830
  status |= MIOS32_MIDI_SendPackage(debug_port, package);
831
 
832
  u32 len = strlen(str);
833
  if( len > 0 ) {
834
    int i = 1; // because str[0] has already been sent
835
    for(i=1; i<len; i+=3) {
836
      u8 b;
837
      u8 terminated = 0;
838
 
839
      package.type = 0x4; // SysEx starts or continues
840
      if( (b=str[i+0]) ) {
841
    package.evnt0 = b & 0x7f;
842
      } else {
843
    package.evnt0 = 0x00;
844
    terminated = 1;
845
      }
846
 
847
      if( !terminated && (b=str[i+1]) ) {
848
    package.evnt1 = b & 0x7f;
849
      } else {
850
    package.evnt1 = 0x00;
851
    terminated = 1;
852
      }
853
 
854
      if( !terminated && (b=str[i+2]) ) {
855
    package.evnt2 = b & 0x7f;
856
      } else {
857
    package.evnt2 = 0x00;
858
    terminated = 1;
859
      }
860
 
861
      status |= MIOS32_MIDI_SendPackage(debug_port, package);
862
    }
863
  }
864
 
865
  package.type = 0x5; // SysEx ends with following single byte. 
866
  package.evnt0 = 0xf7;
867
  package.evnt1 = 0x00;
868
  package.evnt2 = 0x00;
869
  status |= MIOS32_MIDI_SendPackage(debug_port, package);
870
 
871
  return status;
872
#endif
873
}
874
 
875
 
876
/////////////////////////////////////////////////////////////////////////////
369 tk 877
//! Sends an hex dump (formatted representation of memory content) to the 
878
//! MIOS Terminal in MIOS Studio.
879
//!
880
//! The MIDI port used for debugging (MIDI_DEBUG) can be declared in mios32_config.h:
881
//! \code
882
//!   #define MIOS32_MIDI_DEBUG_PORT USB0
883
//! \endcode
884
//! (USB0 is the default value)
885
//!
886
//! Optionally, the port can be changed during runtime with MIOS32_MIDI_DebugPortSet
887
//! \param[in] *src pointer to memory location which should be dumped
888
//! \param[in] len number of bytes which should be sent
889
//! \return < 0 on errors
890
/////////////////////////////////////////////////////////////////////////////
891
s32 MIOS32_MIDI_SendDebugHexDump(u8 *src, u32 len)
892
{
893
  // check if any byte has to be sent
894
  if( !len )
895
    return 0;
896
 
897
  // send hex dump line by line
370 tk 898
  u8 *src_begin = src;
369 tk 899
  u8 *src_end;
900
  for(src_end=(u8 *)((size_t)src + len - 1); src < src_end;) {
376 tk 901
    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 902
    int i;
903
 
904
    // create SysEx header
905
    u8 *sysex_buffer_ptr = buffer;
906
    for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
907
      *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
908
 
909
    // device ID
910
    *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
911
 
912
    // debug message: ack code
913
    *sysex_buffer_ptr++ = MIOS32_MIDI_SYSEX_DEBUG;
914
 
915
    // command identifier
582 tk 916
    *sysex_buffer_ptr++ = 0x40; // output string
369 tk 917
 
918
    // build line:
919
    // add source address
374 tk 920
    sprintf((char *)sysex_buffer_ptr, "%08X ", (u32)(src-src_begin));
921
    sysex_buffer_ptr += 9;
369 tk 922
 
923
    // add up to 16 bytes
924
    u8 *src_chars = src; // for later
925
    for(i=0; i<16; ++i) {
374 tk 926
      sprintf((char *)sysex_buffer_ptr, (src <= src_end) ? " %02X" : "   ", *src);
927
      sysex_buffer_ptr += 3;
369 tk 928
 
929
      ++src;
930
    }
931
 
932
    // add two spaces
374 tk 933
    for(i=0; i<2; ++i)
934
      *sysex_buffer_ptr++ = ' ';
369 tk 935
 
936
    // add characters
937
    for(i=0; i<16; ++i) {
938
      if( *src_chars < 32 || *src_chars >= 128 )
374 tk 939
    *sysex_buffer_ptr++ = '.';
369 tk 940
      else
374 tk 941
    *sysex_buffer_ptr++ = *src_chars;
369 tk 942
 
943
      if( src_chars == src_end )
944
    break;
945
 
946
      ++src_chars;
947
    }
948
 
376 tk 949
    // linebreak
950
    *sysex_buffer_ptr++ = '\n';
951
 
369 tk 952
    // add F7
374 tk 953
    *sysex_buffer_ptr++ = 0xf7;
369 tk 954
 
374 tk 955
    s32 status = MIOS32_MIDI_SendSysEx(debug_port, buffer, (u32)(sysex_buffer_ptr-buffer));
369 tk 956
    if( status < 0 )
957
      return status;
958
  }
959
 
960
  return 0; // no error
961
}
962
 
963
 
964
/////////////////////////////////////////////////////////////////////////////
674 tk 965
//! Checks for incoming MIDI messages amd calls callback_package function
966
//! with following parameters:
211 tk 967
//! \code
674 tk 968
//!    callback_package(mios32_midi_port_t port, mios32_midi_package_t midi_package)
211 tk 969
//! \endcode
528 tk 970
//!
971
//! Not for use in an application - this function is called by
674 tk 972
//! by a task in the programming model, callback_package is APP_MIDI_NotifyPackage()
973
//!
974
//! SysEx streams can be optionally redirected to a separate callback function 
975
//! which can be installed via MIOS32_MIDI_SysExCallback_Init()
976
//!
211 tk 977
//! \return < 0 on errors
33 tk 978
/////////////////////////////////////////////////////////////////////////////
674 tk 979
s32 MIOS32_MIDI_Receive_Handler(void *_callback_package)
33 tk 980
{
981
  u8 port;
982
  mios32_midi_package_t package;
983
 
674 tk 984
  void (*callback_package)(mios32_midi_port_t port, mios32_midi_package_t midi_package) = _callback_package;
33 tk 985
 
78 tk 986
  u8 intf = 0; // interface to be checked
987
  u8 total_packages_forwarded = 0; // number of forwards - stop after 10 forwards to yield some CPU time for other tasks
988
  u8 packages_forwarded = 0;
989
  u8 again = 1;
33 tk 990
  do {
78 tk 991
    // Round Robin
992
    // TODO: maybe a list based approach would be better
993
    // it would allow to add/remove interfaces dynamically
994
    // this would also allow to give certain ports a higher priority (to add them multiple times to the list)
995
    // it would also improve this spagetthi code ;)
529 tk 996
    s32 status = -1;
78 tk 997
    switch( intf++ ) {
998
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
529 tk 999
      case 0: status = MIOS32_USB_MIDI_PackageReceive(&package); port = USB0 + package.cable; break;
78 tk 1000
#else
529 tk 1001
      case 0: status = -1; break;
78 tk 1002
#endif
126 tk 1003
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART0_ASSIGNMENT == 1
529 tk 1004
      case 1: status = MIOS32_UART_MIDI_PackageReceive(0, &package); port = UART0; break;
78 tk 1005
#else
529 tk 1006
      case 1: status = -1; break;
78 tk 1007
#endif
126 tk 1008
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART1_ASSIGNMENT == 1
529 tk 1009
      case 2: status = MIOS32_UART_MIDI_PackageReceive(1, &package); port = UART1; break;
78 tk 1010
#else
529 tk 1011
      case 2: status = -1; break;
78 tk 1012
#endif
1071 tk 1013
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART2_ASSIGNMENT == 1
1014
      case 3: status = MIOS32_UART_MIDI_PackageReceive(2, &package); port = UART2; break;
78 tk 1015
#else
529 tk 1016
      case 3: status = -1; break;
78 tk 1017
#endif
1328 tk 1018
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART3_ASSIGNMENT == 1
1019
      case 4: status = MIOS32_UART_MIDI_PackageReceive(3, &package); port = UART3; break;
78 tk 1020
#else
529 tk 1021
      case 4: status = -1; break;
78 tk 1022
#endif
1023
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
1328 tk 1024
      case 5: status = MIOS32_IIC_MIDI_PackageReceive(0, &package); port = IIC0; break;
78 tk 1025
#else
529 tk 1026
      case 5: status = -1; break;
78 tk 1027
#endif
1028
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
1328 tk 1029
      case 6: status = MIOS32_IIC_MIDI_PackageReceive(1, &package); port = IIC1; break;
78 tk 1030
#else
529 tk 1031
      case 6: status = -1; break;
78 tk 1032
#endif
1033
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
1328 tk 1034
      case 7: status = MIOS32_IIC_MIDI_PackageReceive(2, &package); port = IIC2; break;
78 tk 1035
#else
529 tk 1036
      case 7: status = -1; break;
78 tk 1037
#endif
1038
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
1328 tk 1039
      case 8: status = MIOS32_IIC_MIDI_PackageReceive(3, &package); port = IIC3; break;
78 tk 1040
#else
529 tk 1041
      case 8: status = -1; break;
78 tk 1042
#endif
80 tk 1043
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
1328 tk 1044
      case 9: status = MIOS32_IIC_MIDI_PackageReceive(4, &package); port = IIC4; break;
80 tk 1045
#else
529 tk 1046
      case 9: status = -1; break;
80 tk 1047
#endif
1048
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
1328 tk 1049
      case 10: status = MIOS32_IIC_MIDI_PackageReceive(5, &package); port = IIC5; break;
80 tk 1050
#else
529 tk 1051
      case 10: status = -1; break;
80 tk 1052
#endif
1071 tk 1053
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
1328 tk 1054
      case 11: status = MIOS32_IIC_MIDI_PackageReceive(6, &package); port = IIC6; break;
1071 tk 1055
#else
1056
      case 11: status = -1; break;
1057
#endif
1328 tk 1058
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
1059
      case 12: status = MIOS32_IIC_MIDI_PackageReceive(7, &package); port = IIC7; break;
1060
#else
1061
      case 12: status = -1; break;
1062
#endif
78 tk 1063
      default:
1064
    // allow 10 forwards maximum to yield some CPU time for other tasks
1065
    if( packages_forwarded && total_packages_forwarded < 10 ) {
1066
      intf = 0; // restart with USB
1067
      packages_forwarded = 0; // for checking, if packages still have been forwarded in next round
1068
    } else {
1069
      again = 0; // no more interfaces to be processed
1070
    }
529 tk 1071
    status = -1; // empty round - no message
78 tk 1072
    }
33 tk 1073
 
550 tk 1074
    // timeout detected by interface?
529 tk 1075
    if( status == -10 ) {
1076
      MIOS32_MIDI_TimeOut(port);
1077
      again = 0;
1078
    } else if( status >= 0 ) { // message received?
78 tk 1079
      // notify that a package has been forwarded
1080
      ++packages_forwarded;
1081
      ++total_packages_forwarded;
33 tk 1082
 
78 tk 1083
      // remove cable number from package (MIOS32_MIDI passes it's own port number)
69 tk 1084
      package.cable = 0;
33 tk 1085
 
78 tk 1086
      // branch depending on package type
582 tk 1087
      if( package.type >= 0x8 && package.type < 0xf ) {
674 tk 1088
    if( callback_package != NULL )
1089
      callback_package(port, package);
33 tk 1090
      } else {
675 tk 1091
    u8 filter_sysex = 0;
1092
 
33 tk 1093
    switch( package.type ) {
550 tk 1094
      case 0x0: // reserved, ignore
1095
      case 0x1: // cable events, ignore
1096
        break;
33 tk 1097
 
550 tk 1098
      case 0x2: // Two-byte System Common messages like MTC, SongSelect, etc. 
1099
      case 0x3: // Three-byte System Common messages like SPP, etc. 
674 tk 1100
        if( callback_package != NULL )
1101
          callback_package(port, package); // -> forwarded as event
550 tk 1102
        break;
1103
 
1104
      case 0x4: // SysEx starts or continues (3 bytes)
582 tk 1105
      case 0xf: // Single byte is interpreted as SysEx as well (I noticed that portmidi sometimes sends single bytes!)
674 tk 1106
 
1107
        if( package.evnt0 >= 0xf8 ) { // relevant for package type 0xf
1108
          if( callback_package != NULL )
1109
        callback_package(port, package); // -> realtime event is forwarded as event
1110
          break;
1111
        }
1112
 
550 tk 1113
        if( package.evnt0 == 0xf0 ) {
1114
          // cheap timeout mechanism - see comments above the sysex_timeout_ctr declaration
1115
          if( !sysex_timeout_ctr_flags.ALL ) {
1116
        switch( port & 0xf0 ) {
1117
          case USB0://..15
1118
            sysex_timeout_ctr = 0;
1119
            sysex_timeout_ctr_flags.usb_receives = (1 << (port & 0xf));
1120
            break;
1121
          case UART0://..15
1122
            // already done in MIOS32_UART_MIDI_PackageReceive()
1123
            break;
1124
          case IIC0://..15
1125
            sysex_timeout_ctr = 0;
1126
            sysex_timeout_ctr_flags.iic_receives = (1 << (port & 0xf));
1127
            break;
1128
            // no timeout protection for remaining interfaces (yet)
1129
        }
1130
          }
1131
        }
1132
 
1133
        MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
582 tk 1134
        if( package.type != 0x0f ) {
1135
          MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
1136
          MIOS32_MIDI_SYSEX_Parser(port, package.evnt2); // -> forward to MIOS32 SysEx Parser
1137
        }
1138
 
674 tk 1139
        if( sysex_callback_func != NULL ) {
675 tk 1140
          filter_sysex |= sysex_callback_func(port, package.evnt0); // -> forwarded as SysEx
582 tk 1141
          if( package.type != 0x0f ) {
675 tk 1142
        filter_sysex |= sysex_callback_func(port, package.evnt1); // -> forwarded as SysEx
1143
        filter_sysex |= sysex_callback_func(port, package.evnt2); // -> forwarded as SysEx
582 tk 1144
          }
675 tk 1145
        }
1146
 
1147
        if( callback_package != NULL && !filter_sysex )
674 tk 1148
          callback_package(port, package);
1149
 
550 tk 1150
        break;
1151
 
1152
      case 0x5:   // Single-byte System Common Message or SysEx ends with following single byte. 
1153
        if( package.evnt0 >= 0xf8 ) {
674 tk 1154
          if( callback_package != NULL )
1155
        callback_package(port, package); // -> forwarded as event
550 tk 1156
          break;
1157
        }
1158
        // no >= 0xf8 event: continue!
1159
 
1160
      case 0x6:   // SysEx ends with following two bytes.
1161
      case 0x7: { // SysEx ends with following three bytes.
1162
        u8 num_bytes = package.type - 0x5 + 1;
1163
        u8 current_byte = 0;
1164
 
1165
        if( num_bytes >= 1 ) {
1166
          current_byte = package.evnt0;
1167
          MIOS32_MIDI_SYSEX_Parser(port, current_byte); // -> forward to MIOS32 SysEx Parser
674 tk 1168
          if( sysex_callback_func != NULL )
675 tk 1169
        filter_sysex |= sysex_callback_func(port, current_byte); // -> forwarded as SysEx
550 tk 1170
        }
1171
 
1172
        if( num_bytes >= 2 ) {
1173
          current_byte = package.evnt1;
1174
          MIOS32_MIDI_SYSEX_Parser(port, current_byte); // -> forward to MIOS32 SysEx Parser
674 tk 1175
          if( sysex_callback_func != NULL )
675 tk 1176
        filter_sysex |= sysex_callback_func(port, current_byte); // -> forwarded as SysEx
550 tk 1177
        }
1178
 
1179
        if( num_bytes >= 3 ) {
1180
          current_byte = package.evnt2;
1181
          MIOS32_MIDI_SYSEX_Parser(port, current_byte); // -> forward to MIOS32 SysEx Parser
674 tk 1182
          if( sysex_callback_func != NULL )
675 tk 1183
        filter_sysex |= sysex_callback_func(port, current_byte); // -> forwarded as SysEx
550 tk 1184
        }
1185
 
1186
        // reset timeout protection if required
1187
        if( current_byte == 0xf7 )
1188
          sysex_timeout_ctr_flags.ALL = 0;
674 tk 1189
 
675 tk 1190
        // forward as package if not filtered
1191
        if( callback_package != NULL && !filter_sysex )
674 tk 1192
          callback_package(port, package);
550 tk 1193
 
1194
      } break;
1195
    }    
33 tk 1196
      }
1197
    }
550 tk 1198
 
1199
    // timeout detected by this handler?
1200
    if( sysex_timeout_ctr_flags.ALL && sysex_timeout_ctr > 1000 ) {
1201
      u8 timeout_port = 0;
1202
 
1203
      // determine port
1204
      if( sysex_timeout_ctr_flags.usb_receives ) {
1205
    int i; // i'm missing a prio instruction in C!
1206
    for(i=0; i<16; ++i)
1207
      if( sysex_timeout_ctr_flags.usb_receives & (1 << i) )
1208
        break;
1209
    if( i >= 16 ) // failsafe
1210
      i = 0;
1211
    timeout_port = USB0 + i;
1212
      } else if( sysex_timeout_ctr_flags.iic_receives ) {
1213
    int i; // i'm missing a prio instruction in C!
1214
    for(i=0; i<16; ++i)
1215
      if( sysex_timeout_ctr_flags.iic_receives & (1 << i) )
1216
        break;
1217
    if( i >= 16 ) // failsafe
1218
      i = 0;
1219
    timeout_port = IIC0 + i;
1220
      }
1221
 
1222
      MIOS32_MIDI_TimeOut(timeout_port);
1223
      sysex_timeout_ctr_flags.ALL = 0;
1224
      again = 0;
1225
    }
33 tk 1226
  } while( again );
1227
 
1228
  return 0;
1229
}
1230
 
1231
 
155 tk 1232
/////////////////////////////////////////////////////////////////////////////
528 tk 1233
//! This function should be called periodically each mS to handle timeout
1234
//! and expire counters.
1235
//!
1236
//! Not for use in an application - this function is called by
1237
//! by a task in the programming model!
1238
//! 
1239
//! \return < 0 on errors
1240
/////////////////////////////////////////////////////////////////////////////
1241
s32 MIOS32_MIDI_Periodic_mS(void)
1242
{
1243
  s32 status = 0;
1244
 
1245
#ifndef MIOS32_DONT_USE_USB_MIDI
1246
  status |= MIOS32_USB_MIDI_Periodic_mS();
1247
#endif
1248
 
1249
#ifndef MIOS32_DONT_USE_UART_MIDI
1250
  status |= MIOS32_UART_MIDI_Periodic_mS();
1251
#endif
1252
 
1253
#ifndef MIOS32_DONT_USE_IIC_MIDI
1254
  status |= MIOS32_IIC_MIDI_Periodic_mS();
1255
#endif
1256
 
550 tk 1257
  // increment timeout counter for incoming packages
1258
  // an incomplete event will be timed out after 1000 ticks (1 second)
1259
  if( sysex_timeout_ctr < 65535 )
1260
    ++sysex_timeout_ctr;
1261
 
528 tk 1262
  return status;
1263
}
1264
 
1265
 
1266
/////////////////////////////////////////////////////////////////////////////
281 tk 1267
//! Installs the Tx callback function which is executed by
1268
//! MIOS32_MIDI_SendPackage_NonBlocking() before the MIDI package will be
1269
//! forwarded to the physical interface.
1270
//!
1271
//! The callback allows following usecases:
1272
//! <UL>
282 tk 1273
//!   <LI>package filter
281 tk 1274
//!   <LI>duplicating/routing packages
1275
//!   <LI>monitoring packages (sniffer)
1276
//!   <LI>create virtual busses; loopbacks
282 tk 1277
//!   <LI>extend available ports (e.g. by an OSC or AOUT port)<BR>
1278
//!       It is recommented to give port extensions a port number >= 0x80 to
1279
//!       avoid incompatibility with future MIOS32 port extensions.
281 tk 1280
//! </UL>
1281
//! \param[in] *callback_tx pointer to callback function:<BR>
211 tk 1282
//! \code
674 tk 1283
//!    s32 callback_tx(mios32_midi_port_t port, mios32_midi_package_t package)
1284
//!    {
1285
//!    }
211 tk 1286
//! \endcode
281 tk 1287
//! The package will be forwarded to the physical interface if the function 
1288
//! returns 0.<BR>
1289
//! Should return 1 to filter a package.
1290
//! Should return -2 to initiate a retry (function will be called again)
1291
//! Should return -3 to report any other error.
1292
//! These error codes comply with MIOS32_MIDI_SendPackage_NonBlocking()
211 tk 1293
//! \return < 0 on errors
281 tk 1294
//! \note Please use the filtering capabilities with special care - if a port
1295
//! is filtered which is also used for code upload, you won't be able to exchange
1296
//! the erroneous code w/o starting the bootloader in hold mode after power-on.
155 tk 1297
/////////////////////////////////////////////////////////////////////////////
1327 tk 1298
s32 MIOS32_MIDI_DirectTxCallback_Init(s32 (*callback_tx)(mios32_midi_port_t port, mios32_midi_package_t package))
155 tk 1299
{
1300
  direct_tx_callback_func = callback_tx;
157 tk 1301
 
1302
  return 0; // no error
155 tk 1303
}
1304
 
1305
 
1306
/////////////////////////////////////////////////////////////////////////////
281 tk 1307
//! Installs the Rx callback function which is executed immediately on each
1308
//! incoming/outgoing MIDI byte, partly from interrupt handlers.
1309
//!
1310
//! This function should be executed so fast as possible. It can be used
1311
//! to trigger MIDI Rx LEDs or to trigger on MIDI clock events. In order to
1312
//! avoid MIDI buffer overruns, the max. recommented execution time is 100 uS!
1313
//!
1314
//! It is possible to filter incoming MIDI bytes with the return value of the
1315
//! callback function.<BR>
1316
//! \param[in] *callback_rx pointer to callback function:<BR>
1317
//! \code
674 tk 1318
//!    s32 callback_rx(mios32_midi_port_t port, u8 midi_byte)
1319
//!    {
1320
//!    }
281 tk 1321
//! \endcode
1322
//! The byte will be forwarded into the MIDI Rx queue if the function returns 0.<BR>
1323
//! It will be filtered out if the callback returns != 0 (e.g. 1 for "filter", 
1324
//! or -1 for "error").
1325
//! \return < 0 on errors
1326
//! \note Please use the filtering capabilities with special care - if a port
1327
//! is filtered which is also used for code upload, you won't be able to exchange
1328
//! the erroneous code w/o starting the bootloader in hold mode after power-on.
155 tk 1329
/////////////////////////////////////////////////////////////////////////////
1327 tk 1330
s32 MIOS32_MIDI_DirectRxCallback_Init(s32 (*callback_rx)(mios32_midi_port_t port, u8 midi_byte))
155 tk 1331
{
281 tk 1332
  direct_rx_callback_func = callback_rx;
155 tk 1333
 
157 tk 1334
  return 0; // no error
155 tk 1335
}
1336
 
281 tk 1337
 
155 tk 1338
/////////////////////////////////////////////////////////////////////////////
211 tk 1339
//! This function is used by MIOS32 internal functions to forward received
281 tk 1340
//! MIDI bytes to the Rx Callback routine.
1341
//!
1342
//! It shouldn't be used by applications.
1328 tk 1343
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
281 tk 1344
//! \param[in] midi_byte received MIDI byte
211 tk 1345
//! \return < 0 on errors
155 tk 1346
/////////////////////////////////////////////////////////////////////////////
281 tk 1347
s32 MIOS32_MIDI_SendByteToRxCallback(mios32_midi_port_t port, u8 midi_byte)
155 tk 1348
{
1349
  // note: here we could filter the user hook execution on special situations
281 tk 1350
  if( direct_rx_callback_func != NULL )
1351
    return direct_rx_callback_func(port, midi_byte);
157 tk 1352
  return 0; // no error
155 tk 1353
}
1354
 
1355
/////////////////////////////////////////////////////////////////////////////
211 tk 1356
//! This function is used by MIOS32 internal functions to forward received
281 tk 1357
//! MIDI packages to the Rx Callback routine (byte by byte)
1358
//!
1359
//! It shouldn't be used by applications.
1328 tk 1360
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART3, IIC0..IIC7)
281 tk 1361
//! \param[in] midi_package received MIDI package
211 tk 1362
//! \return < 0 on errors
155 tk 1363
/////////////////////////////////////////////////////////////////////////////
281 tk 1364
s32 MIOS32_MIDI_SendPackageToRxCallback(mios32_midi_port_t port, mios32_midi_package_t midi_package)
155 tk 1365
{
1366
  // note: here we could filter the user hook execution on special situations
281 tk 1367
  if( direct_rx_callback_func != NULL ) {
155 tk 1368
    u8 buffer[3] = {midi_package.evnt0, midi_package.evnt1, midi_package.evnt2};
1369
    int len = mios32_midi_pcktype_num_bytes[midi_package.cin];
1370
    int i;
283 tk 1371
    s32 status = 0;
155 tk 1372
    for(i=0; i<len; ++i)
281 tk 1373
      status |= direct_rx_callback_func(port, buffer[i]);
1374
    return status;
155 tk 1375
  }
157 tk 1376
  return 0; // no error
155 tk 1377
}
1378
 
225 tk 1379
/////////////////////////////////////////////////////////////////////////////
1380
//! This function allows to change the DEFAULT port.<BR>
1381
//! The preset which will be used after application reset can be set in
1382
//! mios32_config.h via "#define MIOS32_MIDI_DEFAULT_PORT <port>".<BR>
1127 tk 1383
//! It's set to USB0 as long as not overruled in mios32_config.h
1328 tk 1384
//! \param[in] port MIDI port (USB0..USB7, UART0..UART3, IIC0..IIC7)
225 tk 1385
//! \return < 0 on errors
1386
/////////////////////////////////////////////////////////////////////////////
1387
s32 MIOS32_MIDI_DefaultPortSet(mios32_midi_port_t port)
1388
{
1389
  if( port == DEFAULT ) // avoid recursion
1390
    return -1;
1391
 
1392
  default_port = port;
1393
 
1394
  return 0; // no error
1395
}
1396
 
1397
/////////////////////////////////////////////////////////////////////////////
1398
//! This function returns the DEFAULT port
1399
//! \return the default port
1400
/////////////////////////////////////////////////////////////////////////////
1401
mios32_midi_port_t MIOS32_MIDI_DefaultPortGet(void)
1402
{
1403
  return default_port;
1404
}
1405
 
1406
 
1407
/////////////////////////////////////////////////////////////////////////////
307 tk 1408
//! This function allows to change the MIDI_DEBUG port.<BR>
1409
//! The preset which will be used after application reset can be set in
1410
//! mios32_config.h via "#define MIOS32_MIDI_DEBUG_PORT <port>".<BR>
1127 tk 1411
//! It's set to USB0 as long as not overruled in mios32_config.h
1328 tk 1412
//! \param[in] port MIDI port (USB0..USB7, UART0..UART3, IIC0..IIC7)
307 tk 1413
//! \return < 0 on errors
1414
/////////////////////////////////////////////////////////////////////////////
1415
s32 MIOS32_MIDI_DebugPortSet(mios32_midi_port_t port)
1416
{
1417
  if( port == MIDI_DEBUG ) // avoid recursion
1418
    return -1;
1419
 
1420
  debug_port = port;
1275 tk 1421
 
307 tk 1422
  return 0; // no error
1423
}
1424
 
1425
/////////////////////////////////////////////////////////////////////////////
1426
//! This function returns the MIDI_DEBUG port
1427
//! \return the debug port
1428
/////////////////////////////////////////////////////////////////////////////
1429
mios32_midi_port_t MIOS32_MIDI_DebugPortGet(void)
1430
{
1431
  return debug_port;
1432
}
1433
 
1434
 
1435
/////////////////////////////////////////////////////////////////////////////
225 tk 1436
//! This function sets the SysEx Device ID, which is used during parsing
1437
//! incoming SysEx Requests to MIOS32<BR>
1438
//! It can also be used by an application for additional parsing with the same ID.<BR>
1439
//! ID changes will get lost after reset. It can be changed permanently by the
1300 tk 1440
//! user via the bootloader update tool
225 tk 1441
//! \param[in] device_id a new (temporary) device ID (0x00..0x7f)
1442
//! \return < 0 on errors
1443
/////////////////////////////////////////////////////////////////////////////
1444
s32 MIOS32_MIDI_DeviceIDSet(u8 device_id)
1445
{
1446
  sysex_device_id = device_id & 0x7f;
1447
  return 0; // no error
1448
}
1449
 
1450
/////////////////////////////////////////////////////////////////////////////
1451
//! This function returns the SysEx Device ID, which is used during parsing
1452
//! incoming SysEx Requests to MIOS32<BR>
1453
//! It can also be used by an application for additional parsing with the same ID.<BR>
1454
//! The initial ID is stored inside the BSL range and will be recovered after
1300 tk 1455
//! reset. It can be changed by the user with the bootloader update tool
225 tk 1456
//! \return SysEx device ID (0x00..0x7f)
1457
/////////////////////////////////////////////////////////////////////////////
1458
u8 MIOS32_MIDI_DeviceIDGet(void)
1459
{
1460
  return sysex_device_id;
1461
}
1462
 
1463
 
1464
/////////////////////////////////////////////////////////////////////////////
674 tk 1465
//! Installs an optional SysEx callback which is called by 
676 tk 1466
//! MIOS32_MIDI_Receive_Handler() to simplify the parsing of SysEx streams.
674 tk 1467
//!
1468
//! Without this callback (or with MIOS32_MIDI_SysExCallback_Init(NULL)),
676 tk 1469
//! SysEx messages are only forwarded to APP_MIDI_NotifyPackage() in chunks of 
674 tk 1470
//! 1, 2 or 3 bytes, tagged with midi_package.type == 0x4..0x7 or 0xf
1471
//! 
1472
//! In this case, the application has to take care for different transmission
1473
//! approaches which are under control of the package sender. E.g., while Windows
1474
//! uses Package Type 4..7 to transmit a SysEx stream, PortMIDI under MacOS sends 
1475
//! a mix of 0xf (single byte) and 0x4 (continued 3-byte) packages instead.
1476
//! 
677 tk 1477
//! By using the SysEx callback, the type of package doesn't play a role anymore,
674 tk 1478
//! instead the application can parse a serial stream.
1479
//!
1480
//! MIOS32 ensures, that realtime events (0xf8..0xff) are still forwarded to
1481
//! APP_MIDI_NotifyPackage(), regardless if they are transmitted in a package
1482
//! type 0x5 or 0xf, so that the SysEx parser doesn't need to filter out such
1483
//! events, which could otherwise appear inside a SysEx stream.
1484
//! 
1485
//! \param[in] *callback_sysex pointer to callback function:<BR>
1486
//! \code
1487
//!    s32 callback_sysex(mios32_midi_port_t port, u8 sysex_byte)
1488
//!    {
675 tk 1489
//!       //
674 tk 1490
//!       // .. parse stream
675 tk 1491
//!       //
1492
//!     
1493
//!       return 1; // don't forward package to APP_MIDI_NotifyPackage()
674 tk 1494
//!    }
1495
//! \endcode
675 tk 1496
//! If the function returns 0, SysEx bytes will be forwarded to APP_MIDI_NotifyPackage() as well.
1497
//! With return value != 0, APP_MIDI_NotifyPackage() won't get the already processed package.
674 tk 1498
//! \return < 0 on errors
1499
/////////////////////////////////////////////////////////////////////////////
1327 tk 1500
s32 MIOS32_MIDI_SysExCallback_Init(s32 (*callback_sysex)(mios32_midi_port_t port, u8 midi_in))
674 tk 1501
{
1502
  sysex_callback_func = callback_sysex;
1503
 
1504
  return 0; // no error
1505
}
1506
 
1507
/////////////////////////////////////////////////////////////////////////////
225 tk 1508
// This function parses an incoming sysex stream for MIOS32 commands
1509
/////////////////////////////////////////////////////////////////////////////
1510
static s32 MIOS32_MIDI_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in)
1511
{
1512
  // ignore realtime messages (see MIDI spec - realtime messages can
1513
  // always be injected into events/streams, and don't change the running status)
1514
  if( midi_in >= 0xf8 )
1515
    return 0;
1516
 
1517
  // TODO: here we could send an error notification, that multiple devices are trying to access the device
1518
  if( sysex_state.MY_SYSEX && port != last_sysex_port )
1519
    return -1;
1520
 
1135 tk 1521
  // USB upload is only allowed via USB0
1522
  // this covers the scenario where other USB1..7 ports are used for MIDI Port forwarding, and a MIOS8 core
1523
  // is connected to one of these ports
1524
  // MIOS Studio reports "Detected MIOS8 and MIOS32 response - selection not supported yet!" in this case
1525
  // By ignoring >= USB1 <= USB7 we have at least a workaround which works (for example) for MIDIbox LC
1526
  if( port >= USB1 && port <= USB7 )
1527
    return -1;
1528
 
225 tk 1529
  last_sysex_port = port;
1530
 
1531
  // branch depending on state
1532
  if( !sysex_state.MY_SYSEX ) {
1533
    if( (sysex_state.CTR < sizeof(mios32_midi_sysex_header) && midi_in != mios32_midi_sysex_header[sysex_state.CTR]) ||
1534
    (sysex_state.CTR == sizeof(mios32_midi_sysex_header) && midi_in != sysex_device_id) ) {
1535
      // incoming byte doesn't match
1536
      MIOS32_MIDI_SYSEX_CmdFinished();
1537
    } else {
1538
      if( ++sysex_state.CTR > sizeof(mios32_midi_sysex_header) ) {
1539
    // complete header received, waiting for data
1540
    sysex_state.MY_SYSEX = 1;
1541
      }
1542
    }
1543
  } else {
1544
    // check for end of SysEx message or invalid status byte
1545
    if( midi_in >= 0x80 ) {
1546
      if( midi_in == 0xf7 && sysex_state.CMD ) {
1547
        MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_END, midi_in);
1548
      }
1549
      MIOS32_MIDI_SYSEX_CmdFinished();
1550
    } else {
1551
      // check if command byte has been received
1552
      if( !sysex_state.CMD ) {
1553
    sysex_state.CMD = 1;
1554
    sysex_cmd = midi_in;
1555
    MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN, midi_in);
1556
      }
1557
      else
1558
    MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_CONT, midi_in);
1559
    }
1560
  }
1561
 
1562
  return 0; // no error
1563
}
1564
 
1565
 
1566
/////////////////////////////////////////////////////////////////////////////
1567
// This function is called at the end of a sysex command or on 
1568
// an invalid message
1569
/////////////////////////////////////////////////////////////////////////////
1570
static s32 MIOS32_MIDI_SYSEX_CmdFinished(void)
1571
{
1572
  // clear all status variables
1573
  sysex_state.ALL = 0;
1574
  sysex_cmd = 0;
1575
 
1576
  return 0; // no error
1577
}
1578
 
1579
/////////////////////////////////////////////////////////////////////////////
1580
// This function handles the sysex commands
1581
/////////////////////////////////////////////////////////////////////////////
1582
static s32 MIOS32_MIDI_SYSEX_Cmd(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
1583
{
238 tk 1584
#if MIOS32_MIDI_BSL_ENHANCEMENTS
1585
  // this compile switch should only be activated for the bootloader!
1586
  if( BSL_SYSEX_Cmd(port, cmd_state, midi_in, sysex_cmd) >= 0 )
1587
    return 0; // BSL has serviced this command - no error
1588
#endif
225 tk 1589
  switch( sysex_cmd ) {
1590
    case 0x00:
230 tk 1591
      MIOS32_MIDI_SYSEX_Cmd_Query(port, cmd_state, midi_in);
225 tk 1592
      break;
582 tk 1593
    case 0x0d:
1594
      MIOS32_MIDI_SYSEX_Cmd_Debug(port, cmd_state, midi_in);
1595
      break;
626 tk 1596
    case 0x0e: // ignore to avoid loopbacks
1597
      break;
225 tk 1598
    case 0x0f:
1599
      MIOS32_MIDI_SYSEX_Cmd_Ping(port, cmd_state, midi_in);
1600
      break;
1601
    default:
1602
      // unknown command
1603
      // TODO: send 0xf7 if merger enabled
1604
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_INVALID_COMMAND);
1605
      MIOS32_MIDI_SYSEX_CmdFinished();      
1606
  }
1607
 
1608
  return 0; // no error
1609
}
1610
 
1611
 
1612
 
1613
/////////////////////////////////////////////////////////////////////////////
230 tk 1614
// Command 00: Query core informations and request BSL entry
225 tk 1615
/////////////////////////////////////////////////////////////////////////////
230 tk 1616
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 1617
{
230 tk 1618
  static u8 query_req = 0;
1619
  char str_buffer[40];
225 tk 1620
 
1621
  switch( cmd_state ) {
1622
 
1623
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
230 tk 1624
      query_req = 0;
225 tk 1625
      break;
1626
 
1627
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
230 tk 1628
      query_req = midi_in;
1629
      break;
1630
 
1631
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
1632
      switch( query_req ) {
1633
        case 0x01: // operating system
1634
      MIOS32_MIDI_SYSEX_SendAckStr(port, "MIOS32");
225 tk 1635
      break;
237 tk 1636
        case 0x02: // Board
230 tk 1637
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_BOARD_STR);
225 tk 1638
      break;
230 tk 1639
        case 0x03: // Core Family
1640
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_FAMILY_STR);
225 tk 1641
      break;
230 tk 1642
        case 0x04: // Chip ID
1643
      sprintf(str_buffer, "%08x", MIOS32_SYS_ChipIDGet());
1644
      MIOS32_MIDI_SYSEX_SendAckStr(port, (char *)str_buffer);
1645
      break;
1646
        case 0x05: // Serial Number
1647
      if( MIOS32_SYS_SerialNumberGet((char *)str_buffer) >= 0 )
1648
        MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1649
      else
1650
        MIOS32_MIDI_SYSEX_SendAckStr(port, "?");
1651
      break;
1652
        case 0x06: // Flash Memory Size
1653
      sprintf(str_buffer, "%d", MIOS32_SYS_FlashSizeGet());
1654
      MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1655
      break;
1656
        case 0x07: // RAM Memory Size
1657
      sprintf(str_buffer, "%d", MIOS32_SYS_RAMSizeGet());
1658
      MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1659
      break;
1660
        case 0x08: // Application Name Line #1
1661
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_LCD_BOOT_MSG_LINE1);
1662
      break;
1663
        case 0x09: // Application Name Line #2
1664
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_LCD_BOOT_MSG_LINE2);
1665
      break;
1666
        case 0x7f:
231 tk 1667
#if MIOS32_MIDI_BSL_ENHANCEMENTS
1668
      // release halt state (or sending upload request) instead of reseting the core
1669
      BSL_SYSEX_ReleaseHaltState();
1670
#else
230 tk 1671
      // reset core (this will send an upload request)
1672
      MIOS32_SYS_Reset();
1673
      // at least on STM32 we will never reach this point
1674
      // but other core families could contain an empty stumb!
231 tk 1675
#endif
230 tk 1676
      break;
1677
        default:
1678
      // unknown query
1679
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_UNKNOWN_QUERY);
225 tk 1680
      }
1681
  }
1682
 
1683
  return 0; // no error
1684
}
1685
 
582 tk 1686
 
225 tk 1687
/////////////////////////////////////////////////////////////////////////////
582 tk 1688
// Command 0D: Debug Input/Output
1689
/////////////////////////////////////////////////////////////////////////////
1690
static s32 MIOS32_MIDI_SYSEX_Cmd_Debug(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
1691
{
1692
  static u8 debug_req = 0xff;
1693
 
1694
  switch( cmd_state ) {
1695
 
1696
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
1697
      debug_req = 0xff;
1698
      break;
1699
 
1700
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
1701
      if( debug_req == 0xff ) {
1702
    debug_req = midi_in;
1703
      } else {
1704
    switch( debug_req ) {
1705
      case 0x00: // input string
1706
        if( debug_command_callback_func != NULL )
1707
          debug_command_callback_func(last_sysex_port, (char)midi_in);
1708
        break;
1709
 
1710
      case 0x40: // output string
1711
        // not supported - DisAck will be sent
1712
        break;
1713
 
1714
      default: // others
1715
        // not supported - DisAck will be sent
1716
        break;
1717
    }
1718
      }
1719
      break;
1720
 
1721
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
1722
      if( debug_req == 0x00 ) {
1723
    // send acknowledge
1724
    MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_ACK, 0x00);
944 tk 1725
 
959 tk 1726
    if( debug_req == 0 && debug_command_callback_func == NULL ) {
1727
      mios32_midi_port_t prev_debug_port = MIOS32_MIDI_DebugPortGet();
1728
      MIOS32_MIDI_DebugPortSet(port);
1477 tk 1729
      MIOS32_MIDI_SendDebugString("[MIOS32_MIDI_SYSEX_Cmd_Debug] command handler not implemented by application\n");
959 tk 1730
      MIOS32_MIDI_DebugPortSet(prev_debug_port);
1731
    }
944 tk 1732
 
582 tk 1733
      } else {
1734
    // send disacknowledge
1735
    MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_UNSUPPORTED_DEBUG);
1736
      }
1737
  }
1738
 
1739
  return 0; // no error
1740
}
1741
 
1742
/////////////////////////////////////////////////////////////////////////////
623 tk 1743
// Command 0F: Ping (just send back acknowledge if no additional byte has been received)
225 tk 1744
/////////////////////////////////////////////////////////////////////////////
1745
static s32 MIOS32_MIDI_SYSEX_Cmd_Ping(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
1746
{
1747
  switch( cmd_state ) {
1748
 
1749
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
623 tk 1750
      sysex_state.PING_BYTE_RECEIVED = 0;
225 tk 1751
      break;
1752
 
1753
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
623 tk 1754
      sysex_state.PING_BYTE_RECEIVED = 1;
225 tk 1755
      break;
1756
 
1757
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
1758
      // TODO: send 0xf7 if merger enabled
1759
 
623 tk 1760
      // send acknowledge if no additional byte has been received
1761
      // to avoid feedback loop if two cores are directly connected
1762
      if( !sysex_state.PING_BYTE_RECEIVED )
1763
    MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_ACK, 0x00);
225 tk 1764
 
1765
      break;
1766
  }
1767
 
1768
  return 0; // no error
1769
}
1770
 
1771
/////////////////////////////////////////////////////////////////////////////
1772
// This function sends a SysEx acknowledge to notify the user about the received command
1773
// expects acknowledge code (e.g. 0x0f for good, 0x0e for error) and additional argument
1774
/////////////////////////////////////////////////////////////////////////////
1775
static s32 MIOS32_MIDI_SYSEX_SendAck(mios32_midi_port_t port, u8 ack_code, u8 ack_arg)
1776
{
1777
  u8 sysex_buffer[32]; // should be enough?
1778
  u8 *sysex_buffer_ptr = &sysex_buffer[0];
1779
  int i;
1780
 
1781
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
1782
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
1783
 
1784
  // device ID
1785
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
1786
 
1787
  // send ack code and argument
1788
  *sysex_buffer_ptr++ = ack_code;
1789
  *sysex_buffer_ptr++ = ack_arg;
1790
 
1791
  // send footer
1792
  *sysex_buffer_ptr++ = 0xf7;
1793
 
1794
  // finally send SysEx stream
1795
  return MIOS32_MIDI_SendSysEx(port, (u8 *)sysex_buffer, (u32)sysex_buffer_ptr - ((u32)&sysex_buffer[0]));
1796
}
1797
 
230 tk 1798
/////////////////////////////////////////////////////////////////////////////
1799
// This function sends an SysEx acknowledge with a string (used on queries)
1800
/////////////////////////////////////////////////////////////////////////////
1801
static s32 MIOS32_MIDI_SYSEX_SendAckStr(mios32_midi_port_t port, char *str)
1802
{
1803
  u8 sysex_buffer[128]; // should be enough?
1804
  u8 *sysex_buffer_ptr = &sysex_buffer[0];
1805
  int i;
225 tk 1806
 
230 tk 1807
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
1808
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
155 tk 1809
 
230 tk 1810
  // device ID
1811
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
1812
 
1813
  // send ack code
1814
  *sysex_buffer_ptr++ = MIOS32_MIDI_SYSEX_ACK;
1815
 
1816
  // send string
307 tk 1817
  for(i=0; i<100 && (str[i] != 0); ++i)
230 tk 1818
    *sysex_buffer_ptr++ = str[i];
1819
 
1820
  // send footer
1821
  *sysex_buffer_ptr++ = 0xf7;
1822
 
1823
  // finally send SysEx stream
1824
  return MIOS32_MIDI_SendSysEx(port, (u8 *)sysex_buffer, (u32)sysex_buffer_ptr - ((u32)&sysex_buffer[0]));
1825
}
1826
 
529 tk 1827
 
1828
/////////////////////////////////////////////////////////////////////////////
582 tk 1829
//! Installs the debug command callback function which is executed on incoming
1830
//! characters from a MIOS Terminal
1831
//!
1832
//! Example:
1833
//! \code
1834
//! s32 CONSOLE_Parse(mios32_midi_port_t port, char c)
1835
//! {
1836
//!   // see $MIOS32_PATH/apps/examples/midi_console/
1837
//!   
1838
//!   return 0; // no error
1839
//! }
1840
//! \endcode
1841
//!
1842
//! The callback function has been installed in an Init() function with:
1843
//! \code
1844
//!   MIOS32_MIDI_DebugCommandCallback_Init(CONSOLE_Parse);
1845
//! \endcode
1846
//! \param[in] callback_debug_command the callback function (NULL disables the callback)
1847
//! \return < 0 on errors
1848
/////////////////////////////////////////////////////////////////////////////
1327 tk 1849
s32 MIOS32_MIDI_DebugCommandCallback_Init(s32 (*callback_debug_command)(mios32_midi_port_t port, char c))
582 tk 1850
{
1851
  debug_command_callback_func = callback_debug_command;
1852
 
1853
  return 0; // no error
1854
}
1855
 
1856
 
1857
/////////////////////////////////////////////////////////////////////////////
529 tk 1858
//! Installs the Timeout callback function which is executed on incomplete
1859
//! MIDI packages received via UART, or on incomplete SysEx streams.
1860
//!
1861
//! A timeout is detected after 1 second.
1862
//!
1863
//! On a timeout, it is recommented to reset MIDI parsing relevant variables,
1864
//! e.g. the state of a SysEx parser.
1865
//!
1866
//! Example:
1867
//! \code
1868
//! s32 NOTIFY_MIDI_TimeOut(mios32_midi_port_t port)
1869
//! {
1870
//!   // if my SysEx parser receives a command (MY_SYSEX flag set), abort parser if port matches
1871
//!   if( sysex_state.MY_SYSEX && port == last_sysex_port )
1872
//!     MySYSEX_CmdFinished();
1873
//!
1874
//!   return 0; // no error
1875
//! }
1876
//! \endcode
1877
//!
1878
//! The callback function has been installed in an Init() function with:
1879
//! \code
674 tk 1880
//!   MIOS32_MIDI_TimeOutCallback_Init(NOTIFY_MIDI_TimeOut)
1881
//!   {
1882
//!   }
529 tk 1883
//! \endcode
1884
//! \param[in] callback_timeout the callback function (NULL disables the callback)
1885
//! \return < 0 on errors
1886
/////////////////////////////////////////////////////////////////////////////
1327 tk 1887
s32 MIOS32_MIDI_TimeOutCallback_Init(s32 (*callback_timeout)(mios32_midi_port_t port))
529 tk 1888
{
1889
  timeout_callback_func = callback_timeout;
1890
 
1891
  return 0; // no error
1892
}
1893
 
1894
 
1895
/////////////////////////////////////////////////////////////////////////////
1896
// This function is called if a MIDI parser runs into timeout
1897
/////////////////////////////////////////////////////////////////////////////
1898
static s32 MIOS32_MIDI_TimeOut(mios32_midi_port_t port)
1899
{
1900
  // if MIOS32 receives a SysEx command (MY_SYSEX flag set), abort parser if port matches
1901
  if( sysex_state.MY_SYSEX && port == last_sysex_port )
1902
    MIOS32_MIDI_SYSEX_CmdFinished();
1903
 
1904
  // optional hook to application
1905
  if( timeout_callback_func != NULL )
1906
    timeout_callback_func(port);
1907
 
1908
#if 1
1909
  // this debug message should always be active, so that common users are informed about the exception
1910
  MIOS32_MIDI_SendDebugMessage("[MIOS32_MIDI_Receive_Handler] Timeout on port 0x%02x\n", port);
1911
#endif
1912
 
1913
  return 0; // no error
1914
}
1915
 
32 tk 1916
#endif /* MIOS32_DONT_USE_MIDI */