Subversion Repositories svn.mios32

Rev

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