Subversion Repositories svn.mios32

Rev

Rev 281 | Rev 283 | 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 282 2009-01-11 16:02:03Z 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>
24
 
25
// this module can be optionally disabled in a local mios32_config.h file (included from mios32.h)
26
#if !defined(MIOS32_DONT_USE_MIDI)
27
 
28
 
29
/////////////////////////////////////////////////////////////////////////////
30
// Global variables
31
/////////////////////////////////////////////////////////////////////////////
32
 
211 tk 33
//! this global array is read from MIOS32_IIC_MIDI and MIOS32_UART_MIDI to
34
//! determine the number of MIDI bytes which are part of a package
80 tk 35
const u8 mios32_midi_pcktype_num_bytes[16] = {
36
  0, // 0: invalid/reserved event
37
  0, // 1: invalid/reserved event
38
  2, // 2: two-byte system common messages like MTC, Song Select, etc.
39
  3, // 3: three-byte system common messages like SPP, etc.
40
  3, // 4: SysEx starts or continues
41
  1, // 5: Single-byte system common message or sysex sends with following single byte
42
  2, // 6: SysEx sends with following two bytes
43
  3, // 7: SysEx sends with following three bytes
44
  3, // 8: Note Off
45
  3, // 9: Note On
46
  3, // a: Poly-Key Press
47
  3, // b: Control Change
48
  2, // c: Program Change
49
  2, // d: Channel Pressure
50
  3, // e: PitchBend Change
51
  1  // f: single byte
52
};
32 tk 53
 
211 tk 54
//! Number if expected bytes for a common MIDI event - 1
89 tk 55
const u8 mios32_midi_expected_bytes_common[8] = {
56
  2, // Note On
57
  2, // Note Off
58
  2, // Poly Preasure
59
  2, // Controller
60
  1, // Program Change
61
  1, // Channel Preasure
62
  2, // Pitch Bender
63
  0, // System Message - must be zero, so that mios32_midi_expected_bytes_system[] will be used
64
};
80 tk 65
 
211 tk 66
//! Number if expected bytes for a system MIDI event - 1
89 tk 67
const u8 mios32_midi_expected_bytes_system[16] = {
68
  1, // SysEx Begin (endless until SysEx End F7)
69
  1, // MTC Data frame
70
  2, // Song Position
71
  1, // Song Select
72
  0, // Reserved
73
  0, // Reserved
74
  0, // Request Tuning Calibration
75
  0, // SysEx End
76
 
77
  // Note: just only for documentation, Realtime Messages don't change the running status
78
  0, // MIDI Clock
79
  0, // MIDI Tick
80
  0, // MIDI Start
81
  0, // MIDI Continue
82
  0, // MIDI Stop
83
  0, // Reserved
84
  0, // Active Sense
85
  0, // Reset
86
};
87
 
225 tk 88
//! should only be used by MIOS32 internally and by the Bootloader!
89
const u8 mios32_midi_sysex_header[5] = { 0xf0, 0x00, 0x00, 0x7e, 0x32 };
89 tk 90
 
225 tk 91
 
32 tk 92
/////////////////////////////////////////////////////////////////////////////
225 tk 93
// Local types
94
/////////////////////////////////////////////////////////////////////////////
95
 
96
typedef union {
97
  struct {
98
    unsigned ALL:8;
99
  };
100
 
101
  struct {
102
    unsigned CTR:3;
103
    unsigned CMD:1;
104
    unsigned MY_SYSEX:1;
105
  };
106
} sysex_state_t;
107
 
108
 
109
/////////////////////////////////////////////////////////////////////////////
32 tk 110
// Local variables
111
/////////////////////////////////////////////////////////////////////////////
112
 
225 tk 113
static mios32_midi_port_t default_port = MIOS32_MIDI_DEFAULT_PORT;
114
 
281 tk 115
static s32 (*direct_rx_callback_func)(mios32_midi_port_t port, u8 midi_byte);
116
static s32 (*direct_tx_callback_func)(mios32_midi_port_t port, mios32_midi_package_t package);
32 tk 117
 
225 tk 118
static sysex_state_t sysex_state;
119
static u8 sysex_device_id;
120
static u8 sysex_cmd;
121
static mios32_midi_port_t last_sysex_port = DEFAULT;
155 tk 122
 
225 tk 123
 
32 tk 124
/////////////////////////////////////////////////////////////////////////////
225 tk 125
// Local prototypes
126
/////////////////////////////////////////////////////////////////////////////
127
 
128
static s32 MIOS32_MIDI_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in);
129
static s32 MIOS32_MIDI_SYSEX_CmdFinished(void);
130
static s32 MIOS32_MIDI_SYSEX_Cmd(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in);
230 tk 131
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 132
static s32 MIOS32_MIDI_SYSEX_Cmd_Ping(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in);
133
static s32 MIOS32_MIDI_SYSEX_SendAck(mios32_midi_port_t port, u8 ack_code, u8 ack_arg);
230 tk 134
static s32 MIOS32_MIDI_SYSEX_SendAckStr(mios32_midi_port_t port, char *str);
225 tk 135
 
136
 
137
/////////////////////////////////////////////////////////////////////////////
211 tk 138
//! Initializes MIDI layer
139
//! \param[in] mode currently only mode 0 supported
140
//! \return < 0 if initialisation failed
32 tk 141
/////////////////////////////////////////////////////////////////////////////
142
s32 MIOS32_MIDI_Init(u32 mode)
143
{
144
  s32 ret = 0;
145
 
110 tk 146
  // currently only mode 0 supported
147
  if( mode != 0 )
32 tk 148
    return -1; // unsupported mode
149
 
225 tk 150
  // set default port as defined in mios32.h/mios32_config.h
151
  default_port = MIOS32_MIDI_DEFAULT_PORT;
152
 
155 tk 153
  // disable Rx/Tx callback functions
154
  direct_rx_callback_func = NULL;
155
  direct_tx_callback_func = NULL;
156
 
157
  // initialize interfaces
101 tk 158
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
110 tk 159
  if( MIOS32_USB_MIDI_Init(0) < 0 )
32 tk 160
    ret |= (1 << 0);
161
#endif
162
 
80 tk 163
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
110 tk 164
  if( MIOS32_UART_MIDI_Init(0) < 0 )
80 tk 165
    ret |= (1 << 1);
166
#endif
167
 
78 tk 168
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
110 tk 169
  if( MIOS32_IIC_MIDI_Init(0) < 0 )
80 tk 170
    ret |= (1 << 2);
78 tk 171
#endif
172
 
225 tk 173
  last_sysex_port = DEFAULT;
174
  sysex_state.ALL = 0;
175
 
176
  // TODO: allow to change device ID (read from flash, resp. BSL based EEPROM emulation)
177
  sysex_device_id = 0x00;
178
 
32 tk 179
  return -ret;
180
}
181
 
