Subversion Repositories svn.mios32

Rev

Rev 2646 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2646 Antichambr 1
// $Id: mios32_uart_midi.c 2312 2016-02-27 23:04:51Z tk $
2
//! \defgroup MIOS32_CAN_MIDI
3
//!
4
//! CAN MIDI layer for MIOS32
5
//!
6
//! Applications shouldn't call these functions directly, instead please use \ref MIOS32_MIDI layer functions
7
//!
8
//! \{
9
/* ==========================================================================
10
 *
11
 *  Copyright (C) 2008 Thorsten Klose (tk@midibox.org)
12
 *  Licensed for personal non-commercial use only.
13
 *  All other rights reserved.
14
 *
15
 * ==========================================================================
16
 */
17
 
18
/////////////////////////////////////////////////////////////////////////////
19
// Include files
20
/////////////////////////////////////////////////////////////////////////////
21
 
22
#include <mios32.h>
23
#include <stdlib.h>
24
#include <string.h>
25
 
26
// this module can be optionally disabled in a local mios32_config.h file (included from mios32.h)
27
#if defined(MIOS32_USE_CAN_MIDI)
28
 
29
#define MIOS32_CAN_MIDI_ID_MASK 0xe1fffffc
30
/////////////////////////////////////////////////////////////////////////////
31
// Global variables
32
/////////////////////////////////////////////////////////////////////////////
33
 
34
 
35
#define DEBUG_CAN_LVL1 {if(can_midi_verbose)MIOS32_MIDI_SendDebugMessage}
36
#define DEBUG_CAN_LVL2 {if(can_midi_verbose>=2)MIOS32_MIDI_SendDebugMessage}
37
#define DEBUG_CAN_LVL3 {if(can_midi_verbose>=3)MIOS32_MIDI_SendDebugMessage}
38
/////////////////////////////////////////////////////////////////////////////
39
// Local Types
40
/////////////////////////////////////////////////////////////////////////////
41
 
42
typedef union {
43
  u8 stat;
44
  struct {
45
    u8 waiting:1;
46
    u8 ready:1;
47
    u8 ending:1;
48
    u8 :5;
49
  };
50
} sysex_stat_rec_t;
51
 
52
typedef struct sysex_unpack_rec_t{
53
  sysex_stat_rec_t stat;
54
  u32 ext_id;
55
  u32 ports;
56
#if defined(MIOS32_CAN_MIDI_SYSEX_STREAM_FIRST)
57
  u8  buffer[1024];
58
#else
59
  u8  buffer[11];
60
#endif
61
  u16 ctr;
62
  u16 timeout_ctr;
63
} sysex_unpack_rec_t;
64
 
65
typedef struct sysex_repack_rec_t{
66
  sysex_stat_rec_t stat;
67
  u32 ext_id;
68
  u32 data_l;
69
  u8  buffer[10];
70
  u8  ctr;
71
  u16 packet;
72
  u16 timeout_ctr;
73
} sysex_repack_rec_t;
74
 
75
 
76
#if MIOS32_CAN_NUM
77
/////////////////////////////////////////////////////////////////////////////
78
// Global variables
79
/////////////////////////////////////////////////////////////////////////////
80
 
81
// CAN MIDI Node Id
82
#if defined MIOS32_CAN_MIDI_NODE_ID
83
u8 mios32_mcan_id = MIOS32_CAN_MIDI_NODE_ID;
84
#else
85
// if not precised it becomes Device_Id on init but can be changed by SW.
86
u8 mios32_mcan_id;
87
#endif
88
 
89
/////////////////////////////////////////////////////////////////////////////
90
// Local variables
91
/////////////////////////////////////////////////////////////////////////////
92
 
93
static u8 mios32_mcan_enhanced = 0;
94
 
95
// status structure for sysex record
96
static sysex_unpack_rec_t sysex_unpack[MIOS32_CAN_MIDI_NUM_PORTS];
97
 
98
// SysEx repack data structure
99
static sysex_repack_rec_t sysex_repack[MIOS32_CAN_MIDI_NUM_PORTS];
100
 
101
// active sense delay counter
102
s16 node_active_sense_ctr;
103
// for frame rate calculation
104
static u32 frame_rate;
105
static u32 can_last_baudrate;
106
 
107
// callback for direct sysex stream
2657 Antichambr 108
static s32 (*sysex_stream_callback_func)(mios32_mcan_header_t header, u8* stream, u16 size);
109
static s32 (*direct_package_callback_func)(mios32_mcan_header_t header, mios32_midi_package_t package);
2646 Antichambr 110
 
111
// verbose
112
static u8 can_midi_verbose = 2;
113
 
114
#endif
115
 
116
 
117
/////////////////////////////////////////////////////////////////////////////
118
/////////////////////////////////////////////////////////////////////////////
119
 
120
// internal function to reset the record structure
121
static s32 MIOS32_CAN_MIDI_SysexUnpackReset(sysex_unpack_rec_t* sysex_unpack)
122
{
123
#if MIOS32_CAN_NUM > 0
124
 
125
  memset(sysex_unpack, 0, sizeof (struct sysex_unpack_rec_t));
126
 
127
#endif
128
  return 0; // no error
129
}
130
 
131
/////////////////////////////////////////////////////////////////////////////
132
/////////////////////////////////////////////////////////////////////////////
133
 
134
// internal function to reset the record structure
135
static s32 MIOS32_CAN_MIDI_SysexRepackReset(sysex_repack_rec_t* sysex_repack)
136
{
137
#if MIOS32_CAN_NUM > 0
138
 
139
  memset(sysex_repack, 0, sizeof (struct sysex_repack_rec_t));
140
 
141
#endif
142
  return 0; // no error
143
}
144
/////////////////////////////////////////////////////////////////////////////
145
/////////////////////////////////////////////////////////////////////////////
146
 
147
// internal function to parse configuration commands
2657 Antichambr 148
static s32 MIOS32_CAN_MIDI_LocalCmdParser(mios32_mcan_header_t header, mios32_midi_package_t* package)
2646 Antichambr 149
{
150
#if MIOS32_CAN_NUM > 0
151
 
152
 
153
 
154
#endif
155
  return 0; // no error
156
}
157
 
