Subversion Repositories svn.mios32

Rev

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