182
 
183
/////////////////////////////////////////////////////////////////////////////
211 tk 184
//! This function checks the availability of a MIDI port
185
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
186
//! \return 1: port available
187
//! \return 0: port not available
78 tk 188
/////////////////////////////////////////////////////////////////////////////
189
s32 MIOS32_MIDI_CheckAvailable(mios32_midi_port_t port)
190
{
191
  // if default port: select mapped port
192
  if( !(port & 0xf0) ) {
225 tk 193
    port = default_port;
78 tk 194
  }
195
 
196
  // branch depending on selected port
197
  switch( port >> 4 ) {
198
    case 1:
199
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
200
      return MIOS32_USB_MIDI_CheckAvailable();
201
#else
202
      return 0; // USB has been disabled
203
#endif
204
 
205
    case 2:
80 tk 206
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
207
      return MIOS32_UART_MIDI_CheckAvailable(port & 0xf);
208
#else
209
      return 0; // UART_MIDI has been disabled
210
#endif
78 tk 211
 
212
    case 3:
213
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
214
      return MIOS32_IIC_MIDI_CheckAvailable(port & 0xf);
215
#else
216
      return 0; // IIC_MIDI has been disabled
217
#endif
218
 
219
    case 4:
220
      return 0; // Ethernet not implemented yet
221
 
222
    default:
223
      // invalid port
224
      return 0;
225
  }
226
}
227
 
228
 
229
/////////////////////////////////////////////////////////////////////////////
211 tk 230
//! Sends a package over given port
281 tk 231
//!
211 tk 232
//! This is a low level function. In difference to other MIOS32_MIDI_Send* functions,
233
//! It allows to send packages in non-blocking mode (caller has to retry if -2 is returned)
281 tk 234
//!
235
//! Before the package is forwarded, an optional Tx Callback function will be called
236
//! which allows to filter/monitor/route the package, or extend the MIDI transmitter
237
//! by custom MIDI Output ports (e.g. for internal busses, OSC, AOUT, etc.)
211 tk 238
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
239
//! \param[in] package MIDI package
240
//! \return -1 if port not available
241
//! \return -2 buffer is full
242
//!         caller should retry until buffer is free again
281 tk 243
//! \return -3 Tx Callback reported an error
244
//! \return 1 if package has been filtered by Tx callback
211 tk 245
//! \return 0 on success
110 tk 246
/////////////////////////////////////////////////////////////////////////////
247
s32 MIOS32_MIDI_SendPackage_NonBlocking(mios32_midi_port_t port, mios32_midi_package_t package)
248
{
249
  // if default port: select mapped port
250
  if( !(port & 0xf0) ) {
225 tk 251
    port = default_port;
110 tk 252
  }
253
 
254
  // insert subport number into package
255
  package.cable = port & 0xf;
256
 
281 tk 257
  // forward to Tx callback function and break if package has been filtered
258
  if( direct_tx_callback_func != NULL ) {
259
    s32 status;
260
    if( status = direct_tx_callback_func(port, package) )
261
      return status;
262
  }
263
 
110 tk 264
  // branch depending on selected port
265
  switch( port >> 4 ) {
266
    case 1:
267
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 268
      return MIOS32_USB_MIDI_PackageSend_NonBlocking(package);
110 tk 269
#else
270
      return -1; // USB has been disabled
271
#endif
272
 
273
    case 2:
274
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
275
      return MIOS32_UART_MIDI_PackageSend_NonBlocking(package.cable, package);
276
#else
277
      return -1; // UART_MIDI has been disabled
278
#endif
279
 
280
    case 3:
281
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
282
      return MIOS32_IIC_MIDI_PackageSend_NonBlocking(package.cable, package);
283
#else
284
      return -1; // IIC_MIDI has been disabled
285
#endif
286
 
287
    case 4:
288
      return -1; // Ethernet not implemented yet
289
 
290
    default:
291
      // invalid port
292
      return -1;
293
  }
294
}
295
 
296
 
297
/////////////////////////////////////////////////////////////////////////////
211 tk 298
//! Sends a package over given port
299
//! This is a low level function - use the remaining MIOS32_MIDI_Send* functions
300
//! to send specific MIDI events
301
//! (blocking function)
302
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
303
//! \param[in] package MIDI package
304
//! \return -1 if port not available
305
//! \return 0 on success
32 tk 306
/////////////////////////////////////////////////////////////////////////////
69 tk 307
s32 MIOS32_MIDI_SendPackage(mios32_midi_port_t port, mios32_midi_package_t package)
32 tk 308
{
80 tk 309
  // if default port: select mapped port
310
  if( !(port & 0xf0) ) {
225 tk 311
    port = default_port;
80 tk 312
  }
313
 
32 tk 314
  // insert subport number into package
89 tk 315
  package.cable = port & 0xf;
32 tk 316
 
317
  // branch depending on selected port
318
  switch( port >> 4 ) {
80 tk 319
    case 1:
78 tk 320
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 321
      return MIOS32_USB_MIDI_PackageSend(package);
32 tk 322
#else
323
      return -1; // USB has been disabled
324
#endif
325
 
80 tk 326
    case 2:
327
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI)
328
      return MIOS32_UART_MIDI_PackageSend(package.cable, package);
329
#else
330
      return -1; // UART_MIDI has been disabled
331
#endif
32 tk 332
 
80 tk 333
    case 3:
78 tk 334
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
335
      return MIOS32_IIC_MIDI_PackageSend(package.cable, package);
336
#else
337
      return -1; // IIC_MIDI has been disabled
338
#endif
32 tk 339
 
80 tk 340
    case 4:
32 tk 341
      return -1; // Ethernet not implemented yet
342
 
343
    default:
344
      // invalid port
345
      return -1;
346
  }