158
/////////////////////////////////////////////////////////////////////////////
159
//! Initializes CAN MIDI layer
160
//! \param[in] mode currently only mode 0 supported
161
//! \return < 0 if initialisation failed
162
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
163
/////////////////////////////////////////////////////////////////////////////
164
s32 MIOS32_CAN_MIDI_Init(u32 mode)
165
{
166
 
167
#if MIOS32_CAN_NUM == 0
168
  return -1; // no CAN enabled
169
#else
170
  int i;
171
 
172
  // currently only mode 0 supported
173
  if( mode != 0 )
174
    return -2; // unsupported mode
175
 
176
#if defined MIOS32_CAN_MIDI_ENHANCED
177
  MIOS32_CAN_MIDI_ModeSet(1);
178
#else
179
  MIOS32_CAN_MIDI_ModeSet(0);
180
#endif
181
 
182
#if defined MIOS32_CAN_MIDI_VERBOSE_LEVEL
183
  // set defined verbose
184
  MIOS32_CAN_MIDI_VerboseSet(MIOS32_CAN_MIDI_VERBOSE_LEVEL);
185
#endif
186
 
187
  // set active sense delay counter in mS
188
  node_active_sense_ctr = 1000;
189
 
190
  // initialize MIDI record
191
  for (i=0; i<MIOS32_CAN_MIDI_NUM_PORTS; i++) {
192
    MIOS32_CAN_MIDI_SysexUnpackReset(&sysex_unpack[i]);
193
    MIOS32_CAN_MIDI_SysexRepackReset(&sysex_repack[i]);
194
  }
195
 
196
 
197
  sysex_stream_callback_func = NULL;
198
 
199
  // if any MIDI assignment:
200
#if MIOS32_CAN1_ASSIGNMENT == 1 
201
  // initialize CAN interface
202
  if( MIOS32_CAN_Init(0) < 0 )
203
    return -3; // initialisation of CAN Interface failed
204
 
205
  // by default the Node ID is the Sysex Device ID
206
  // Think about configure a different Device_ID for each of your device present on the MIDIan
207
  // via the bootloader update tool.
208
  //MIOS32_CAN_MIDI_NodeIDSet(MIOS32_MIDI_DeviceIDGet());
209
 
210
  // Initialize permanent filtering for Node System Exclusive and Common messages
211
  MIOS32_CAN_MIDI_FilterInit(1);
212
 
213
 
214
#endif
215
 
216
  return 0; // no error
217
#endif
218
}
219
 
220
/////////////////////////////////////////////////////////////////////////////
221
//! Initializes CAN MIDI layer
222
//! \param[in] mode currently only mode 0 supported
223
//! \return < 0 if initialisation failed
224
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
225
/////////////////////////////////////////////////////////////////////////////
226
s32 MIOS32_CAN_MIDI_VerboseSet(u8 level)
227
{
228
#if MIOS32_CAN_NUM == 0
229
  return -1; // no CAN enabled
230
#else
231
 
232
  can_midi_verbose = level;
233
  MIOS32_CAN_VerboseSet(level); // they are independant e.g. CAN is used but not for midi purpose
234
  return 0; // no error
235
#endif
236
}
237
 
238
/////////////////////////////////////////////////////////////////////////////
239
//! Initializes CAN MIDI layer
240
//! \param[in] mode currently only mode 0 supported
241
//! \return < 0 if initialisation failed
242
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
243
/////////////////////////////////////////////////////////////////////////////
244
s32 MIOS32_CAN_MIDI_VerboseGet(void)
245
{
246
#ifndef MIOS32_CAN_MIDI_VERBOSE_LEVEL
247
  return 0;
248
#else
249
#if MIOS32_CAN_NUM == 0
250
  return -1; // no CAN enabled
251
#else
252
  return can_midi_verbose; // no error
253
#endif
254
#endif
255
}
256
 
257
 
258
/////////////////////////////////////////////////////////////////////////////
259
// Changes the Node ID, Default startup Id is the Device_Id
260
// IN: node_id: configures the CAN_MIDI Node ID
261
//              MIDIan has no master and slave ID node
262
// OUT: returns < 0 if configuration failed
263
// Note id is the same for both CAN
264
/////////////////////////////////////////////////////////////////////////////
265
s32 MIOS32_CAN_MIDI_NodeIDSet(u8 node_id)
266
{
267
#ifndef MIOS32_CAN_MIDI_VERBOSE_LEVEL
268
  return 0;
269
#else
270
#if MIOS32_CAN_NUM == 0
271
  return -1; // no CAN enabled
272
#else
273
 
274
  // my node_id must be 0..127
275
  if( node_id >= 128 )
276
    return -1;
277
 
278
  // take over node ID
279
  mios32_mcan_id = node_id;
280
 
281
  return 0; // no error
282
#endif
283
#endif
284
}
285
 
286
 
287
/////////////////////////////////////////////////////////////////////////////
288
// Returns the Node ID
289
// IN: -
290
// OUT: if -1: node not configured yet
291
//      if >= 0: node ID
292
/////////////////////////////////////////////////////////////////////////////
293
s32 MIOS32_CAN_MIDI_NodeIDGet(void)
294
{
295
#if MIOS32_CAN_NUM == 0
296
  return -1; // no CAN enabled
297
#else
298
  return mios32_mcan_id;
299
#endif
300
}
301
 
302
/////////////////////////////////////////////////////////////////////////////
303
// Changes the Node ID, Default startup Id is the Device_Id
304
// IN: node_id: configures the CAN_MIDI Node ID
305
//              MIDIan has no master and slave ID node
306
// OUT: returns < 0 if configuration failed
307
// Note id is the same for both CAN
308
/////////////////////////////////////////////////////////////////////////////
309
s32 MIOS32_CAN_MIDI_ModeSet(u8 mode)
310
{
311
#if MIOS32_CAN_NUM == 0
312
  return -1; // no CAN enabled
313
#else
314
  mios32_mcan_enhanced = 0;
315
  if(mode)mios32_mcan_enhanced = 1;
316
 
317
  return 0; // no error
318
#endif
319
}
320
 
321
 
322
/////////////////////////////////////////////////////////////////////////////
323
// Returns the Node ID
324
// IN: -
325
// OUT: if -1: node not configured yet
326
//      if >= 0: node ID
327
/////////////////////////////////////////////////////////////////////////////
328
s32 MIOS32_CAN_MIDI_ModeGet(void)
329
{
330
#if MIOS32_CAN_NUM == 0
331
  return -1; // no CAN enabled
332
#else
333
  return mios32_mcan_enhanced;
334
#endif
335
}
336
 
337
 
