Subversion Repositories svn.mios32

Rev

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