347
}
348
 
349
 
350
/////////////////////////////////////////////////////////////////////////////
211 tk 351
//! Sends a MIDI Event
352
//! This function is provided for a more comfortable use model
353
//!    o MIOS32_MIDI_SendNoteOff(port, chn, note, vel)
354
//!    o MIOS32_MIDI_SendNoteOn(port, chn, note, vel)
355
//!    o MIOS32_MIDI_SendPolyAftertouch(port, chn, note, val)
356
//!    o MIOS32_MIDI_SendCC(port, chn, cc, val)
357
//!    o MIOS32_MIDI_SendProgramChange(port, chn, prg)
358
//!    o MIOS32_MIDI_ChannelAftertouch(port, chn, val)
359
//!    o MIOS32_MIDI_PitchBend(port, chn, val)
360
//!
361
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
362
//! \param[in] evnt0 first MIDI byte
225 tk 363
//! \param[in] evnt1 second MIDI byte
364
//! \param[in] evnt2 third MIDI byte
211 tk 365
//! \return -1 if port not available
366
//! \return 0 on success
32 tk 367
/////////////////////////////////////////////////////////////////////////////
69 tk 368
s32 MIOS32_MIDI_SendEvent(mios32_midi_port_t port, u8 evnt0, u8 evnt1, u8 evnt2)
32 tk 369
{
33 tk 370
  mios32_midi_package_t package;
371
 
372
  // MEMO: don't optimize this function by calling MIOS32_MIDI_SendSpecialEvent
373
  // from here, because the 4 * u8 parameter list of this function leads
374
  // to best compile results (4*u8 combined to a single u32)
375
 
376
  package.type  = evnt0 >> 4;
377
  package.evnt0 = evnt0;
378
  package.evnt1 = evnt1;
379
  package.evnt2 = evnt2;
380
  return MIOS32_MIDI_SendPackage(port, package);
32 tk 381
}
382
 
69 tk 383
s32 MIOS32_MIDI_SendNoteOff(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 vel)
136 tk 384
{ return MIOS32_MIDI_SendEvent(port, 0x80 | chn, note, vel); }
32 tk 385
 
69 tk 386
s32 MIOS32_MIDI_SendNoteOn(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 vel)
136 tk 387
{ return MIOS32_MIDI_SendEvent(port, 0x90 | chn, note, vel); }
69 tk 388
 
389
s32 MIOS32_MIDI_SendPolyPressure(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 note, u8 val)
136 tk 390
{ return MIOS32_MIDI_SendEvent(port, 0xa0 | chn, note, val); }
69 tk 391
 
392
s32 MIOS32_MIDI_SendCC(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 cc, u8 val)
136 tk 393
{ return MIOS32_MIDI_SendEvent(port, 0xb0 | chn, cc,   val); }
69 tk 394
 
395
s32 MIOS32_MIDI_SendProgramChange(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 prg)
136 tk 396
{ return MIOS32_MIDI_SendEvent(port, 0xc0 | chn, prg,  0x00); }
69 tk 397
 
398
s32 MIOS32_MIDI_SendAftertouch(mios32_midi_port_t port, mios32_midi_chn_t chn, u8 val)
136 tk 399
{ return MIOS32_MIDI_SendEvent(port, 0xd0 | chn, val,  0x00); }
69 tk 400
 
401
s32 MIOS32_MIDI_SendPitchBend(mios32_midi_port_t port, mios32_midi_chn_t chn, u16 val)
136 tk 402
{ return MIOS32_MIDI_SendEvent(port, 0xe0 | chn, val & 0x7f, val >> 7); }
69 tk 403
 
404
 
33 tk 405
/////////////////////////////////////////////////////////////////////////////
211 tk 406
//! Sends a special type MIDI Event
407
//! This function is provided for a more comfortable use model
408
//! It is aliased to following functions
409
//!    o MIOS32_MIDI_SendMTC(port, val)
410
//!    o MIOS32_MIDI_SendSongPosition(port, val)
411
//!    o MIOS32_MIDI_SendSongSelect(port, val)
412
//!    o MIOS32_MIDI_SendTuneRequest()
413
//!    o MIOS32_MIDI_SendClock()
414
//!    o MIOS32_MIDI_SendTick()
415
//!    o MIOS32_MIDI_SendStart()
416
//!    o MIOS32_MIDI_SendStop()
417
//!    o MIOS32_MIDI_SendContinue()
418
//!    o MIOS32_MIDI_SendActiveSense()
419
//!    o MIOS32_MIDI_SendReset()
420
//!
421
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
422
//! \param[in] type the event type
423
//! \param[in] evnt0 first MIDI byte
225 tk 424
//! \param[in] evnt1 second MIDI byte
425
//! \param[in] evnt2 third MIDI byte
211 tk 426
//! \return -1 if port not available
427
//! \return 0 on success
33 tk 428
/////////////////////////////////////////////////////////////////////////////
69 tk 429
s32 MIOS32_MIDI_SendSpecialEvent(mios32_midi_port_t port, u8 type, u8 evnt0, u8 evnt1, u8 evnt2)
33 tk 430
{
431
  mios32_midi_package_t package;
432
 
433
  package.type  = type;
434
  package.evnt0 = evnt0;
435
  package.evnt1 = evnt1;
436
  package.evnt2 = evnt2;
437
  return MIOS32_MIDI_SendPackage(port, package);
438
}
439
 
440
 
69 tk 441
s32 MIOS32_MIDI_SendMTC(mios32_midi_port_t port, u8 val)
136 tk 442
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x2, 0xf1, val, 0x00); }
69 tk 443
 
444
s32 MIOS32_MIDI_SendSongPosition(mios32_midi_port_t port, u16 val)
136 tk 445
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x3, 0xf2, val & 0x7f, val >> 7); }
69 tk 446
 