338
/////////////////////////////////////////////////////////////////////////////
339
//! Initializes CAN MIDI layer
340
//! \param[in] bypass 0:off, >=1:on
341
//! \return < 0 if initialisation failed
342
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
343
/////////////////////////////////////////////////////////////////////////////
344
s32 MIOS32_CAN_MIDI_FilterInit(u8 bypass)
345
{
346
#if MIOS32_CAN_NUM == 0
347
  return -1; // no CAN enabled
348
#else
349
 
350
  //u8 i;
2657 Antichambr 351
  //mios32_can_ext_filter_t filt32;
352
  mios32_can_std_filter_t filt16[2];
2646 Antichambr 353
 
354
//  /* Node System messages and bypass -> Fifo0 */
355
//  // filter Bank#0, checks for incoming Node SysEx and SysCom messages
356
//  filt32.filt.ALL = 0;
357
//  filt32.filt.event = 0xf8;
358
//  //filt32.filt.dst_devid = mios32_mcan_id;
359
//  filt32.filt.ide = 1; // 29bits extented id
360
//  filt32.mask.ALL = 0;
361
//  filt32.mask.event = 0xf8; // =>0xf8 only
362
//  //filt32.mask.dst_devid = 0x7f;
363
//  filt32.mask.ide = 1;
364
//  MIOS32_CAN_Init32bitFilter(0, 0, filt32, 1); // CAN1, FIFO0, filter, enabled
365
 
366
  // filter Bank#1, checks for incoming Node System Common and bypass
367
 
368
 
369
  filt16[0].filt.ALL = 0; // Second 16bit filter is a Bypass filter
370
  //this 11bit id must never happen.
371
  //filt16[0].mask.event = (bypass ? 0x00 : 0xff); // 0xff: bypass off, 0x00: bypass on.
372
  filt16[0].mask.ALL = 0x00;
373
 
374
  filt16[1].filt.ALL = 0; // Second not used
375
  filt16[1].mask.ALL = 0x00;
376
  MIOS32_CAN_Init16bitFilter(0, 0, filt16[0], filt16[1], 1); // CAN1, FIFO0, filter, enabled
377
 
378
//  /* Device System messages and Real Time -> Fifo0 */
379
//  // filter Bank#2, checks for incoming Device(s) SysEx messages
380
//  filt32.filt.ALL = 0;
381
//  filt32.filt.event = 0xf0;
382
//  filt32.filt.ide = 1; // 29bits extented id
383
//  filt32.mask.ALL = 0;
384
//  filt32.mask.event = 0xff; // =>0xf0 only
385
//  filt32.mask.ide = 1;
386
//  MIOS32_CAN_Init32bitFilter(2, 0, filt32, 1); // CAN1, FIFO0, filter, enabled
387
//  
388
//  // filter Bank#3, checks for incoming Device System Common and Real Time
389
//  filt16[0].filt.ALL = 0; // first 16bit filter, Device SysCom
390
//  filt16[0].filt.event = 0xf0;
391
//  filt16[0].mask.ALL = 0;
392
//  filt16[0].mask.event = 0xf8; // =>0xf1...0xf7
393
//  
394
//  filt16[1].filt.ALL = 0; // Second 16bit filter, Real Time
395
//  filt16[1].filt.event = 0x78;
396
//  filt16[1].filt.ide = 0; // 11bits standard id
397
//  filt16[1].mask.ALL = 0;
398
//  filt16[1].mask.event = 0xf8; // =>0x78...0x7f
399
//  filt16[1].mask.ide = 0;
400
//  MIOS32_CAN_Init16bitFilter(3, 0, filt16[0], filt16[1], 1); // CAN1, FIFO0, filter, enabled
401
//  
402
//  /* Device Voicing messages -> Fifo1 */
403
//  // filter Bank#0x7..0xd , checks for incoming Device Channel Voice messages
404
//  filt32.filt.ALL = 0;
405
//  filt32.filt.ide = 1; // 29bits extented id
406
//  filt32.mask.ALL = 0;
407
//  filt32.mask.status = 0xf;
408
//  filt32.mask.ide = 1;
409
//  for (i=0x8; i<=0xe; i++) {
410
//    filt32.filt.status = i;
411
//    MIOS32_CAN_Init32bitFilter(i-1, 1, filt32, 1); // CAN1, FIFO0, filter, enabled
412
//  }
413
  return 0; // no error
414
#endif
415
}
416
 
417
/////////////////////////////////////////////////////////////////////////////
418
//! This function can be used to determine, if a CAN interface is available
419
//! \param[in] can_port CAN number (0..2)
420
//! \return 1: interface available
421
//! \return 0: interface not available
422
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
423
/////////////////////////////////////////////////////////////////////////////
424
s32 MIOS32_CAN_MIDI_CheckAvailable(u8 cable)
425
{
426
#if MIOS32_CAN_NUM == 0
427
  return -1; // all CANs explicitely disabled
428
#else
429
    if (MIOS32_CAN_IsAssignedToMIDI(0) == 0) // CAN assigned to MIDI?
430
      return 0;
431
    if( (cable & 0x0f) >= MIOS32_CAN_MIDI_NUM_PORTS )
432
      return 0;
433
#endif
434
  return 1;
435
}
436
 
437
/////////////////////////////////////////////////////////////////////////////
438
//! This function should be called periodically each mS to handle timeout
439
//! and expire counters.
440
//!
441
//! Not for use in an application - this function is called from
442
//! MIOS32_MIDI_Periodic_mS(), which is called by a task in the programming
443
//! model!
444
//!
445
//! \return < 0 on errors
446
/////////////////////////////////////////////////////////////////////////////
447
s32 MIOS32_CAN_MIDI_Periodic_mS(void)
448
{
449
#if MIOS32_CAN_NUM == 0
450
  return -1; // all CANs explicitely disabled
451
#else
452
  u8 cable;
453
 
454
  MIOS32_IRQ_Disable();
455
  for(cable=0; cable<MIOS32_CAN_MIDI_NUM_PORTS; cable++) {
456
    // simplify addressing of sysex record
457
    sysex_repack_rec_t *rpk = &sysex_repack[cable];
458
    sysex_unpack_rec_t *upk = &sysex_unpack[cable];
459
    //    // increment the expire counters for running status optimisation.
460
    //    //
461
    //    // The running status will expire after 1000 ticks (1 second)
462
    //    // to ensure, that the current status will be sent at least each second
463
    //    // to cover the case that the MIDI cable is (re-)connected during runtime.
464
    //    if( rs_expire_ctr[can_port] < 65535 )
465
    //      ++rs_expire_ctr[can_port];
466
 
467
    // increment timeout counter for incoming packages
468
    // an incomplete event will be timed out after 1000 ticks (1 second)
469
    if( rpk->timeout_ctr < 65535 )
470
      rpk->timeout_ctr++;
471
    if( upk->timeout_ctr < 65535 )
472
      upk->timeout_ctr++;
473
  }
474
  MIOS32_IRQ_Enable();
475
  // (atomic operation not required in MIOS32_CAN_MIDI_PackageSend_NonBlocking() due to single-byte accesses)
476
  if(can_midi_verbose == 0) return 0; // no error
477
  if( (--node_active_sense_ctr) <=0 ){
478
    node_active_sense_ctr = 1000; // every second
479
    u32 new_frame_rate;
480
    if( MIOS32_CAN_MIDI_CheckAvailable(0) ){
481
 
2657 Antichambr 482
      mios32_can_stat_report_t report;
2646 Antichambr 483
      MIOS32_CAN_ReportGetCurr(0, &report);
484
 
485
      new_frame_rate = report.rx_packets_ctr - can_last_baudrate;
486
      can_last_baudrate = report.rx_packets_ctr;
487
      if(frame_rate != new_frame_rate){
488
        frame_rate = new_frame_rate;
489
        u8 percent =(u8)(new_frame_rate /245);
490
        MIOS32_MIDI_SendDebugMessage("[MIOS32_CAN_MIDI_Periodic_mS] framerate: %d f/s, %d%%", new_frame_rate, percent);
491
      }
492
 
493
      mios32_midi_package_t  p;
494
      p.ALL = 0;
495
      p.cin = 0x5;
496
      p.cable = 0x0;
497
      p.evnt0 = 0xfe ; // active sense
498
 
499
      MIOS32_CAN_MIDI_PackageSend(p);
500
      //MIOS32_CAN_MIDI_PacketTransmit(0, p);
501
    }
502
}
503
 
504
#endif
505
 
506
  return 0; // no error
507
}
508
 
509
 
510
/////////////////////////////////////////////////////////////////////////////
511
//! This function transfers a new MCAN packet to the selected MCAN port
512
//! \param[in] MCAN Packet
513
//! \return 0: no error
514
//! \return -1: CAN_MIDI device not available
515
//! \return -2: CAN_MIDI buffer is full
516
//!             caller should retry until buffer is free again
517
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
518
/////////////////////////////////////////////////////////////////////////////
2657 Antichambr 519
s32 MIOS32_CAN_MIDI_PacketTransmit_NonBlocking(mios32_mcan_packet_t p)
2646 Antichambr 520
{
521
#if MIOS32_CAN_NUM == 0
522
  return -1; // all CANs explicitely disabled
523
#else
524
  // tx enabler bit
525
  p.id.txrq = 1;
526
#if defined(MIOS32_CAN_MIDI_VERBOSE_LEVEL)
527
  if(can_midi_verbose>=3){DEBUG_MSG("[MIOS32_CAN_MIDI_PacketTransmit] [0x%02x][0x%02x][0x%02x][0x%02x][0x%02x][0x%02x][0x%02x][0x%02x]\n", p.data.bytes[0],p.data.bytes[1],p.data.bytes[2],p.data.bytes[3],p.data.bytes[4],p.data.bytes[5],p.data.bytes[6],p.data.bytes[7]);}
528
#endif
529
  switch( MIOS32_CAN_TxBufferPut(0, p.packet) ) {
530
  //switch( MIOS32_CAN_Transmit(can_port, p, 0) ) {
531
    case  0 ... 2: return  0; // transfer successfull
532
    case -1: return -1;
533
    case -2: return -2; // buffer full, request retry
534
    case -3: return -3; // CAN bus error
535
    default: return -4; // CAN not available
536
  }
537
 
538
#endif
539
}
540
 
541
/////////////////////////////////////////////////////////////////////////////
542
//! This function transfers a new MCAN packet to the selected MCAN port
543
//! (blocking function)
544
//! \param[in] MCAN Packet
545
//! \return 0: no error
546
//! \return -1: CAN_MIDI device not available
547
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
548
/////////////////////////////////////////////////////////////////////////////
2657 Antichambr 549
s32 MIOS32_CAN_MIDI_PacketTransmit(mios32_mcan_packet_t p)
2646 Antichambr 550
{
551
  s32 error;
552
 
553
  while( (error=MIOS32_CAN_MIDI_PacketTransmit_NonBlocking(p)) == -2);
554
 
555
  return error;
556
}
557
 
558
/////////////////////////////////////////////////////////////////////////////
559
//! This function formats and transfers a new MCAN packet to the selected MCAN port
560
//! \param[in] header MCAN Extra Infos
561
//! \param[in] package MIDI package
562
//! \return 0: no error
563
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
564
/////////////////////////////////////////////////////////////////////////////
2657 Antichambr 565
s32 MIOS32_CAN_MIDI_PacketSend_NonBlocking(mios32_mcan_header_t header, mios32_midi_package_t package)
2646 Antichambr 566
{
567
#if MIOS32_CAN_NUM == 0
568
  return -1; // all CANs explicitely disabled
569
#else
570
  // exit if MCANx port not available
571
  if( !MIOS32_CAN_MIDI_CheckAvailable(package.cable) )
572
    return -3;
573
 
574
  s32 error = 0;
575
 
576
  // Parse package to Sysex repack
577
  // notes: see "const u8 mios32_mcan_pcktype_num_bytes[16]"
578
  if(package.evnt0 == 0xf0 && package.type == 0x4) {
579
    //header.cin_cable = 0x40 + package.cable;  // Start
580
    error = MIOS32_CAN_MIDI_SysexRepackSend(header, package);
581
    return error;
582
  }else if(package.type == 0x4) {
583
    //header.cin_cable = 0x60 + package.cable; // Cont
584
    error = MIOS32_CAN_MIDI_SysexRepackSend(header, package);
585
    return error;
586
  }else if(package.type == 0x5 && package.evnt0 == 0xf7){
587
    //header.cin_cable = 0x70 + package.cable;  // end
588
    error = MIOS32_CAN_MIDI_SysexRepackSend(header, package);
589
    return error;
590
  }else if(package.type == 0x6 || package.type == 0x7){
591
    //header.cin_cable = 0x70 + package.cable;  // end
592
    error = MIOS32_CAN_MIDI_SysexRepackSend(header, package);
593
    return error;
594
  }else{ // This is not Sysex
2657 Antichambr 595
    mios32_mcan_packet_t p;
2646 Antichambr 596
    //p.frame_id = header.frame_id;
597
    u8* byte = &p.data.bytes[0];
598
    p.ctrl.dlc = 0;
599
#if defined(MIOS32_CAN_MIDI_ENHANCED)
600
    // On extended frame adds the src/dst ports infos
601
    if(header.is_extended == 1){
602
      *byte++ = header.dst_port;
603
      *byte++ = header.src_port;
604
      p.ctrl.dlc += 2;
605
    }
606
#endif
607
    // Adds data depending on expected bytes
608
    u8 expected_bytes = mios32_midi_pcktype_num_bytes[header.type];
609
    switch (expected_bytes) {
610
      case 1:
611
        *byte = package.evnt0;
612
        p.ctrl.dlc += expected_bytes;
613
        break;
614
      case 2:
615
        *byte++ = package.evnt0;
616
        *byte = package.evnt1;
617
        p.ctrl.dlc += expected_bytes;
618
        break;
619
      case 3:
620
        *byte++ = package.evnt0;
621
        *byte++ = package.evnt1;
622
        *byte = package.evnt2;
623
        p.ctrl.dlc += expected_bytes;
624
        break;
625
      default:
626
        return -4; // wrong datas
627
    }
628
    p.id = header.id;
629
    while( (error = MIOS32_CAN_MIDI_PacketTransmit_NonBlocking(p)) == -2);
630
#if defined(MIOS32_CAN_MIDI_VERBOSE_LEVEL)
631
    if(can_midi_verbose>=2){DEBUG_MSG("[MIOS32_CAN_MIDI_PacketSend] type:0x%02x, cable:%d, ide:%d, dlc:%d, package:0x%08x\n", header.type, header.cable, header.is_extended, p.ctrl.dlc, package.ALL);}
632
#endif
633
    return error;
634
  }
635
  return error;
636
 
637
#endif
638
}
639
 
640
/////////////////////////////////////////////////////////////////////////////
641
//! This function formats and transfers a new MCAN packet to the selected MCAN port
642
//! (blocking function)
643
//! \param[in] header MCAN Extra Infos
644
//! \param[in] package MIDI package
645
//! \return 0: no error
646
//! \return -1: CAN_MIDI device not available
647
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
648
/////////////////////////////////////////////////////////////////////////////
2657 Antichambr 649
s32 MIOS32_CAN_MIDI_PacketSend(mios32_mcan_header_t header, mios32_midi_package_t package)
2646 Antichambr 650
{
651
  s32 error;
652
  //DEBUG_MSG("[MIOS32_CAN_MIDI_PackageSend] 0x%08x\n", package.ALL);
653
 
654
  while( (error=MIOS32_CAN_MIDI_PacketSend_NonBlocking(header, package)) == -2);
655
 
656
  return error;
657
}
658
 
659
/////////////////////////////////////////////////////////////////////////////
660
//! This function sends a new MIDI package to the selected MCAN port
661
//! \param[in] package MIDI package
662
//! \return 0: no error
663
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
664
/////////////////////////////////////////////////////////////////////////////
665
s32 MIOS32_CAN_MIDI_PackageSend_NonBlocking(mios32_midi_package_t package)
666
{
667
  s32 error;
668
 
2657 Antichambr 669
  mios32_mcan_header_t header;
2646 Antichambr 670
  MIOS32_CAN_MIDI_DefaultHeaderInit(&header);
671
  header.cable = package.cable;
672
  header.type = package.type;
673
  error = MIOS32_CAN_MIDI_PacketSend_NonBlocking(header, package);
674
 
675
  return error;
676
}
677
 