447
s32 MIOS32_MIDI_SendSongSelect(mios32_midi_port_t port, u8 val)
136 tk 448
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x2, 0xf3, val, 0x00); }
69 tk 449
 
450
s32 MIOS32_MIDI_SendTuneRequest(mios32_midi_port_t port)
136 tk 451
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf6, 0x00, 0x00); }
69 tk 452
 
453
s32 MIOS32_MIDI_SendClock(mios32_midi_port_t port)
136 tk 454
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf8, 0x00, 0x00); }
69 tk 455
 
456
s32 MIOS32_MIDI_SendTick(mios32_midi_port_t port)
136 tk 457
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xf9, 0x00, 0x00); }
69 tk 458
 
459
s32 MIOS32_MIDI_SendStart(mios32_midi_port_t port)
136 tk 460
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfa, 0x00, 0x00); }
69 tk 461
 
462
s32 MIOS32_MIDI_SendStop(mios32_midi_port_t port)
136 tk 463
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfb, 0x00, 0x00); }
69 tk 464
 
465
s32 MIOS32_MIDI_SendContinue(mios32_midi_port_t port)
136 tk 466
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfc, 0x00, 0x00); }
69 tk 467
 
468
s32 MIOS32_MIDI_SendActiveSense(mios32_midi_port_t port)
136 tk 469
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xfe, 0x00, 0x00); }
69 tk 470
 
471
s32 MIOS32_MIDI_SendReset(mios32_midi_port_t port)
136 tk 472
{ return MIOS32_MIDI_SendSpecialEvent(port, 0x5, 0xff, 0x00, 0x00); }
69 tk 473
 
474
 
33 tk 475
/////////////////////////////////////////////////////////////////////////////
211 tk 476
//! Sends a SysEx Stream
477
//! This function is provided for a more comfortable use model
478
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
479
//! \param[in] stream pointer to SysEx stream
480
//! \param[in] count number of bytes
481
//! \return -1 if port not available
482
//! \return 0 on success
33 tk 483
/////////////////////////////////////////////////////////////////////////////
69 tk 484
s32 MIOS32_MIDI_SendSysEx(mios32_midi_port_t port, u8 *stream, u32 count)
33 tk 485
{
486
  s32 res;
487
  u32 offset;
488
  mios32_midi_package_t package;
489
 
490
  // MEMO: have a look into the project.lss file - gcc optimizes this code pretty well :)
491
 
492
  for(offset=0; offset<count;) {
493
    // package type depends on number of remaining bytes
494
    switch( count-offset ) {
495
      case 1:
496
    package.type = 0x5; // SysEx ends with following single byte. 
497
    package.evnt0 = stream[offset++];
498
    package.evnt1 = 0x00;
499
    package.evnt2 = 0x00;
500
    break;
501
      case 2:
502
    package.type = 0x6; // SysEx ends with following two bytes.
503
    package.evnt0 = stream[offset++];
504
    package.evnt1 = stream[offset++];
505
    package.evnt2 = 0x00;
506
    break;
507
      case 3:
508
    package.type = 0x7; // SysEx ends with following three bytes. 
509
    package.evnt0 = stream[offset++];
510
    package.evnt1 = stream[offset++];
511
    package.evnt2 = stream[offset++];
512
    break;
513
      default:
514
    package.type = 0x4; // SysEx starts or continues
515
    package.evnt0 = stream[offset++];
516
    package.evnt1 = stream[offset++];
517
    package.evnt2 = stream[offset++];
518
    }
519
 
110 tk 520
    res=MIOS32_MIDI_SendPackage(port, package);
33 tk 521
 
110 tk 522
    // expection? (e.g., port not available)
33 tk 523
    if( res < 0 )
524
      return res;
525
  }
526
 
527
  return 0;
528
}
529
 
530
 