678
 
679
/////////////////////////////////////////////////////////////////////////////
680
//! This function sends a new MIDI package to the selected CAN_MIDI port
681
//! (blocking function)
682
//! \param[in] package MIDI package
683
//! \return 0: no error
684
//! \return -1: CAN_MIDI device not available
685
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
686
/////////////////////////////////////////////////////////////////////////////
687
s32 MIOS32_CAN_MIDI_PackageSend(mios32_midi_package_t package)
688
{
689
  s32 error;
690
 
691
  while( (error=MIOS32_CAN_MIDI_PackageSend_NonBlocking(package)) == -2);
692
 
693
  return error;
694
}
695
 
696
/////////////////////////////////////////////////////////////////////////////
697
//! This function repacks a Sysex MIDI Package to a MCAN Sysex Packet
698
//! It groups the 3 bytes packages in 8 bytes packet(s) and send it to the can back to back
699
//! (blocking function)
700
//! \param[in] header MCAN Extra Infos
701
//! \param[in] package MIDI package
702
//! \return 0: no error
703
//! \return -1: CAN_MIDI device not available
704
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
705
/////////////////////////////////////////////////////////////////////////////
2657 Antichambr 706
s32 MIOS32_CAN_MIDI_SysexRepackSend(mios32_mcan_header_t header, mios32_midi_package_t package)
2646 Antichambr 707
{
708
#if MIOS32_CAN_NUM == 0
709
  return -1; // all CANs explicitely disabled
710
#else
711
 
712
  // exit if MCANx port not available
713
  if( !MIOS32_CAN_MIDI_CheckAvailable(header.cable) )
714
    return -1;
715
 
716
  u8 i;
717
  s32 error = 0;
718
 
719
  sysex_repack_rec_t *rpk = &sysex_repack[header.cable];// simplify addressing of sysex record
720
 
721
  // incoming MIDI package timed out (incomplete package received)
722
  if( rpk->stat.waiting && rpk->timeout_ctr > 1000 ) { // 1000 mS = 1 second
723
    // stop waiting
724
    MIOS32_CAN_MIDI_SysexRepackReset(rpk);
725
    // notify that incomplete package has been received
726
    return error;
727
  }
728
 
729
  switch (header.type) {
730
 
731
    case 4: // Start/Cont
732
      if(package.evnt0 == 0xf0){
733
        if(rpk->stat.waiting!=0)return error;
734
        rpk->ctr = 0; // Re-init byte and packet counters on 0xf0
735
        rpk->packet = 0;
736
        rpk->ext_id = header.ext_id & MIOS32_CAN_MIDI_ID_MASK;
737
        // On extended frame adds the src/dst ports infos
738
#if defined(MIOS32_CAN_MIDI_ENHANCED)
739
        if(header.is_extended){
740
          rpk->buffer[rpk->ctr++] = header.src_port;
741
          rpk->buffer[rpk->ctr++] = header.dst_port;
742
        }
743
#endif
744
        rpk->stat.waiting = 1;
745
      }
746
      if(rpk->stat.waiting==0)return error;
747
      if(rpk->ext_id != (header.ext_id & MIOS32_CAN_MIDI_ID_MASK))return error;
748
      rpk->buffer[rpk->ctr++] = package.evnt0;
749
      rpk->buffer[rpk->ctr++] = package.evnt1;
750
      rpk->buffer[rpk->ctr++] = package.evnt2;
751
      rpk->timeout_ctr = 0;
752
      break;
753
    case 7: // Ends with three bytes
754
      if(rpk->stat.waiting==0)return error;
755
      if(rpk->ext_id != (header.ext_id & MIOS32_CAN_MIDI_ID_MASK))return error;
756
      rpk->buffer[rpk->ctr++] = package.evnt0;
757
      rpk->buffer[rpk->ctr++] = package.evnt1;
758
      rpk->buffer[rpk->ctr++] = package.evnt2;
759
      rpk->stat.ending = 1;
760
      break;
761
    case 6: // Ends with two bytes
762
      if(rpk->stat.waiting==0)return error;
763
      if(rpk->ext_id != (header.ext_id & MIOS32_CAN_MIDI_ID_MASK))return error;
764
      rpk->buffer[rpk->ctr++] = package.evnt0;
765
      rpk->buffer[rpk->ctr++] = package.evnt1;
766
      rpk->stat.ending = 1;
767
      break;
768
    case 5: // Ends with a single byte
769
      if(rpk->stat.waiting==0)return error;
770
      if(rpk->ext_id != (header.ext_id & MIOS32_CAN_MIDI_ID_MASK))return error;
771
      rpk->buffer[rpk->ctr++] = package.evnt0;
772
      rpk->stat.ending = 1;
773
      break;
774
    default:
775
      break;
776
  }
777
 
778
  if(rpk->ctr >= 8){ // a full packet is ready
779
    if (rpk->packet == 0)header.type = 0x4;  // =>Start
780
    else header.type = 0x6;  // =>Cont
2657 Antichambr 781
    mios32_mcan_packet_t p;
2646 Antichambr 782
    // copy id
783
    p.id = header.id;
784
    // dlc
785
    p.ctrl.dlc = 8;
786
    for(i=0;i<8;i++)p.data.bytes[i] = rpk->buffer[i]; // Copy to packet
787
    while( (error = MIOS32_CAN_MIDI_PacketTransmit_NonBlocking(p)) == -2);
788
    rpk->packet++;
789
    rpk->ctr %= 8; // removes sent packet from counter
790
    // shift down the remaining bytes
791
    for(i=0;i<rpk->ctr;i++)rpk->buffer[i] = rpk->buffer[i+8];
792
#if defined(MIOS32_CAN_MIDI_VERBOSE_LEVEL)
793
    if(can_midi_verbose>=2){DEBUG_MSG("[MIOS32_CAN_MIDI_SysexRepackSend] type:0x%02x, cable:%d, ide:%d, dlc:%d\n", header.type, header.cable, header.is_extended, p.ctrl.dlc);}
794
#endif
795
  }
796
  if(rpk->stat.ending == 1){ // this is last packet
797
    if (rpk->packet == 0)header.type = 0x4;  // =>Start(special case only one packet stream)
798
    else header.type = 0x7;  // =>End
2657 Antichambr 799
    mios32_mcan_packet_t p;
2646 Antichambr 800
    // copy id
801
    p.id = header.id;
802
    // dlc
803
    p.ctrl.dlc = rpk->ctr;
804
    for(i=0;i<rpk->ctr;i++)p.data.bytes[i] = rpk->buffer[i]; // Copy to packet
805
    while( (error = MIOS32_CAN_MIDI_PacketTransmit_NonBlocking(p)) == -2);
806
#if defined(MIOS32_CAN_MIDI_VERBOSE_LEVEL)
807
    if(can_midi_verbose>=2){DEBUG_MSG("[MIOS32_CAN_MIDI_SysexRepackSend] type:0x%02x, cable:%d, ide:%d, dlc:%d\n", header.type, header.cable, header.is_extended, p.ctrl.dlc);}
808
#endif
809
    // repack reset
810
    MIOS32_CAN_MIDI_SysexRepackReset(rpk);
811
  }
812
  return error;
813
 
814
#endif
815
}
816
 
817
 
818
/////////////////////////////////////////////////////////////////////////////
819
//! This function sends a Sysex Stream MIDI to the selected MCAN port
820
//! It divides the stream in 8 bytes packet(s) and send it to the can back to back
821
//! \param[in] header MCAN Extra Infos
822
//! \param[in] stream
823
//! \param[in] size of the stream
824
//! \return 0: no error
825
//! \return -1: CAN_MIDI device not available
826
/////////////////////////////////////////////////////////////////////////////
2657 Antichambr 827
s32 MIOS32_CAN_MIDI_SysexSend_NonBlocking(mios32_mcan_header_t header, u8 *stream, u16 size)
2646 Antichambr 828
{
829
#if MIOS32_CAN_NUM == 0
830
  return -1; // all CANs explicitely disabled
831
#else
832
  // exit if MCANx port not available
833
  if( !MIOS32_CAN_MIDI_CheckAvailable(header.cable) )
834
    return -3;
835
  // no bytes to send -> no error
836
  if( !size )
837
    return 0;
838
 
839
  // Prepare the Packet
840
  s32 error;
2657 Antichambr 841
  mios32_mcan_packet_t p;
2646 Antichambr 842
  p.ctrl.ALL = 0;
843
  p.data.data_l = 0;
844
  p.data.data_h = 0;
845
 
846
  // On extended frame adds the src/dst ports
847
  // infos at start of first packet.
848
  if(header.is_extended){
849
    size += 2;
850
  }
851
 
852
  // Calc packet number and last packet DLC
853
  u16 packet_num;
854
  u8 i, j, last_dlc;
855
  packet_num = (u16)(size >> 3);
856
  last_dlc = (u8)(size % 8);
857
  if(last_dlc != 0)packet_num++;
858
 
859
  u8* stream_ptr = &stream[0];
860
  // loops packets
861
  for (i=0; i<packet_num; i++) {
862
    u8* byte = &p.data.bytes[0];
863
    // Set DLC and type depending on packet
864
    if(i == 0){    // Start
865
      // On extended frame adds the src/dst ports infos
866
      header.type = 0x4;  // Start Flag if one unique packet(<= 8 bytes in stream)
867
      if(packet_num == 1)p.ctrl.dlc = last_dlc;
868
      else p.ctrl.dlc = 8;
869
#if defined(MIOS32_CAN_MIDI_ENHANCED)
870
      if(header.is_extended){
871
        *byte++ = header.dst_port;
872
        *byte++ = header.src_port;
873
        for (j=0; j<(p.ctrl.dlc-2); j++)*byte++ = *stream_ptr++;
874
      }else{
875
        for (j=0; j<p.ctrl.dlc; j++)*byte++ = *stream_ptr++;
876
      }
877
#else
878
      for (j=0; j<p.ctrl.dlc; j++)*byte++ = *stream_ptr++;
879
#endif
880
    }else if(i == (packet_num-1)){   //last packet
881
      header.type = 0x7;  // End
882
      p.ctrl.dlc = last_dlc;
883
      for (j=0; j<p.ctrl.dlc; j++)*byte++ = *stream_ptr++;
884
    }else{  //others packets
885
      header.type = 0x6;  // Cont
886
      p.ctrl.dlc = 8;
887
      for (j=0; j<8; j++)*byte++ = *stream_ptr++;
888
    }
889
#if defined(MIOS32_CAN_MIDI_VERBOSE_LEVEL)
890
    if(can_midi_verbose>=2){DEBUG_MSG("[MIOS32_CAN_MIDI_SysexSend] type:0x%02x, cable:%d, ide:%d, dlc:%d\n", header.type, header.cable, header.is_extended, p.ctrl.dlc);}
891
#endif
892
    p.id = header.id;
893
    while( (error = MIOS32_CAN_MIDI_PacketTransmit_NonBlocking(p)) == -2);
894
    if(error <0 ){
895
      // it must stop cause it can not retry
896
      return error;
897
    }
898
  }
899
  return 0;
900
#endif
901
}
902
 
903
/////////////////////////////////////////////////////////////////////////////
904
//! This function sends a Sysex Stream MIDI to the selected CAN_MIDI port
905
//! It divides the stream in 8 bytes packet(s) and send it to the can back to back
906
//! (blocking function)
907
//! \param[in] can_port CAN_MIDI module number (0..1)
908
//! \param[in] package MIDI package
909
//! \return 0: no error
910
//! \return -1: CAN_MIDI device not available
911
/////////////////////////////////////////////////////////////////////////////
2657 Antichambr 912
s32 MIOS32_CAN_MIDI_SysexSend(mios32_mcan_header_t header, u8 *stream, u16 size)
2646 Antichambr 913
{
914
#if MIOS32_CAN_NUM == 0
915
  return -1; // all CANs explicitely disabled - accordingly no package in buffer
916
#else
917
  s32 error;
918
 
919
  while( (error=MIOS32_CAN_MIDI_SysexSend_NonBlocking(header, stream, size)) == -2);
920
 
921
  return error;
922
#endif
923
}
924
 
925
 
926
/////////////////////////////////////////////////////////////////////////////
927
//! Installs an optional SysEx callback which is called by
928
//! MIOS32_MIDI_Receive_Handler() to simplify the parsing of SysEx streams.
929
//!
930
//! Without this callback (or with MIOS32_MIDI_SysExCallback_Init(NULL)),
931
//! SysEx messages are only forwarded to APP_MIDI_NotifyPackage() in chunks of
932
//! 1, 2 or 3 bytes, tagged with midi_package.type == 0x4..0x7 or 0xf
933
//!
934
//! In this case, the application has to take care for different transmission
935
//! approaches which are under control of the package sender. E.g., while Windows
936
//! uses Package Type 4..7 to transmit a SysEx stream, PortMIDI under MacOS sends
937
//! a mix of 0xf (single byte) and 0x4 (continued 3-byte) packages instead.
938
//!
939
//! By using the SysEx callback, the type of package doesn't play a role anymore,
940
//! instead the application can parse a serial stream.
941
//!
942
//! MIOS32 ensures, that realtime events (0xf8..0xff) are still forwarded to
943
//! APP_MIDI_NotifyPackage(), regardless if they are transmitted in a package
944
//! type 0x5 or 0xf, so that the SysEx parser doesn't need to filter out such
945
//! events, which could otherwise appear inside a SysEx stream.
946
//!
947
//! \param[in] *callback_sysex pointer to callback function:<BR>
948
//! \code
949
//!    s32 callback_sysex(mios32_midi_port_t port, u8 sysex_byte)
950
//!    {
951
//!       //
952
//!       // .. parse stream
953
//!       //
954
//!
955
//!       return 1; // don't forward package to APP_MIDI_NotifyPackage()
956
//!    }
957
//! \endcode
958
//! If the function returns 0, SysEx bytes will be forwarded to APP_MIDI_NotifyPackage() as well.
959
//! With return value != 0, APP_MIDI_NotifyPackage() won't get the already processed package.
960
//! \return < 0 on errors
961
/////////////////////////////////////////////////////////////////////////////
2657 Antichambr 962
s32 MIOS32_CAN_MIDI_SysExStreamCallback_Init(s32 (*callback_sysex_stream)(mios32_mcan_header_t header, u8* stream, u16 size))
2646 Antichambr 963
{
964
#if MIOS32_CAN_NUM == 0
965
  return -1; // all CANs explicitely disabled - accordingly no package in buffer
966
#else
967
  sysex_stream_callback_func = callback_sysex_stream;
968
 
969
  return 0; // no error
970
#endif
971
}
972
 