531
/////////////////////////////////////////////////////////////////////////////
211 tk 532
//! Checks for incoming MIDI messages, calls either the callback_event or
533
//! callback_sysex function with following parameters:
534
//! \code
535
//!    callback_event(mios32_midi_port_t port, mios32_midi_package_t midi_package)
536
//!    callback_sysex(mios32_midi_port_t port, u8 sysex_byte)
537
//! \endcode
538
//! \return < 0 on errors
33 tk 539
/////////////////////////////////////////////////////////////////////////////
540
s32 MIOS32_MIDI_Receive_Handler(void *_callback_event, void *_callback_sysex)
541
{
542
  u8 port;
543
  mios32_midi_package_t package;
544
 
69 tk 545
  void (*callback_event)(mios32_midi_port_t port, mios32_midi_package_t midi_package) = _callback_event;
546
  void (*callback_sysex)(mios32_midi_port_t port, u8 sysex_byte) = _callback_sysex;
33 tk 547
 
78 tk 548
  u8 intf = 0; // interface to be checked
549
  u8 total_packages_forwarded = 0; // number of forwards - stop after 10 forwards to yield some CPU time for other tasks
550
  u8 packages_forwarded = 0;
551
  u8 again = 1;
33 tk 552
  do {
78 tk 553
    // Round Robin
554
    // TODO: maybe a list based approach would be better
555
    // it would allow to add/remove interfaces dynamically
556
    // this would also allow to give certain ports a higher priority (to add them multiple times to the list)
557
    // it would also improve this spagetthi code ;)
558
    s32 error = -1;
559
    switch( intf++ ) {
560
#if !defined(MIOS32_DONT_USE_USB) && !defined(MIOS32_DONT_USE_USB_MIDI)
191 tk 561
      case 0: error = MIOS32_USB_MIDI_PackageReceive(&package); port = USB0 + package.cable; break;
78 tk 562
#else
563
      case 0: error = -1; break;
564
#endif
126 tk 565
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART0_ASSIGNMENT == 1
80 tk 566
      case 1: error = MIOS32_UART_MIDI_PackageReceive(0, &package); port = UART0; break;
78 tk 567
#else
568
      case 1: error = -1; break;
569
#endif
126 tk 570
#if !defined(MIOS32_DONT_USE_UART) && !defined(MIOS32_DONT_USE_UART_MIDI) && MIOS32_UART1_ASSIGNMENT == 1
80 tk 571
      case 2: error = MIOS32_UART_MIDI_PackageReceive(1, &package); port = UART1; break;
78 tk 572
#else
573
      case 2: error = -1; break;
574
#endif
575
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 576
      case 3: error = MIOS32_IIC_MIDI_PackageReceive(0, &package); port = IIC0; break;
78 tk 577
#else
578
      case 3: error = -1; break;
579
#endif
580
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 581
      case 4: error = MIOS32_IIC_MIDI_PackageReceive(1, &package); port = IIC1; break;
78 tk 582
#else
583
      case 4: error = -1; break;
584
#endif
585
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 586
      case 5: error = MIOS32_IIC_MIDI_PackageReceive(2, &package); port = IIC2; break;
78 tk 587
#else
588
      case 5: error = -1; break;
589
#endif
590
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 591
      case 6: error = MIOS32_IIC_MIDI_PackageReceive(3, &package); port = IIC3; break;
78 tk 592
#else
593
      case 6: error = -1; break;
594
#endif
595
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 596
      case 7: error = MIOS32_IIC_MIDI_PackageReceive(4, &package); port = IIC4; break;
78 tk 597
#else
598
      case 7: error = -1; break;
599
#endif
600
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
80 tk 601
      case 8: error = MIOS32_IIC_MIDI_PackageReceive(5, &package); port = IIC5; break;
78 tk 602
#else
603
      case 8: error = -1; break;
604
#endif
80 tk 605
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
606
      case 9: error = MIOS32_IIC_MIDI_PackageReceive(6, &package); port = IIC6; break;
607
#else
608
      case 9: error = -1; break;
609
#endif
610
#if !defined(MIOS32_DONT_USE_IIC) && !defined(MIOS32_DONT_USE_IIC_MIDI)
611
      case 10: error = MIOS32_IIC_MIDI_PackageReceive(7, &package); port = IIC7; break;
612
#else
613
      case 10: error = -1; break;
614
#endif
78 tk 615
      default:
616
    // allow 10 forwards maximum to yield some CPU time for other tasks
617
    if( packages_forwarded && total_packages_forwarded < 10 ) {
618
      intf = 0; // restart with USB
619
      packages_forwarded = 0; // for checking, if packages still have been forwarded in next round
620
    } else {
621
      again = 0; // no more interfaces to be processed
622
    }
623
    error = -1; // empty round - no message
624
    }
33 tk 625
 
78 tk 626
    // message received?
627
    if( error >= 0 ) {
628
      // notify that a package has been forwarded
629
      ++packages_forwarded;
630
      ++total_packages_forwarded;
33 tk 631
 
78 tk 632
      // remove cable number from package (MIOS32_MIDI passes it's own port number)
69 tk 633
      package.cable = 0;
33 tk 634
 
78 tk 635
      // branch depending on package type
33 tk 636
      if( package.type >= 0x8 ) {
217 tk 637
    if( callback_event != NULL )
638
      callback_event(port, package);
33 tk 639
      } else {
640
    switch( package.type ) {
641
    case 0x0: // reserved, ignore
642
    case 0x1: // cable events, ignore
643
      break;
644
 
645
    case 0x2: // Two-byte System Common messages like MTC, SongSelect, etc. 
646
    case 0x3: // Three-byte System Common messages like SPP, etc. 
217 tk 647
      if( callback_event != NULL )
648
        callback_event(port, package); // -> forwarded as event
33 tk 649
      break;
650
    case 0x4: // SysEx starts or continues (3 bytes)
217 tk 651
      if( callback_sysex != NULL ) {
652
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
653
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
654
        callback_sysex(port, package.evnt2); // -> forwarded as SysEx
655
      }
225 tk 656
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
657
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
658
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt2); // -> forward to MIOS32 SysEx Parser
33 tk 659
      break;
660
    case 0x5: // Single-byte System Common Message or SysEx ends with following single byte. 
217 tk 661
      if( package.evnt0 >= 0xf8 ) {
662
        if( callback_event != NULL )
663
          callback_event(port, package); // -> forwarded as event
664
      } else {
665
        if( callback_sysex != NULL )
666
          callback_sysex(port, package.evnt0); // -> forwarded as SysEx
225 tk 667
        MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
217 tk 668
      }
33 tk 669
      break;
670
    case 0x6: // SysEx ends with following two bytes.
217 tk 671
      if( callback_sysex != NULL ) {
672
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
673
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
674
      }
225 tk 675
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
676
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
33 tk 677
      break;
678
    case 0x7: // SysEx ends with following three bytes.
217 tk 679
      if( callback_sysex != NULL ) {
680
        callback_sysex(port, package.evnt0); // -> forwarded as SysEx
681
        callback_sysex(port, package.evnt1); // -> forwarded as SysEx
682
        callback_sysex(port, package.evnt2); // -> forwarded as SysEx
683
      }
225 tk 684
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt0); // -> forward to MIOS32 SysEx Parser
685
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt1); // -> forward to MIOS32 SysEx Parser
686
      MIOS32_MIDI_SYSEX_Parser(port, package.evnt2); // -> forward to MIOS32 SysEx Parser
33 tk 687
      break;
688
    }
689
      }
690
    }
691
  } while( again );
692
 
693
  return 0;
694
}
695
 
696
 