973
//////////////////////////////////////////////////////////////////////////
974
//! Installs an optional Direct Midi package Callback callback
975
//! If the function returns 0, SysEx bytes will be forwarded to APP_MIDI_NotifyPackage() as well.
976
//! With return value != 0, APP_MIDI_NotifyPackage() won't get the already processed package.
977
//! \return < 0 on errors
978
/////////////////////////////////////////////////////////////////////////////
2657 Antichambr 979
s32 MIOS32_CAN_MIDI_PackageCallback_Init(s32 (*direct_package_callback)(mios32_mcan_header_t header, mios32_midi_package_t package))
2646 Antichambr 980
{
981
#if MIOS32_CAN_NUM == 0
982
  return -1; // all CANs explicitely disabled - accordingly no package in buffer
983
#else
984
  direct_package_callback_func = direct_package_callback;
985
 
986
  return 0; // no error
987
#endif
988
}
989
 
990
/////////////////////////////////////////////////////////////////////////////
991
//
992
/////////////////////////////////////////////////////////////////////////////
993
static s32 MIOS32_CAN_MIDI_SysexUnPack(u8 cable, mios32_midi_package_t *package)
994
{
995
  int i;
996
  // midi repack from sysex stream
997
  sysex_unpack_rec_t *upk = &sysex_unpack[cable];
998
 
999
  if(upk->stat.ending == 1 && upk->ctr<=3){
1000
    switch(upk->ctr){
1001
      case 3:
1002
        package->type = 0x7; // F: tree bytes
1003
        package->cable = cable;
1004
        package->evnt0 = upk->buffer[0];
1005
        package->evnt1 = upk->buffer[1];
1006
        package->evnt2 = upk->buffer[2];
1007
        break;
1008
      case 2:
1009
        package->type = 0x6; // F: two bytes
1010
        package->cable = cable;
1011
        package->evnt0 = upk->buffer[0];
1012
        package->evnt1 = upk->buffer[1];
1013
        break;
1014
      case 1:
1015
        package->type = 0x5; // F: single byte
1016
        package->cable = cable;
1017
        package->evnt0 = upk->buffer[0];
1018
        break;
1019
      default:
1020
        break;
1021
    }
1022
    // toDo package callback
1023
    MIOS32_CAN_MIDI_SysexUnpackReset(upk);
1024
    return 1; //last package ready
1025
  }else  if(upk->ctr>=3){
1026
    package->type = 0x4; // F: single byte
1027
    package->cable = cable;
1028
    package->evnt0 = upk->buffer[0];
1029
    package->evnt1 = upk->buffer[1];
1030
    package->evnt2 = upk->buffer[2];
1031
    upk->ctr -=3;
1032
    // shift down the remaining bytes
1033
    for(i=0;i<upk->ctr;i++)upk->buffer[i] = upk->buffer[i+3];
1034
    return 1;
1035
  }else return 0;
1036
}
1037
 
1038
 
1039
/////////////////////////////////////////////////////////////////////////////
1040
//! This function checks for a new package
1041
//! \param[in] can_port CAN_MIDI module number (0..2)
1042
//! \param[out] package pointer to MIDI package (received package will be put into the given variable
1043
//! \return 0: no error
1044
//! \return -1: no package in buffer
1045
//! \return -10: incoming MIDI package timed out (incomplete package received)
1046
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_MIDI layer functions
1047
/////////////////////////////////////////////////////////////////////////////
1048
s32 MIOS32_CAN_MIDI_PackageReceive(mios32_midi_package_t *package)
1049
{
1050
#if MIOS32_CAN_NUM == 0
1051
  return -1; // all CANs explicitely disabled - accordingly no package in buffer
1052
#else
1053
 
1054
  int i;
1055
  s32 status = 0;
1056
  // clear MIDI package
1057
  package->ALL = 0;
1058
 
1059
  // Checks for stream repack first.
1060
  for (i=0; i<MIOS32_CAN_MIDI_NUM_PORTS; i++) {
1061
    // incoming MIDI package timed out (incomplete package received)
1062
    if( sysex_unpack[i].stat.waiting && sysex_unpack[i].timeout_ctr > 1000 ) { // 1000 mS = 1 second
1063
      // stop waiting, reset
1064
      MIOS32_CAN_MIDI_SysexUnpackReset(&sysex_unpack[i]);
1065
    }
1066
    // there's some
1067
    if(sysex_unpack[i].stat.ready == 1)
1068
      status = MIOS32_CAN_MIDI_SysexUnPack(i, package);
1069
    if(status == 1)return status;
1070
  }
1071
 
2657 Antichambr 1072
  mios32_mcan_packet_t p;
2646 Antichambr 1073
  // Something in the buffer?
1074
  if(MIOS32_CAN_RxBufferGet(0, &p.packet) >= 0) {
1075
    // usable structure
2657 Antichambr 1076
    mios32_mcan_header_t header;
2646 Antichambr 1077
    header.id = p.id;
1078
    // exit if CAN port not available
1079
    if( !MIOS32_CAN_MIDI_CheckAvailable(header.cable) )
1080
      return 0;
1081
//    //test
1082
//#if defined(MIOS32_CAN_MIDI_VERBOSE_LEVEL)
1083
//    if(can_midi_verbose>=3)DEBUG_MSG("[MIOS32_CAN_MIDI_PackageReceive] 0x%08x 0x%08x\n", header.ext_id, header.ext_id & MIOS32_CAN_MIDI_ID_MASK);
1084
//#endif
1085
    if(header.type == 0x4 || header.type == 0x6 || header.type == 0x7){
1086
      // simplify addressing of sysex record
1087
      sysex_unpack_rec_t *upk = &sysex_unpack[header.cable];
1088
 
1089
#if defined(MIOS32_CAN_MIDI_VERBOSE_LEVEL)
1090
      if(can_midi_verbose>=2){DEBUG_MSG("[MIOS32_CAN_MIDI_PackageReceive] type:0x%02x, cable:%d, ide:%d, dlc:%d, data: 0x%08x%08x\n", header.type, header.cable, header.is_extended, p.ctrl.dlc, p.data.data_h, p.data.data_l);}
1091
#endif
1092
      status = 0;
1093
      switch (header.type) {
1094
        case 0x4:
1095
          // if busy filters new sysex message
1096
          if(upk->stat.waiting)break; // not forwarded
1097
          // store current stream header
1098
          upk->ext_id = header.ext_id & MIOS32_CAN_MIDI_ID_MASK;   // Mask removes type field
1099
          // basic/enhanced?
1100
          if(header.is_extended == 1){
1101
#if defined(MIOS32_CAN_MIDI_ENHANCED)
1102
            // breaks if third byte in data is not SOX
1103
            if(p.data.bytes[2] != 0xf0)break;
1104
            // copy ports from the two first bytes of data
1105
            upk->ports = p.data.data[0];
1106
            // because of precedent lines stream counter is dlc -2
1107
            upk->ctr = p.ctrl.dlc -2;
1108
            // copy data bytes
1109
            for (i=0; i<upk->ctr; i++)upk->buffer[i] = p.data.bytes[i+2];
1110
#else
1111
            break;
1112
#endif
1113
          }else{
1114
            // breaks if first byte in data is not SOX
1115
            if(p.data.bytes[0] != 0xf0)break;
1116
            // stream counter is dlc
1117
            upk->ctr = p.ctrl.dlc;
1118
            for (i=0; i<upk->ctr; i++)upk->buffer[i] = p.data.bytes[i];
1119
          }
1120
          // Ends if last byte is EOX
1121
          if(p.data.bytes[p.ctrl.dlc-1] == 0xf7)upk->stat.ending = 1; // last more sysex packet-
1122
          else upk->stat.waiting = 1; // we are waiting for more sysex packet
1123
          // reset timeout
1124
          upk->timeout_ctr = 0;
1125
#if !defined(MIOS32_CAN_MIDI_SYSEX_STREAM_FIRST)
1126
          upk->stat.ready = 1;
1127
          status = MIOS32_CAN_MIDI_SysexUnPack(header.cable, package);
1128
#endif
1129
          break;
1130
        case 0x6 ... 0x7:
1131
          if(!upk->stat.waiting)break; // not forwarded
1132
          // compare headers, breaks if no match with stream packet
1133
          if(upk->ext_id != (header.ext_id & MIOS32_CAN_MIDI_ID_MASK))break; // not forwarded
1134
          // copy data bytes
1135
          for (i=0; i<p.ctrl.dlc; i++)
1136
            upk->buffer[upk->ctr+i] = p.data.bytes[i];
1137
          // adds dlc to stream counter
1138
          upk->ctr += p.ctrl.dlc;
1139
          if(header.type == 0x7)upk->stat.ending = 1; // last more sysex packet-
1140
          else upk->stat.waiting = 1; // we are waiting for more sysex packet
1141
          // reset timeout
1142
          upk->timeout_ctr = 0;
1143
#if !defined(MIOS32_CAN_MIDI_SYSEX_STREAM_FIRST)
1144
          upk->stat.ready = 1;
1145
          status = MIOS32_CAN_MIDI_SysexUnPack(header.cable, package);
1146
#endif
1147
          break;
1148
        default:
1149
          break;
1150
      }
1151
 
1152
      if(upk->stat.ending){ //
1153
        //upk->ending = 0;
1154
        upk->stat.waiting = 0;
1155
#if defined(MIOS32_CAN_MIDI_SYSEX_STREAM_FIRST)
1156
        // Sysex stream callback if callback returns 0 then no midi repack
1157
        s32 callback_status = 0;
1158
        if( sysex_stream_callback_func != NULL ){
1159
          header.ext_id = upk->ext_id;
1160
          header.type = 0x4;
1161
          header.ports = upk->ports;
1162
          callback_status = sysex_stream_callback_func(header, upk->buffer, upk->ctr); // -> forwarded as SysEx stream
1163
        }
1164
        if(!callback_status){
1165
          // start packaging
1166
          upk->stat.ready = 1;
1167
          return MIOS32_CAN_MIDI_SysexUnPack(header.cable, package);
1168
        }else{
1169
          MIOS32_CAN_MIDI_SysexUnpackReset(upk);
1170
          return 0; // stream forwarded but no midi repack
1171
        }
1172
#else
1173
        return status; //last package ready
1174
#endif
1175
      }else{
1176
        return status;  // no midi package
1177
      }
1178
 
1179
    } else { // Others messages than Sysex
1180
      // prepare header
2657 Antichambr 1181
      mios32_mcan_header_t header;
2646 Antichambr 1182
      header.id = p.id;
1183
      // data pointer
1184
      u8* byte = &p.data.bytes[0];
1185
      // is enhanced packet
1186
      if(header.is_extended){
1187
#if defined(MIOS32_CAN_MIDI_ENHANCED)
1188
        header.src_port = *byte++;
1189
        header.src_port = *byte++;
1190
        p.ctrl.dlc -=2;
1191
#else
1192
        return 0;  // not forwarded
1193
#endif
1194
      }
1195
      u8 expected_bytes = mios32_midi_pcktype_num_bytes[header.type];
1196
      if( expected_bytes == p.ctrl.dlc) { // Packet is single byte cmd, expected_bytes=0 and DLC=0
1197
 
1198
        package->type = header.type;
1199
        package->cable = header.cable;
1200
        for (i=0; i<expected_bytes; i++)package->bytes[i+1] = *byte++;
1201
#if defined(MIOS32_CAN_MIDI_VERBOSE_LEVEL)
1202
        if(can_midi_verbose>=2){DEBUG_MSG("[MIOS32_CAN_MIDI_PackageReceive] type:0x%02x, cable:%d, ide:%d, dlc:%d, package:0x%08x\n", header.type, header.cable, header.is_extended, p.ctrl.dlc, package->ALL);}
1203
#endif
1204
        if(header.type == 0x0){
1205
          return 0;
1206
        }else if(header.type == 0x1){ // Local command filter
1207
          MIOS32_CAN_MIDI_LocalCmdParser(header, package);
1208
          return 0;
1209
        }else{
1210
          s32 callback_status = 0;
1211
          if( direct_package_callback_func != NULL ){
1212
            mios32_midi_package_t direct_package = *package;
1213
            callback_status = direct_package_callback_func(header, direct_package); // -> forwarded as MCAN Midi Package
1214
          }
1215
          if(!callback_status)return 1; // midi package ok
1216
          else return 0;  // not forwarded
1217
        }
1218
      }else return 0;  // no midi package
1219
    }
1220
  }else return -2;
1221
 
1222
#endif
1223
}
1224
 
1225
/////////////////////////////////////////////////////////////////////////////
1226
//
1227
/////////////////////////////////////////////////////////////////////////////
2657 Antichambr 1228
u32 MIOS32_CAN_MIDI_DefaultHeaderInit(mios32_mcan_header_t* header)
2646 Antichambr 1229
{
1230
#if MIOS32_CAN_NUM == 0
1231
  return -1; // all CANs explicitely disabled - accordingly no package in buffer
1232
#else
1233
  // reset
1234
  header->ext_id = 0;
1235
  header->ports = 0;
1236
 
1237
  if(mios32_mcan_enhanced > 0)header->is_extended = 1;else header->is_extended = 0;
1238
  //header->is_extended = 0;
1239
  header->src_node  = mios32_mcan_id;
1240
  header->src_port  = MCAN0;
1241
  header->dst_node  = MIOS32_CAN_MIDI_DEF_DEST_ID;
1242
  header->dst_port  = MCAN0;
1243
  header->app_type  = MIOS32_CAN_MIDI_APP_CODE;
1244
  header->vman_prio = MIOS32_CAN_MIDI_DEF_VMAN;
1245
 
1246
  return 0; // no error
1247
#endif
1248
}
1249
 
1250
//!}
1251
 
1252
#endif /* MIOS32_USE_CAN_MIDI */