155 tk 697
/////////////////////////////////////////////////////////////////////////////
281 tk 698
//! Installs the Tx callback function which is executed by
699
//! MIOS32_MIDI_SendPackage_NonBlocking() before the MIDI package will be
700
//! forwarded to the physical interface.
701
//!
702
//! The callback allows following usecases:
703
//! <UL>
282 tk 704
//!   <LI>package filter
281 tk 705
//!   <LI>duplicating/routing packages
706
//!   <LI>monitoring packages (sniffer)
707
//!   <LI>create virtual busses; loopbacks
282 tk 708
//!   <LI>extend available ports (e.g. by an OSC or AOUT port)<BR>
709
//!       It is recommented to give port extensions a port number >= 0x80 to
710
//!       avoid incompatibility with future MIOS32 port extensions.
281 tk 711
//! </UL>
712
//! \param[in] *callback_tx pointer to callback function:<BR>
211 tk 713
//! \code
281 tk 714
//!    s32 callback_tx(mios32_midi_port_t port, mios32_midi_package_t package);
211 tk 715
//! \endcode
281 tk 716
//! The package will be forwarded to the physical interface if the function 
717
//! returns 0.<BR>
718
//! Should return 1 to filter a package.
719
//! Should return -2 to initiate a retry (function will be called again)
720
//! Should return -3 to report any other error.
721
//! These error codes comply with MIOS32_MIDI_SendPackage_NonBlocking()
211 tk 722
//! \return < 0 on errors
281 tk 723
//! \note Please use the filtering capabilities with special care - if a port
724
//! is filtered which is also used for code upload, you won't be able to exchange
725
//! the erroneous code w/o starting the bootloader in hold mode after power-on.
155 tk 726
/////////////////////////////////////////////////////////////////////////////
281 tk 727
s32 MIOS32_MIDI_DirectTxCallback_Init(void *callback_tx)
155 tk 728
{
729
  direct_tx_callback_func = callback_tx;
157 tk 730
 
731
  return 0; // no error
155 tk 732
}
733
 
734
 
735
/////////////////////////////////////////////////////////////////////////////
281 tk 736
//! Installs the Rx callback function which is executed immediately on each
737
//! incoming/outgoing MIDI byte, partly from interrupt handlers.
738
//!
739
//! This function should be executed so fast as possible. It can be used
740
//! to trigger MIDI Rx LEDs or to trigger on MIDI clock events. In order to
741
//! avoid MIDI buffer overruns, the max. recommented execution time is 100 uS!
742
//!
743
//! It is possible to filter incoming MIDI bytes with the return value of the
744
//! callback function.<BR>
745
//! \param[in] *callback_rx pointer to callback function:<BR>
746
//! \code
747
//!    s32 callback_rx(mios32_midi_port_t port, u8 midi_byte);
748
//! \endcode
749
//! The byte will be forwarded into the MIDI Rx queue if the function returns 0.<BR>
750
//! It will be filtered out if the callback returns != 0 (e.g. 1 for "filter", 
751
//! or -1 for "error").
752
//! \return < 0 on errors
753
//! \note Please use the filtering capabilities with special care - if a port
754
//! is filtered which is also used for code upload, you won't be able to exchange
755
//! the erroneous code w/o starting the bootloader in hold mode after power-on.
155 tk 756
/////////////////////////////////////////////////////////////////////////////
281 tk 757
s32 MIOS32_MIDI_DirectRxCallback_Init(void *callback_rx)
155 tk 758
{
281 tk 759
  direct_rx_callback_func = callback_rx;
155 tk 760
 
157 tk 761
  return 0; // no error
155 tk 762
}
763
 
281 tk 764
 
155 tk 765
/////////////////////////////////////////////////////////////////////////////
211 tk 766
//! This function is used by MIOS32 internal functions to forward received
281 tk 767
//! MIDI bytes to the Rx Callback routine.
768
//!
769
//! It shouldn't be used by applications.
211 tk 770
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
281 tk 771
//! \param[in] midi_byte received MIDI byte
211 tk 772
//! \return < 0 on errors
155 tk 773
/////////////////////////////////////////////////////////////////////////////
281 tk 774
s32 MIOS32_MIDI_SendByteToRxCallback(mios32_midi_port_t port, u8 midi_byte)
155 tk 775
{
776
  // note: here we could filter the user hook execution on special situations
281 tk 777
  if( direct_rx_callback_func != NULL )
778
    return direct_rx_callback_func(port, midi_byte);
157 tk 779
  return 0; // no error
155 tk 780
}
781
 
782
/////////////////////////////////////////////////////////////////////////////
211 tk 783
//! This function is used by MIOS32 internal functions to forward received
281 tk 784
//! MIDI packages to the Rx Callback routine (byte by byte)
785
//!
786
//! It shouldn't be used by applications.
211 tk 787
//! \param[in] port MIDI port (DEFAULT, USB0..USB7, UART0..UART1, IIC0..IIC7)
281 tk 788
//! \param[in] midi_package received MIDI package
211 tk 789
//! \return < 0 on errors
155 tk 790
/////////////////////////////////////////////////////////////////////////////
281 tk 791
s32 MIOS32_MIDI_SendPackageToRxCallback(mios32_midi_port_t port, mios32_midi_package_t midi_package)
155 tk 792
{
793
  // note: here we could filter the user hook execution on special situations
281 tk 794
  if( direct_rx_callback_func != NULL ) {
155 tk 795
    u8 buffer[3] = {midi_package.evnt0, midi_package.evnt1, midi_package.evnt2};
796
    int len = mios32_midi_pcktype_num_bytes[midi_package.cin];
797
    int i;
281 tk 798
    s32 status;
155 tk 799
    for(i=0; i<len; ++i)
281 tk 800
      status |= direct_rx_callback_func(port, buffer[i]);
801
    return status;
155 tk 802
  }
157 tk 803
  return 0; // no error
155 tk 804
}
805
 
225 tk 806
 
807
/////////////////////////////////////////////////////////////////////////////
808
//! This function allows to change the DEFAULT port.<BR>
809
//! The preset which will be used after application reset can be set in
810
//! mios32_config.h via "#define MIOS32_MIDI_DEFAULT_PORT <port>".<BR>
811
//! It's set to USB0 so long not overruled in mios32_config.h
812
//! \param[in] port MIDI port (USB0..USB7, UART0..UART1, IIC0..IIC7)
813
//! \return < 0 on errors
814
/////////////////////////////////////////////////////////////////////////////
815
s32 MIOS32_MIDI_DefaultPortSet(mios32_midi_port_t port)
816
{
817
  if( port == DEFAULT ) // avoid recursion
818
    return -1;
819
 
820
  default_port = port;
821
 
822
  return 0; // no error
823
}
824
 
825
/////////////////////////////////////////////////////////////////////////////
826
//! This function returns the DEFAULT port
827
//! \return the default port
828
/////////////////////////////////////////////////////////////////////////////
829
mios32_midi_port_t MIOS32_MIDI_DefaultPortGet(void)
830
{
831
  return default_port;
832
}
833
 
834
 
835
/////////////////////////////////////////////////////////////////////////////
836
//! This function sets the SysEx Device ID, which is used during parsing
837
//! incoming SysEx Requests to MIOS32<BR>
838
//! It can also be used by an application for additional parsing with the same ID.<BR>
839
//! ID changes will get lost after reset. It can be changed permanently by the
840
//! user via Bootloader Command 0x0c
841
//! \param[in] device_id a new (temporary) device ID (0x00..0x7f)
842
//! \return < 0 on errors
843
/////////////////////////////////////////////////////////////////////////////
844
s32 MIOS32_MIDI_DeviceIDSet(u8 device_id)
845
{
846
  sysex_device_id = device_id & 0x7f;
847
  return 0; // no error
848
}
849
 
850
/////////////////////////////////////////////////////////////////////////////
851
//! This function returns the SysEx Device ID, which is used during parsing
852
//! incoming SysEx Requests to MIOS32<BR>
853
//! It can also be used by an application for additional parsing with the same ID.<BR>
854
//! The initial ID is stored inside the BSL range and will be recovered after
855
//! reset. It can be changed by the user via Bootloader Command 0x0c
856
//! \return SysEx device ID (0x00..0x7f)
857
//! \todo store device ID via BSL based EEPROM emulation
858
/////////////////////////////////////////////////////////////////////////////
859
u8 MIOS32_MIDI_DeviceIDGet(void)
860
{
861
  return sysex_device_id;
862
}
863
 
864
 
865
/////////////////////////////////////////////////////////////////////////////
866
// This function parses an incoming sysex stream for MIOS32 commands
867
/////////////////////////////////////////////////////////////////////////////
868
static s32 MIOS32_MIDI_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in)
869
{
870
  // ignore realtime messages (see MIDI spec - realtime messages can
871
  // always be injected into events/streams, and don't change the running status)
872
  if( midi_in >= 0xf8 )
873
    return 0;
874
 
875
  // TODO: here we could send an error notification, that multiple devices are trying to access the device
876
  if( sysex_state.MY_SYSEX && port != last_sysex_port )
877
    return -1;
878
 
879
  last_sysex_port = port;
880
 
881
  // branch depending on state
882
  if( !sysex_state.MY_SYSEX ) {
883
    if( (sysex_state.CTR < sizeof(mios32_midi_sysex_header) && midi_in != mios32_midi_sysex_header[sysex_state.CTR]) ||
884
    (sysex_state.CTR == sizeof(mios32_midi_sysex_header) && midi_in != sysex_device_id) ) {
885
      // incoming byte doesn't match
886
      MIOS32_MIDI_SYSEX_CmdFinished();
887
    } else {
888
      if( ++sysex_state.CTR > sizeof(mios32_midi_sysex_header) ) {
889
    // complete header received, waiting for data
890
    sysex_state.MY_SYSEX = 1;
891
      }
892
    }
893
  } else {
894
    // check for end of SysEx message or invalid status byte
895
    if( midi_in >= 0x80 ) {
896
      if( midi_in == 0xf7 && sysex_state.CMD ) {
897
        MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_END, midi_in);
898
      }
899
      MIOS32_MIDI_SYSEX_CmdFinished();
900
    } else {
901
      // check if command byte has been received
902
      if( !sysex_state.CMD ) {
903
    sysex_state.CMD = 1;
904
    sysex_cmd = midi_in;
905
    MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN, midi_in);
906
      }
907
      else
908
    MIOS32_MIDI_SYSEX_Cmd(port, MIOS32_MIDI_SYSEX_CMD_STATE_CONT, midi_in);
909
    }
910
  }
911
 
912
  return 0; // no error
913
}
914
 
915
 
916
/////////////////////////////////////////////////////////////////////////////
917
// This function is called at the end of a sysex command or on 
918
// an invalid message
919
/////////////////////////////////////////////////////////////////////////////
920
static s32 MIOS32_MIDI_SYSEX_CmdFinished(void)
921
{
922
  // clear all status variables
923
  sysex_state.ALL = 0;
924
  sysex_cmd = 0;
925
 
926
  return 0; // no error
927
}
928
 
929
/////////////////////////////////////////////////////////////////////////////
930
// This function handles the sysex commands
931
/////////////////////////////////////////////////////////////////////////////
932
static s32 MIOS32_MIDI_SYSEX_Cmd(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
933
{
238 tk 934
#if MIOS32_MIDI_BSL_ENHANCEMENTS
935
  // this compile switch should only be activated for the bootloader!
936
  if( BSL_SYSEX_Cmd(port, cmd_state, midi_in, sysex_cmd) >= 0 )
937
    return 0; // BSL has serviced this command - no error
938
#endif
225 tk 939
  switch( sysex_cmd ) {
940
    case 0x00:
230 tk 941
      MIOS32_MIDI_SYSEX_Cmd_Query(port, cmd_state, midi_in);
225 tk 942
      break;
943
    case 0x0f:
944
      MIOS32_MIDI_SYSEX_Cmd_Ping(port, cmd_state, midi_in);
945
      break;
946
    default:
947
      // unknown command
948
      // TODO: send 0xf7 if merger enabled
949
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_INVALID_COMMAND);
950
      MIOS32_MIDI_SYSEX_CmdFinished();      
951
  }
952
 
953
  return 0; // no error
954
}
955
 
956
 
957
 
958
/////////////////////////////////////////////////////////////////////////////
230 tk 959
// Command 00: Query core informations and request BSL entry
225 tk 960
/////////////////////////////////////////////////////////////////////////////
230 tk 961
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 962
{
230 tk 963
  static u8 query_req = 0;
964
  char str_buffer[40];
225 tk 965
 
966
  switch( cmd_state ) {
967
 
968
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
230 tk 969
      query_req = 0;
225 tk 970
      break;
971
 
972
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
230 tk 973
      query_req = midi_in;
974
      break;
975
 
976
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
977
      switch( query_req ) {
978
        case 0x01: // operating system
979
      MIOS32_MIDI_SYSEX_SendAckStr(port, "MIOS32");
225 tk 980
      break;
237 tk 981
        case 0x02: // Board
230 tk 982
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_BOARD_STR);
225 tk 983
      break;
230 tk 984
        case 0x03: // Core Family
985
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_FAMILY_STR);
225 tk 986
      break;
230 tk 987
        case 0x04: // Chip ID
988
      sprintf(str_buffer, "%08x", MIOS32_SYS_ChipIDGet());
989
      MIOS32_MIDI_SYSEX_SendAckStr(port, (char *)str_buffer);
990
      break;
991
        case 0x05: // Serial Number
992
      if( MIOS32_SYS_SerialNumberGet((char *)str_buffer) >= 0 )
993
        MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
994
      else
995
        MIOS32_MIDI_SYSEX_SendAckStr(port, "?");
996
      break;
997
        case 0x06: // Flash Memory Size
998
      sprintf(str_buffer, "%d", MIOS32_SYS_FlashSizeGet());
999
      MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1000
      break;
1001
        case 0x07: // RAM Memory Size
1002
      sprintf(str_buffer, "%d", MIOS32_SYS_RAMSizeGet());
1003
      MIOS32_MIDI_SYSEX_SendAckStr(port, str_buffer);
1004
      break;
1005
        case 0x08: // Application Name Line #1
1006
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_LCD_BOOT_MSG_LINE1);
1007
      break;
1008
        case 0x09: // Application Name Line #2
1009
      MIOS32_MIDI_SYSEX_SendAckStr(port, MIOS32_LCD_BOOT_MSG_LINE2);
1010
      break;
1011
        case 0x7f:
231 tk 1012
#if MIOS32_MIDI_BSL_ENHANCEMENTS
1013
      // release halt state (or sending upload request) instead of reseting the core
1014
      BSL_SYSEX_ReleaseHaltState();
1015
#else
230 tk 1016
      // reset core (this will send an upload request)
1017
      MIOS32_SYS_Reset();
1018
      // at least on STM32 we will never reach this point
1019
      // but other core families could contain an empty stumb!
231 tk 1020
#endif
230 tk 1021
      break;
1022
        default:
1023
      // unknown query
1024
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_DISACK, MIOS32_MIDI_SYSEX_DISACK_UNKNOWN_QUERY);
225 tk 1025
      }
1026
  }
1027
 
1028
  return 0; // no error
1029
}
1030
 
1031
/////////////////////////////////////////////////////////////////////////////
1032
// Command 0F: Ping (just send back acknowledge)
1033
/////////////////////////////////////////////////////////////////////////////
1034
static s32 MIOS32_MIDI_SYSEX_Cmd_Ping(mios32_midi_port_t port, mios32_midi_sysex_cmd_state_t cmd_state, u8 midi_in)
1035
{
1036
  switch( cmd_state ) {
1037
 
1038
    case MIOS32_MIDI_SYSEX_CMD_STATE_BEGIN:
1039
      // nothing to do
1040
      break;
1041
 
1042
    case MIOS32_MIDI_SYSEX_CMD_STATE_CONT:
1043
      // nothing to do
1044
      break;
1045
 
1046
    default: // MIOS32_MIDI_SYSEX_CMD_STATE_END
1047
      // TODO: send 0xf7 if merger enabled
1048
 
1049
      // send acknowledge
1050
      MIOS32_MIDI_SYSEX_SendAck(port, MIOS32_MIDI_SYSEX_ACK, 0x00);
1051
 
1052
      break;
1053
  }
1054
 
1055
  return 0; // no error
1056
}
1057
 
1058
/////////////////////////////////////////////////////////////////////////////
1059
// This function sends a SysEx acknowledge to notify the user about the received command
1060
// expects acknowledge code (e.g. 0x0f for good, 0x0e for error) and additional argument
1061
/////////////////////////////////////////////////////////////////////////////
1062
static s32 MIOS32_MIDI_SYSEX_SendAck(mios32_midi_port_t port, u8 ack_code, u8 ack_arg)
1063
{
1064
  u8 sysex_buffer[32]; // should be enough?
1065
  u8 *sysex_buffer_ptr = &sysex_buffer[0];
1066
  int i;
1067
 
1068
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
1069
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
1070
 
1071
  // device ID
1072
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
1073
 
1074
  // send ack code and argument
1075
  *sysex_buffer_ptr++ = ack_code;
1076
  *sysex_buffer_ptr++ = ack_arg;
1077
 
1078
  // send footer
1079
  *sysex_buffer_ptr++ = 0xf7;
1080
 
1081
  // finally send SysEx stream
1082
  return MIOS32_MIDI_SendSysEx(port, (u8 *)sysex_buffer, (u32)sysex_buffer_ptr - ((u32)&sysex_buffer[0]));
1083
}
1084
 
230 tk 1085
/////////////////////////////////////////////////////////////////////////////
1086
// This function sends an SysEx acknowledge with a string (used on queries)
1087
/////////////////////////////////////////////////////////////////////////////
1088
static s32 MIOS32_MIDI_SYSEX_SendAckStr(mios32_midi_port_t port, char *str)
1089
{
1090
  u8 sysex_buffer[128]; // should be enough?
1091
  u8 *sysex_buffer_ptr = &sysex_buffer[0];
1092
  int i;
225 tk 1093
 
230 tk 1094
  for(i=0; i<sizeof(mios32_midi_sysex_header); ++i)
1095
    *sysex_buffer_ptr++ = mios32_midi_sysex_header[i];
155 tk 1096
 
230 tk 1097
  // device ID
1098
  *sysex_buffer_ptr++ = MIOS32_MIDI_DeviceIDGet();
1099
 
1100
  // send ack code
1101
  *sysex_buffer_ptr++ = MIOS32_MIDI_SYSEX_ACK;
1102
 
1103
  // send string
1104
  for(i=0; i<100 && str[i] != 0; ++i)
1105
    *sysex_buffer_ptr++ = str[i];
1106
 
1107
  // send footer
1108
  *sysex_buffer_ptr++ = 0xf7;
1109
 
1110
  // finally send SysEx stream
1111
  return MIOS32_MIDI_SendSysEx(port, (u8 *)sysex_buffer, (u32)sysex_buffer_ptr - ((u32)&sysex_buffer[0]));
1112
}
1113
 
32 tk 1114
#endif /* MIOS32_DONT_USE_MIDI */