Subversion Repositories svn.mios32

Rev

Rev 2399 | Rev 2432 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
944 tk 1
// $Id: seq_terminal.c 2425 2016-11-03 00:44:22Z tk $
2
/*
3
 * MIDIbox SEQ MIDI Terminal
4
 *
5
 * ==========================================================================
6
 *
7
 *  Copyright (C) 2010 Thorsten Klose (tk@midibox.org)
8
 *  Licensed for personal non-commercial use only.
9
 *  All other rights reserved.
10
 *
11
 * ==========================================================================
12
 */
13
 
14
/////////////////////////////////////////////////////////////////////////////
15
// Include files
16
/////////////////////////////////////////////////////////////////////////////
17
 
18
#include <mios32.h>
19
#include <string.h>
20
 
21
#include <seq_midi_out.h>
2263 tk 22
#include <blm_scalar_master.h>
974 tk 23
#include <ff.h>
944 tk 24
 
1140 tk 25
#include <aout.h>
1633 tk 26
#include <app_lcd.h>
1140 tk 27
 
944 tk 28
#include "tasks.h"
29
 
30
#include "app.h"
31
#include "seq_terminal.h"
32
 
33
 
34
#include "seq_core.h"
35
#include "seq_cc.h"
36
#include "seq_layer.h"
37
#include "seq_par.h"
38
#include "seq_trg.h"
1754 tk 39
#include "seq_record.h"
944 tk 40
#include "seq_midi_port.h"
1390 tk 41
#include "seq_midi_router.h"
42
#include "seq_blm.h"
1316 tk 43
#include "seq_song.h"
44
#include "seq_mixer.h"
1864 tk 45
#include "seq_hwcfg.h"
1865 tk 46
#include "seq_tpd.h"
2130 tk 47
#include "seq_lcd_logo.h"
1316 tk 48
 
1261 tk 49
#include "file.h"
944 tk 50
#include "seq_file.h"
51
#include "seq_file_b.h"
52
#include "seq_file_s.h"
53
#include "seq_file_m.h"
54
#include "seq_file_g.h"
55
#include "seq_file_c.h"
1117 tk 56
#include "seq_file_t.h"
1052 tk 57
#include "seq_file_gc.h"
1203 tk 58
#include "seq_file_bm.h"
944 tk 59
#include "seq_file_hw.h"
60
 
1068 tk 61
#include "seq_ui.h"
62
 
944 tk 63
#include "seq_statistics.h"
64
 
1020 tk 65
#if !defined(MIOS32_FAMILY_EMULATION)
1387 tk 66
#include "uip_terminal.h"
1020 tk 67
#endif
944 tk 68
 
1019 tk 69
 
944 tk 70
/////////////////////////////////////////////////////////////////////////////
71
// Local defines
72
/////////////////////////////////////////////////////////////////////////////
73
 
1543 tk 74
#define STRING_MAX 100 // recommended size for file transfers via FILE_BrowserHandler()
944 tk 75
 
76
 
77
/////////////////////////////////////////////////////////////////////////////
78
// Local variables
79
/////////////////////////////////////////////////////////////////////////////
80
 
1117 tk 81
static char line_buffer[STRING_MAX];
944 tk 82
static u16 line_ix;
83
 
2030 tk 84
typedef enum {
85
  UPLOADING_FILE_NONE,
86
  UPLOADING_FILE_HW,
87
  UPLOADING_FILE_C,
88
  UPLOADING_FILE_GC,
89
  UPLOADING_FILE_G,
90
  UPLOADING_FILE_BM,
91
} uploading_file_t;
92
 
93
static uploading_file_t uploading_file;
94
 
944 tk 95
/////////////////////////////////////////////////////////////////////////////
1543 tk 96
// Local prototypes
97
/////////////////////////////////////////////////////////////////////////////
98
 
99
static s32 TERMINAL_ParseFilebrowser(mios32_midi_port_t port, char byte);
100
 
1864 tk 101
static s32 TERMINAL_BrowserUploadCallback(char *filename);
1543 tk 102
 
1864 tk 103
 
1543 tk 104
/////////////////////////////////////////////////////////////////////////////
944 tk 105
// Initialisation
106
/////////////////////////////////////////////////////////////////////////////
107
s32 SEQ_TERMINAL_Init(u32 mode)
108
{
1543 tk 109
  // install the callback function which is called on incoming characters from MIOS Terminal
944 tk 110
  MIOS32_MIDI_DebugCommandCallback_Init(SEQ_TERMINAL_Parse);
111
 
1543 tk 112
  // install the callback function which is called on incoming characters from MIOS Filebrowser
113
  MIOS32_MIDI_FilebrowserCommandCallback_Init(TERMINAL_ParseFilebrowser);
114
 
944 tk 115
  // clear line buffer
116
  line_buffer[0] = 0;
117
  line_ix = 0;
118
 
2030 tk 119
  // for file autoload
120
  uploading_file = 0;
1864 tk 121
 
944 tk 122
  return 0; // no error
123
}
124
 
125
 
126
/////////////////////////////////////////////////////////////////////////////
127
// help function which parses a decimal or hex value
128
// returns >= 0 if value is valid
129
// returns -1 if value is invalid
130
/////////////////////////////////////////////////////////////////////////////
131
static s32 get_dec(char *word)
132
{
133
  if( word == NULL )
134
    return -1;
135
 
136
  char *next;
137
  long l = strtol(word, &next, 0);
138
 
139
  if( word == next )
140
    return -1;
141
 
142
  return l; // value is valid
143
}
144
 
145
 
146
/////////////////////////////////////////////////////////////////////////////
1390 tk 147
// help function which parses for on or off
148
// returns 0 if 'off', 1 if 'on', -1 if invalid
149
/////////////////////////////////////////////////////////////////////////////
150
static s32 get_on_off(char *word)
151
{
152
  if( strcmp(word, "on") == 0 )
153
    return 1;
154
 
155
  if( strcmp(word, "off") == 0 )
156
    return 0;
157
 
158
  return -1;
159
}
160
 
161
 
162
/////////////////////////////////////////////////////////////////////////////
944 tk 163
// Parser
164
/////////////////////////////////////////////////////////////////////////////
1387 tk 165
s32 SEQ_TERMINAL_Parse(mios32_midi_port_t port, char byte)
944 tk 166
{
959 tk 167
  // temporary change debug port (will be restored at the end of this function)
168
  mios32_midi_port_t prev_debug_port = MIOS32_MIDI_DebugPortGet();
169
  MIOS32_MIDI_DebugPortSet(port);
170
 
944 tk 171
  if( byte == '\r' ) {
172
    // ignore
173
  } else if( byte == '\n' ) {
1868 tk 174
    SEQ_TERMINAL_ParseLine(line_buffer, APP_SendDebugMessage);
1311 tk 175
    line_ix = 0;
176
    line_buffer[line_ix] = 0;
177
  } else if( line_ix < (STRING_MAX-1) ) {
178
    line_buffer[line_ix++] = byte;
179
    line_buffer[line_ix] = 0;
180
  }
944 tk 181
 
1311 tk 182
  // restore debug port
183
  MIOS32_MIDI_DebugPortSet(prev_debug_port);
1083 tk 184
 
1311 tk 185
  return 0; // no error
186
}
187
 
188
 
189
/////////////////////////////////////////////////////////////////////////////
1543 tk 190
// Parser for Filebrowser
191
/////////////////////////////////////////////////////////////////////////////
192
s32 TERMINAL_ParseFilebrowser(mios32_midi_port_t port, char byte)
193
{
194
  if( byte == '\r' ) {
195
    // ignore
196
  } else if( byte == '\n' ) {
1864 tk 197
    // for the auto-load function
198
    FILE_BrowserUploadCallback_Init(TERMINAL_BrowserUploadCallback);
199
 
1543 tk 200
    MUTEX_MIDIOUT_TAKE;
201
    MUTEX_SDCARD_TAKE;
202
    FILE_BrowserHandler(port, line_buffer);
203
    MUTEX_SDCARD_GIVE;
204
    MUTEX_MIDIOUT_GIVE;
205
    line_ix = 0;
206
    line_buffer[line_ix] = 0;
207
  } else if( line_ix < (STRING_MAX-1) ) {
208
    line_buffer[line_ix++] = byte;
209
    line_buffer[line_ix] = 0;
210
  }
211
 
212
  return 0; // no error
213
}
214
 
1864 tk 215
/////////////////////////////////////////////////////////////////////////////
216
//! For the auto-load function
217
/////////////////////////////////////////////////////////////////////////////
218
static s32 TERMINAL_BrowserUploadCallback(char *filename)
219
{
220
  if( filename ) {
221
    // check for MBSEQ_HW.V4
2030 tk 222
    uploading_file = UPLOADING_FILE_NONE;
223
    if( strcasecmp(filename, "/mbseq_hw.v4") == 0 )
224
      uploading_file = UPLOADING_FILE_HW;
2399 tk 225
    if( strcasecmp(filename, "/mbseq_hw.v4l") == 0 )
226
      uploading_file = UPLOADING_FILE_HW;
2030 tk 227
    else if( strcasestr(filename, "/mbseq_c.v4") != NULL )
228
      uploading_file = UPLOADING_FILE_C;
229
    else if( strcasecmp(filename, "/mbseq_gc.v4") == 0 )
230
      uploading_file = UPLOADING_FILE_GC;
231
    else if( strcasestr(filename, "/mbseq_g.v4") != NULL )
232
      uploading_file = UPLOADING_FILE_G;
233
    else if( strcasestr(filename, "/mbseq_bm.v4") != NULL )
234
      uploading_file = UPLOADING_FILE_BM;
1864 tk 235
  } else {
2030 tk 236
    switch( uploading_file ) {
237
 
238
    case UPLOADING_FILE_HW: {
1864 tk 239
      DEBUG_MSG("AUTOLOAD '/MBSEQ_HW.V4'\n");
240
      SEQ_HWCFG_Init(0);
241
      SEQ_FILE_HW_Init(0);
242
      SEQ_FILE_HW_Load();      
2030 tk 243
    } break;
244
 
245
    case UPLOADING_FILE_C: {
246
      DEBUG_MSG("AUTOLOAD 'MBSEQ_C.V4'\n");
247
      SEQ_FILE_C_Load(seq_file_session_name);
248
    } break;
249
 
250
    case UPLOADING_FILE_GC: {
251
      DEBUG_MSG("AUTOLOAD '/MBSEQ_GC.V4'\n");
252
      SEQ_FILE_GC_Load();
253
    } break;
254
 
255
    case UPLOADING_FILE_G: {
256
      DEBUG_MSG("AUTOLOAD 'MBSEQ_G.V4'\n");
257
      SEQ_FILE_G_Load(seq_file_session_name);
258
    } break;
259
 
260
    case UPLOADING_FILE_BM: {
261
      DEBUG_MSG("AUTOLOAD 'MBSEQ_BM.V4'\n");
262
      SEQ_FILE_BM_Load(seq_file_session_name, 1); // global
263
      SEQ_FILE_BM_Load(seq_file_session_name, 0); // session
264
    } break;
265
 
266
 
1864 tk 267
    }
268
  }
1543 tk 269
 
1864 tk 270
  return 0; // no error
271
}
272
 
1543 tk 273
/////////////////////////////////////////////////////////////////////////////
1311 tk 274
// Parser for a complete line - also used by shell.c for telnet
275
/////////////////////////////////////////////////////////////////////////////
276
s32 SEQ_TERMINAL_ParseLine(char *input, void *_output_function)
277
{
278
  void (*out)(char *format, ...) = _output_function;
279
  char *separators = " \t";
280
  char *brkt;
281
  char *parameter;
282
 
1868 tk 283
  MUTEX_MIDIOUT_TAKE;
284
 
1387 tk 285
#if !defined(MIOS32_FAMILY_EMULATION)
286
  if( UIP_TERMINAL_ParseLine(input, _output_function) >= 1 )
287
    return 0; // command parsed by UIP Terminal
288
#endif
289
 
1492 tk 290
#if !defined(MIOS32_FAMILY_EMULATION)
291
  if( AOUT_TerminalParseLine(input, _output_function) >= 1 )
292
    return 0; // command parsed
293
#endif
294
 
1633 tk 295
#ifdef MIOS32_LCD_universal
296
  if( APP_LCD_TerminalParseLine(input, _output_function) >= 1 )
297
    return 0; // command parsed
298
#endif
299
 
1868 tk 300
  MUTEX_MIDIOUT_GIVE;
301
 
1311 tk 302
  if( (parameter = strtok_r(line_buffer, separators, &brkt)) ) {
303
    if( strcmp(parameter, "help") == 0 ) {
304
      SEQ_TERMINAL_PrintHelp(out);
305
    } else if( strcmp(parameter, "system") == 0 ) {
306
      SEQ_TERMINAL_PrintSystem(out);
1653 tk 307
    } else if( strcmp(parameter, "memory") == 0 ) {
2250 tk 308
      // new: expert option (therefore not documented in help page):
309
      // "memory <from-address> <to-address> dumps any memory region (not protected against bus errors - potential hard fault!)
310
      char *arg;
311
      if( (arg = strtok_r(NULL, separators, &brkt)) ) {
312
    int begin_addr = get_dec(arg);
313
    int end_addr = -1;
314
 
315
    if( (arg = strtok_r(NULL, separators, &brkt)) ) {
316
      end_addr = get_dec(arg);
317
    }
318
 
319
    if( begin_addr == -1 || end_addr == -1 ) {
320
      out("SYNTAX: memory <begin-addr> <end-addr>");
321
    } else if( begin_addr > end_addr ) {
322
      out("ERROR: end address has to be greater equal the start address");
323
    } else {
324
      u32 size = end_addr - begin_addr;
325
      if( size > 0x10000 ) {
326
        out("ERROR: it isn't recommended to dump more than 64k at once!");
327
      } else {
328
        u8 *ptr = (u8 *)begin_addr;
329
        MIOS32_MIDI_SendDebugHexDump(ptr, size);
330
      }
331
    }
332
      } else {
333
    SEQ_TERMINAL_PrintMemoryInfo(out);
334
      }
1653 tk 335
    } else if( strcmp(parameter, "sdcard") == 0 ) {
336
      SEQ_TERMINAL_PrintSdCardInfo(out);
337
    } else if( strcmp(parameter, "sdcard_format") == 0 ) {
338
      if( !brkt || strcasecmp(brkt, "yes, I'm sure") != 0 ) {
339
    out("ATTENTION: this command will format your SD Card!!!");
340
    out("           ALL DATA WILL BE DELETED FOREVER!!!");
341
    out("           Check the current content with the 'sdcard' command");
342
    out("           Create a backup on your computer if necessary!");
343
    out("To start formatting, please enter: sdcard_format yes, I'm sure");
344
    if( brkt ) {
345
      out("('%s' wasn't the right \"password\")", brkt);
346
    }
347
      } else {
2161 tk 348
#if !defined(MIOS32_FAMILY_EMULATION)
1653 tk 349
    MUTEX_SDCARD_TAKE;
350
    out("Formatting SD Card...");
351
    FRESULT res;
352
    if( (res=f_mkfs(0,0,0)) != FR_OK ) {
353
      out("Formatting failed with error code: %d!", res);
354
    } else {
355
      out("...with success!");
356
#ifdef MBSEQV4L    
357
      out("Please upload your MBSEQ_HW.V4L file with the MIOS Filebrowser now!");
358
#else
359
      out("Please upload your MBSEQ_HW.V4 file with the MIOS Filebrowser now!");
360
#endif
361
      out("Thereafter enter 'reset' to restart the application.");
362
    }
363
    MUTEX_SDCARD_GIVE;
2161 tk 364
#else
365
    out("Not in emulation...!");
366
#endif
1653 tk 367
      }
1311 tk 368
    } else if( strcmp(parameter, "global") == 0 ) {
369
      SEQ_TERMINAL_PrintGlobalConfig(out);
370
    } else if( strcmp(parameter, "bookmarks") == 0 ) {
371
      SEQ_TERMINAL_PrintBookmarks(out);
372
    } else if( strcmp(parameter, "config") == 0 ) {
373
      SEQ_TERMINAL_PrintSessionConfig(out);
374
    } else if( strcmp(parameter, "tracks") == 0 ) {
375
      SEQ_TERMINAL_PrintTracks(out);
376
    } else if( strcmp(parameter, "track") == 0 ) {
377
      char *arg;
378
      if( (arg = strtok_r(NULL, separators, &brkt)) ) {
379
    int track = get_dec(arg);
380
    if( track < 1 || track > SEQ_CORE_NUM_TRACKS ) {
381
      out("Wrong track number %d - expected track 1..%d\n", track, SEQ_CORE_NUM_TRACKS);
1083 tk 382
    } else {
1311 tk 383
      SEQ_TERMINAL_PrintTrack(out, track-1);
1083 tk 384
    }
1311 tk 385
      } else {
1866 tk 386
    out("Please specify track, e.g. \"track 1\"");
1311 tk 387
      }
388
    } else if( strcmp(parameter, "mixer") == 0 ) {
389
      SEQ_TERMINAL_PrintCurrentMixerMap(out);
390
    } else if( strcmp(parameter, "song") == 0 ) {
391
      SEQ_TERMINAL_PrintCurrentSong(out);
392
    } else if( strcmp(parameter, "grooves") == 0 ) {
393
      SEQ_TERMINAL_PrintGrooveTemplates(out);
1320 tk 394
    } else if( strcmp(parameter, "msd") == 0 ) {
1866 tk 395
      out("Mass Storage Device Mode not supported by this application!");
1865 tk 396
    } else if( strcmp(parameter, "tpd") == 0 ) {
397
      SEQ_TPD_PrintString(brkt); // easter egg ;-)
1390 tk 398
    } else if( strcmp(parameter, "set") == 0 ) {
399
      if( (parameter = strtok_r(NULL, separators, &brkt)) ) {
400
    if( strcmp(parameter, "router") == 0 ) {
401
      char *arg;
402
      if( !(arg = strtok_r(NULL, separators, &brkt)) ) {
403
        out("Missing node number!");
404
      } else {
405
        s32 node = get_dec(arg);
406
        if( node < 1 || node > SEQ_MIDI_ROUTER_NUM_NODES ) {
407
          out("Expecting node number between 1..%d!", SEQ_MIDI_ROUTER_NUM_NODES);
408
        } else {
409
          node-=1; // user counts from 1
410
 
411
          if( !(arg = strtok_r(NULL, separators, &brkt)) ) {
412
        out("Missing input port!");
413
          } else {
414
        mios32_midi_port_t src_port = 0xff;
415
        int port_ix;
416
        for(port_ix=0; port_ix<SEQ_MIDI_PORT_InNumGet(); ++port_ix) {
417
          // terminate port name at first space
418
          char port_name[10];
419
          strcpy(port_name, SEQ_MIDI_PORT_InNameGet(port_ix));
420
          int i; for(i=0; i<strlen(port_name); ++i) if( port_name[i] == ' ' ) port_name[i] = 0;
421
 
422
          if( strcmp(arg, port_name) == 0 ) {
423
            src_port = SEQ_MIDI_PORT_InPortGet(port_ix);
424
            break;
425
          }
426
        }
427
 
428
        if( src_port >= 0xf0 ) {
429
          out("Unknown or invalid MIDI input port!");
430
        } else {
431
 
432
          char *arg_src_chn;
433
          if( !(arg_src_chn = strtok_r(NULL, separators, &brkt)) ) {
434
            out("Missing source channel, expecting off, 1..16 or all!");
435
          } else {
436
            int src_chn = -1;
437
 
438
            if( strcmp(arg_src_chn, "---") == 0 || strcmp(arg_src_chn, "off") == 0 )
439
              src_chn = 0;
1713 tk 440
            else if( strcasecmp(arg_src_chn, "all") == 0 )
1390 tk 441
              src_chn = 17;
442
            else {
443
              src_chn = get_dec(arg_src_chn);
444
              if( src_chn > 16 )
445
            src_chn = -1;
446
            }
447
 
448
            if( src_chn < 0 ) {
449
              out("Invalid source channel, expecting off, 1..16 or all!");
450
            } else {
451
 
452
              if( !(arg = strtok_r(NULL, separators, &brkt)) ) {
453
            out("Missing output port!");
454
              } else {
455
            mios32_midi_port_t dst_port = 0xff;
456
            int port_ix;
457
            for(port_ix=0; port_ix<SEQ_MIDI_PORT_OutNumGet(); ++port_ix) {
458
              // terminate port name at first space
459
              char port_name[10];
460
              strcpy(port_name, SEQ_MIDI_PORT_OutNameGet(port_ix));
461
              int i; for(i=0; i<strlen(port_name); ++i) if( port_name[i] == ' ' ) port_name[i] = 0;
462
 
463
              if( strcmp(arg, port_name) == 0 ) {
464
                dst_port = SEQ_MIDI_PORT_OutPortGet(port_ix);
465
                break;
466
              }
467
            }
468
 
469
            if( dst_port >= 0xf0 ) {
470
              out("Unknown or invalid MIDI output port!");
471
            } else {
472
 
473
              char *arg_dst_chn;
474
              if( !(arg_dst_chn = strtok_r(NULL, separators, &brkt)) ) {
475
                out("Missing destination channel, expecting off, 1..16 or all!");
476
              } else {
477
                int dst_chn = -1;
478
 
479
                if( strcmp(arg_dst_chn, "---") == 0 || strcmp(arg_dst_chn, "off") == 0 )
480
                  dst_chn = 0;
1713 tk 481
                else if( strcasecmp(arg_dst_chn, "all") == 0 )
1390 tk 482
                  dst_chn = 17;
1713 tk 483
                else if( strcasecmp(arg_dst_chn, "trk") == 0 || strcasecmp(arg_dst_chn, "track") == 0 )
484
                  dst_chn = 18;
1746 tk 485
                else if( strcasecmp(arg_dst_chn, "stk") == 0 ||
486
                     strcasecmp(arg_dst_chn, "strk") == 0 ||
487
                     strcasecmp(arg_dst_chn, "seltrk") == 0 ||
488
                     strcasecmp(arg_dst_chn, "seltrack") == 0 ||
489
                     strcasecmp(arg_dst_chn, "track") == 0 )
490
                  dst_chn = 19;
1390 tk 491
                else {
492
                  dst_chn = get_dec(arg_dst_chn);
493
                  if( dst_chn > 16 )
494
                dst_chn = -1;
495
                }
496
 
497
                if( dst_chn < 0 ) {
498
                  out("Invalid destination channel, expecting off, 1..16 or all!");
499
                } else {
500
                  //
501
                  // finally...
502
                  //
503
                  seq_midi_router_node_t *n = &seq_midi_router_node[node];
504
                  n->src_port = src_port;
505
                  n->src_chn = src_chn;
506
                  n->dst_port = dst_port;
507
                  n->dst_chn = dst_chn;
508
 
509
                  out("Changed Node %d to SRC:%s %s  DST:%s %s",
510
                  node+1,
511
                  SEQ_MIDI_PORT_InNameGet(SEQ_MIDI_PORT_InIxGet(n->src_port)),
512
                  arg_src_chn,
513
                  SEQ_MIDI_PORT_OutNameGet(SEQ_MIDI_PORT_OutIxGet(n->dst_port)),
514
                  arg_dst_chn);
515
                }
516
              }
517
            }
518
              }
519
            }
520
          }
521
        }
522
          }
523
        }
524
      }
525
    } else if( strcmp(parameter, "mclk_in") == 0 || strcmp(parameter, "mclk_out") == 0 ) {
526
      int mclk_in = strcmp(parameter, "mclk_in") == 0;
527
 
528
      char *arg;
529
      if( !(arg = strtok_r(NULL, separators, &brkt)) ) {
530
        out("Missing MIDI clock port!");
531
      } else {
532
        mios32_midi_port_t mclk_port = 0xff;
533
        int port_ix;
534
        for(port_ix=0; port_ix<SEQ_MIDI_PORT_ClkNumGet(); ++port_ix) {
535
          // terminate port name at first space
536
          char port_name[10];
537
          strcpy(port_name, SEQ_MIDI_PORT_ClkNameGet(port_ix));
538
          int i; for(i=0; i<strlen(port_name); ++i) if( port_name[i] == ' ' ) port_name[i] = 0;
539
 
540
          if( strcmp(arg, port_name) == 0 ) {
541
        mclk_port = SEQ_MIDI_PORT_ClkPortGet(port_ix);
542
        break;
543
          }
544
        }
545
 
546
        if( mclk_in && mclk_port >= 0xf0 ) {
547
          // extra: allow 'INx' as well
548
          if( strncmp(arg, "IN", 2) == 0 && arg[2] >= '1' && arg[2] <= '4' )
549
        mclk_port = UART0 + (arg[2] - '1');
550
        }
551
 
552
        if( !mclk_in && mclk_port >= 0xf0 ) {
553
          // extra: allow 'OUTx' as well
554
          if( strncmp(arg, "OUT", 3) == 0 && arg[3] >= '1' && arg[3] <= '4' )
555
        mclk_port = UART0 + (arg[3] - '1');
556
        }
557
 
558
        if( mclk_port >= 0xf0 ) {
559
          out("Unknown or invalid MIDI Clock port!");
560
        } else {
561
          int on_off = -1;
562
          char *arg_on_off;
563
          if( !(arg_on_off = strtok_r(NULL, separators, &brkt)) ||
564
          (on_off = get_on_off(arg_on_off)) < 0 ) {
565
        out("Missing 'on' or 'off' after port name!");
566
          } else {
567
        if( mclk_in ) {
568
          if( SEQ_MIDI_ROUTER_MIDIClockInSet(mclk_port, on_off) < 0 )
569
            out("Failed to set MIDI Clock port %s", arg);
570
          else
571
            out("Set MIDI Clock for IN port %s to %s\n", arg, arg_on_off);
572
        } else {
573
          if( SEQ_MIDI_ROUTER_MIDIClockOutSet(mclk_port, on_off) < 0 )
574
            out("Failed to set MIDI Clock port %s", arg);
575
          else
576
            out("Set MIDI Clock for OUT port %s to %s\n", arg, arg_on_off);
577
        }
578
          }
579
        }
580
      }
2176 tk 581
    } else if( strcmp(parameter, "din_testmode") == 0 ) {
582
          int on_off = -1;
583
          if( (parameter = strtok_r(NULL, separators, &brkt)) )
584
            on_off = get_on_off(parameter);
585
 
586
          if( on_off < 0 ) {
587
            out("Expecting 'on' or 'off'");
588
          } else {
589
            app_din_testmode = on_off;
590
            out("DIN testmode turned %s", on_off ? "on" : "off");
591
          }
1390 tk 592
    } else if( strcmp(parameter, "blm_port") == 0 ) {
593
      char *arg;
594
      if( !(arg = strtok_r(NULL, separators, &brkt)) ) {
595
        out("Please specifify BLM MIDI input port or 'off' to disable BLM!");
596
      } else {
597
        if( strcmp(arg, "off") == 0 ) {
2263 tk 598
          BLM_SCALAR_MASTER_MIDI_PortSet(0, 0x00);
1390 tk 599
          out("BLM port has been disabled!");
600
        } else {
601
          mios32_midi_port_t blm_port = 0xff;
602
          int port_ix;
603
          for(port_ix=0; port_ix<SEQ_MIDI_PORT_InNumGet(); ++port_ix) {
604
        // terminate port name at first space
605
        char port_name[10];
606
        strcpy(port_name, SEQ_MIDI_PORT_InNameGet(port_ix));
607
        int i; for(i=0; i<strlen(port_name); ++i) if( port_name[i] == ' ' ) port_name[i] = 0;
608
 
609
        if( strcmp(arg, port_name) == 0 ) {
610
          blm_port = SEQ_MIDI_PORT_InPortGet(port_ix);
611
          break;
612
        }
613
          }
614
 
615
          if( blm_port >= 0xf0 ) {
616
        out("Unknown or invalid BLM input port!");
617
          } else {
2263 tk 618
        BLM_SCALAR_MASTER_MIDI_PortSet(0, blm_port);
619
        out("BLM port set to %s", SEQ_MIDI_PORT_InNameGet(SEQ_MIDI_PORT_InIxGet(BLM_SCALAR_MASTER_MIDI_PortGet(0))));
1390 tk 620
          }
621
        }
622
      }
1754 tk 623
 
624
    } else if( strcmp(parameter, "rec_quantisation") == 0 ) {
625
      char *arg;
626
      int value;
627
      if( !(arg = strtok_r(NULL, separators, &brkt)) ) {
628
        out("Please specify quantisation between 1%%..100%% (default: 10%%, current: %d%%)\n", seq_record_quantize);
629
      } else {
630
        int len;
631
        while( (len=strlen(arg)) && arg[len-1] == '%' ) {
632
          arg[len-1] = 0;
633
        }
634
 
635
        if( (value=get_dec(arg)) < 0 || value > 100 ) {
1866 tk 636
          out("Quantisation should be between 1%%..100%%!");
1754 tk 637
        } else {
638
          seq_record_quantize = value;
639
          out("Quantisation set to %d%%\n", seq_record_quantize);
1866 tk 640
          out("Enter 'store' to save this setting on SD Card.");
1754 tk 641
        }
642
      }
1390 tk 643
    } else {
644
      out("Unknown set parameter: '%s'!", parameter);
645
    }
646
      } else {
647
    out("Missing parameter after 'set'!");
648
      }
649
    } else if( strcmp(parameter, "router") == 0 ) {
650
      SEQ_TERMINAL_PrintRouterInfo(out);
1387 tk 651
    } else if( strcmp(parameter, "play") == 0 || strcmp(parameter, "start") == 0 ) { // play or start do the same
1311 tk 652
      SEQ_UI_Button_Play(0);
1866 tk 653
      out("Sequencer started...");
1311 tk 654
    } else if( strcmp(parameter, "stop") == 0 ) {
655
      SEQ_UI_Button_Stop(0);
1866 tk 656
      out("Sequencer stopped...");
657
    } else if( strcmp(parameter, "store") == 0 || (strcmp(parameter, "save") == 0 && strlen(brkt) == 0) ) {
658
      if( seq_ui_backup_req || seq_ui_format_req ) {
659
    out("Ongoing session creation - please wait!");
660
      } else if( strlen(brkt) ) {
661
    out("ERROR: use 'save' if you want to store the session under a new name!");
1387 tk 662
      } else {
1866 tk 663
    seq_ui_saveall_req = 1;
664
    out("Storing complete session on SD Card: /SESSIONS/%s\n", seq_file_session_name);
1387 tk 665
      }
1866 tk 666
    } else if( strcmp(parameter, "new") == 0 || strcmp(parameter, "saveas") == 0 || strcmp(parameter, "save") == 0 ) {
667
      if( seq_ui_backup_req || seq_ui_format_req ) {
668
    out("Ongoing session creation - please wait!");
669
      } else {
670
    MUTEX_SDCARD_TAKE;
671
 
672
    char *session_dir = brkt;
673
    u8 new_session = strcmp(parameter, "new") == 0;
674
 
675
    if( !strlen(session_dir) ) {
676
      out("Please specifiy a session name!");
677
    } else {
678
      if( strlen(session_dir) > 8 ) {
679
        out("Session name '%s' too long, only 8 characters allowed!\n", session_dir);
680
      } else if( SEQ_FILE_IsValidSessionName(session_dir) < 1 ) {
681
        out("Session name '%s' contains invalid characters!!\n", session_dir);
682
      } else {
683
        s32 status;
684
        char path[30];
685
        sprintf(path, "%s/%s", SEQ_FILE_SESSION_PATH, session_dir);
686
        status = FILE_DirExists(path);
687
        if( status < 0 ) {
688
          out("SD Card Error %d (FatFs: D%3d)\n", status, file_dfs_errno);
689
        } else if( status >= 1 ) {
690
          out("The session '%s' already exists, please delete it first!\n", session_dir);
691
        } else if( !new_session && SEQ_FILE_SaveAllFiles() < 0 ) {
692
          out("Failed to store session on SD Card: /SESSIONS/%s\n", seq_file_session_name);
693
        } else {
694
          FILE_MakeDir(path); // create directory
695
          status = FILE_DirExists(path);
696
          if( status < 1 ) {
697
        out("Failed to create new session (Error code %d, FatFs: D%3d)\n", status, file_dfs_errno);
698
          } else {
699
        if( (status=SEQ_FILE_CreateSession(session_dir, new_session)) < 0 ) {
700
          out("Failed to create new session during final call (Error code %d, FatFs: D%3d)\n", status, file_dfs_errno);
701
        } else {
702
          if( new_session ) {
703
            out("Creating new session '%s' - please wait, this can take a while!!!\n", session_dir);
704
          } else {
705
            out("Copy current session to '%s' - please wait, this can take a while!!!\n", session_dir);
706
          }
707
        }
708
          }
709
        }
710
      }
711
    }
712
 
713
    MUTEX_SDCARD_GIVE;
714
      }
715
    } else if( strcmp(parameter, "open") == 0 || strcmp(parameter, "load") == 0 ) {
716
      if( seq_ui_backup_req || seq_ui_format_req ) {
717
    out("Ongoing session creation - please wait!");
718
      } else {
719
    MUTEX_SDCARD_TAKE;
720
    char *session_dir = brkt;
721
 
722
    if( !strlen(session_dir) ) {
723
      out("Please specifiy a session name!");
724
    } else {
725
      char path[30];
726
      sprintf(path, "%s/%s", SEQ_FILE_SESSION_PATH, session_dir);
727
 
728
      s32 status = FILE_DirExists(path);
729
      if( status < 0 ) {
730
        out("SD Card Error %d (FatFs: D%3d)\n", status, file_dfs_errno);
731
      } else if( status < 1 ) {
732
        out("The session '%s' doesn't exist!\n", session_dir);
733
      } else {
734
        // remember previous session and switch to new name
735
        char prev_session_name[13];
736
        strcpy(prev_session_name, seq_file_session_name);
737
        strcpy(seq_file_session_name, session_dir);
738
 
739
        // try to load files
740
        status = SEQ_FILE_LoadAllFiles(0); // excluding HW config
741
 
742
        if( status < 0 ) {
743
          // session invalid - switch back to previous one!
744
          strcpy(seq_file_session_name, prev_session_name);
745
          out("The session '%s' is invalid!\n", session_dir);
746
        } else {
747
          out("Changed to session '%s'\n", session_dir);
748
 
749
          // store session name
750
          status |= SEQ_FILE_StoreSessionName();
751
        }
752
      }
753
    }
754
    MUTEX_SDCARD_GIVE;
755
      }
756
    } else if( strcmp(parameter, "delete") == 0 ) {
757
      if( seq_ui_backup_req || seq_ui_format_req ) {
758
    out("Ongoing session creation - please wait!");
759
      } else {
760
    MUTEX_SDCARD_TAKE;
761
    char *session_dir = brkt;
762
 
763
    if( !strlen(session_dir) ) {
764
      out("Please specifiy a session name!");
765
    } else {
766
      char path[30];
767
      sprintf(path, "%s/%s", SEQ_FILE_SESSION_PATH, session_dir);
768
 
769
      s32 status = FILE_DirExists(path);
770
      if( status < 0 ) {
771
        out("SD Card Error %d (FatFs: D%3d)\n", status, file_dfs_errno);
772
      } else if( status < 1 ) {
773
        out("The session '%s' doesn't exist!\n", session_dir);
774
      } else if( strcasecmp(session_dir, seq_file_session_name) == 0 ) {
775
        out("This is the active session! It can't be deleted!");
776
      } else if( strcasecmp(session_dir, "default") == 0 ) {
777
        out("The default session can't be deleted!");
778
      } else if( (status=SEQ_FILE_DeleteSession(session_dir)) < 0 ) {
779
        out("ERROR: delete %s failed!\n", session_dir);
780
      }
781
    }
782
    MUTEX_SDCARD_GIVE;
783
      }
784
    } else if( strcmp(parameter, "session") == 0 ) {
785
      out("Current session: %s", seq_file_session_name);
786
    } else if( strcmp(parameter, "sessions") == 0 ) {
787
      if( seq_ui_backup_req || seq_ui_format_req ) {
788
    out("Ongoing session creation - please wait!");
789
      } else {
790
    MUTEX_SDCARD_TAKE;
791
    s32 status = 0;
792
    DIR di;
793
    FILINFO de;
794
 
795
    if( f_opendir(&di, SEQ_FILE_SESSION_PATH) != FR_OK ) {
796
      out("ERROR: the %s directory doesn't exist!", SEQ_FILE_SESSION_PATH);
797
    } else {
798
      int num_dirs = 0;
799
      while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
800
        if( de.fname[0] && de.fname[0] != '.' && (de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
801
          ++num_dirs;
802
 
803
          out("Session #%3d: %s", num_dirs, de.fname);
804
        }
805
      }
806
      if( num_dirs < 1 ) {
807
        out("No session found!");
808
      } else if( num_dirs < 2 ) {
809
        out("%d session found!", num_dirs);
810
      } else {
811
        out("%d sessions found!", num_dirs);
812
      }
813
    }
814
    MUTEX_SDCARD_GIVE;
815
      }
1387 tk 816
    } else if( strcmp(parameter, "restore") == 0 ) {
1866 tk 817
      if( seq_ui_backup_req || seq_ui_format_req ) {
818
    out("Ongoing session creation - please wait!");
819
      } else if( strlen(brkt) ) {
820
    out("ERROR: use 'open' if you want to load a specific session!");
1387 tk 821
      } else {
1866 tk 822
    MUTEX_SDCARD_TAKE;
823
    if( SEQ_FILE_LoadAllFiles(1) < 0 ) {
824
      out("Failed to restore session from SD Card: /SESSIONS/%s\n", seq_file_session_name);
825
    } else {
826
      out("Restored complete session from SD Card: /SESSIONS/%s\n", seq_file_session_name);
827
    }
828
    MUTEX_SDCARD_GIVE;
1387 tk 829
      }
2131 tk 830
#ifndef MBSEQV4L
2130 tk 831
    } else if( strcmp(parameter, "screen_saver") == 0 ) {
832
      SEQ_LCD_LOGO_ScreenSaver_Enable();
833
      if( seq_lcd_logo_screensaver_delay ) {
834
    out("Screen Saver activated.");
835
      } else {
836
    out("Screen Saver has been disabled in UTIL->OPT - please set delay to >= 1 minute!");
837
      }
2131 tk 838
#endif
1311 tk 839
    } else if( strcmp(parameter, "reset") == 0 ) {
840
      MIOS32_SYS_Reset();
841
    } else {
1866 tk 842
      out("Unknown command - type 'help' to list available commands!");
944 tk 843
    }
844
  }
845
 
846
  return 0; // no error
847
}
848
 
849
 
1049 tk 850
s32 SEQ_TERMINAL_PrintHelp(void *_output_function)
944 tk 851
{
1049 tk 852
  void (*out)(char *format, ...) = _output_function;
853
 
854
  out("Welcome to " MIOS32_LCD_BOOT_MSG_LINE1 "!");
855
  out("Following commands are available:");
1866 tk 856
  out("  system:         print system info");
857
  out("  memory:         print memory allocation info");
858
  out("  sdcard:         print SD Card info");
859
  out("  sdcard_format:  formats the SD Card (you will be asked for confirmation)");
860
  out("  global:         print global configuration");
861
  out("  config:         print local session configuration");
862
  out("  tracks:         print overview of all tracks");
863
  out("  track <track>:  print info about a specific track");
864
  out("  mixer:          print current mixer map");
865
  out("  song:           print current song info");
866
  out("  grooves:        print groove templates");
867
  out("  bookmarks:      print bookmarks");
868
  out("  router:         print MIDI router info");
869
  out("  tpd <string>:   print a scrolled text on the TPD");
1457 tk 870
  out("  set router <node> <in-port> <off|channel|all> <out-port> <off|channel|all>: change router setting");
1390 tk 871
  out("  set mclk_in  <in-port>  <on|off>: change MIDI IN Clock setting");
872
  out("  set mclk_out <out-port> <on|off>: change MIDI OUT Clock setting");
2176 tk 873
  out("  set din_testmode <on|off>: change DIN (button/encoder) testmode (current: %s)", app_din_testmode ? "on" : "off");
1390 tk 874
  out("  set blm_port <off|in-port>: change BLM input port (same port is used for output)");
1754 tk 875
  out("  set rec_quantisation <1..100>: change record quantisation (default: 10%%, current: %d%%)\n", seq_record_quantize);
1868 tk 876
 
877
  MUTEX_MIDIOUT_TAKE;
1083 tk 878
#if !defined(MIOS32_FAMILY_EMULATION)
1492 tk 879
  AOUT_TerminalHelp(_output_function);
880
#endif
1633 tk 881
#ifdef MIOS32_LCD_universal
882
  APP_LCD_TerminalHelp(_output_function);
883
#endif
1492 tk 884
#if !defined(MIOS32_FAMILY_EMULATION)
1387 tk 885
  UIP_TERMINAL_Help(_output_function);
1083 tk 886
#endif
1868 tk 887
  MUTEX_MIDIOUT_GIVE;
888
 
1866 tk 889
  out("  play or start:  emulates the PLAY button");
890
  out("  stop:           emulates the STOP button");
891
  out("  store or save:  stores session under the current name on SD Card");
892
  out("  restore:        restores complete session from SD Card");
893
  out("  saveas <name>:  saves the current session under a new name");
894
  out("  new <name>:     creates a new session");
895
  out("  delete <name>:  deletes a session");
896
  out("  session:        prints the current session name");
897
  out("  sessions:       prints all available sessions");
2131 tk 898
#ifndef MBSEQV4L
2130 tk 899
  out("  screen_saver:   enables the screen saver immediately");
2131 tk 900
#endif
1866 tk 901
  out("  reset:          resets the MIDIbox SEQ (!)");
902
  out("  help:           this page");
1049 tk 903
 
904
  return 0; // no error
905
}
906
 
1320 tk 907
// Help function
908
static void stringNote(char *label, u8 note)
909
{
910
  const char noteTab[12][3] = { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" };
1049 tk 911
 
1320 tk 912
  // print "---" if note number is 0
913
  if( note == 0 )
914
    sprintf(label, "---  ");
915
  else {
916
    u8 octave = note / 12;
917
    note %= 12;
918
 
919
    // print semitone and octave (-2): up to 4 chars
920
    sprintf(label, "%s%d  ",
921
        noteTab[note],
922
        (int)octave-2);
923
  }
924
}
925
 
926
 
927
 
1049 tk 928
s32 SEQ_TERMINAL_PrintSystem(void *_output_function)
929
{
930
  void (*out)(char *format, ...) = _output_function;
944 tk 931
  char str_buffer[128];
932
 
1866 tk 933
  out("System Informations:");
934
  out("====================");
935
  out(MIOS32_LCD_BOOT_MSG_LINE1 " " MIOS32_LCD_BOOT_MSG_LINE2 "");
944 tk 936
 
937
  mios32_sys_time_t t = MIOS32_SYS_TimeGet();
938
  int hours = (t.seconds / 3600) % 24;
939
  int minutes = (t.seconds % 3600) / 60;
940
  int seconds = (t.seconds % 3600) % 60;
941
 
1866 tk 942
  out("Operating System: MIOS32");
943
  out("Board: " MIOS32_BOARD_STR "");
944
  out("Chip Family: " MIOS32_FAMILY_STR "");
944 tk 945
  if( MIOS32_SYS_SerialNumberGet((char *)str_buffer) >= 0 )
1049 tk 946
    out("Serial Number: %s\n", str_buffer);
944 tk 947
  else
1866 tk 948
    out("Serial Number: ?");
1049 tk 949
  out("Flash Memory Size: %d bytes\n", MIOS32_SYS_FlashSizeGet());
950
  out("RAM Size: %d bytes\n", MIOS32_SYS_RAMSizeGet());
944 tk 951
 
1769 tk 952
  {
1866 tk 953
    out("MIDI IN Ports:");
1769 tk 954
    int num = SEQ_MIDI_PORT_InNumGet();
955
    int i;
956
    for(i=0; i<num; ++i) {
957
      mios32_midi_port_t port = SEQ_MIDI_PORT_InPortGet(i);
958
      out("  - %s (%s)\n", SEQ_MIDI_PORT_InNameGet(i), SEQ_MIDI_PORT_InCheckAvailable(port) ? "available" : "not available");
959
    }    
960
  }
961
 
962
  {
1866 tk 963
    out("MIDI OUT Ports:");
1769 tk 964
    int num = SEQ_MIDI_PORT_OutNumGet();
965
    int i;
966
    for(i=0; i<num; ++i) {
967
      mios32_midi_port_t port = SEQ_MIDI_PORT_OutPortGet(i);
968
      out("  - %s (%s)\n", SEQ_MIDI_PORT_OutNameGet(i), SEQ_MIDI_PORT_OutCheckAvailable(port) ? "available" : "not available");
969
    }    
970
  }
971
 
1049 tk 972
  out("Systime: %02d:%02d:%02d\n", hours, minutes, seconds);
2275 tk 973
  out("CPU Load: %d%%\n", SEQ_STATISTICS_CurrentCPULoad());
1049 tk 974
  out("MIDI Scheduler: Alloc %3d/%3d Drops: %3d",
944 tk 975
        seq_midi_out_allocated, seq_midi_out_max_allocated, seq_midi_out_dropouts);
976
 
977
  u32 stopwatch_value_max = SEQ_STATISTICS_StopwatchGetValueMax();
978
  u32 stopwatch_value = SEQ_STATISTICS_StopwatchGetValue();
979
  if( stopwatch_value_max == 0xffffffff ) {
1866 tk 980
    out("Stopwatch: Overrun!");
944 tk 981
  } else if( !stopwatch_value_max ) {
1866 tk 982
    out("Stopwatch: no result yet");
944 tk 983
  } else {
1049 tk 984
    out("Stopwatch: %d/%d uS\n", stopwatch_value, stopwatch_value_max);
944 tk 985
  }
986
 
1320 tk 987
  u8 scale, root_selection, root;
988
  SEQ_CORE_FTS_GetScaleAndRoot(&scale, &root_selection, &root);
989
  char root_note_str[20];
990
  stringNote(root_note_str, root + 0x3c);
991
  out("Current Root Note (via %s): %s\n",
992
      root_selection == 0 ? "Keyboard" : "Selection",
993
      root_note_str);
994
 
1744 tk 995
#if !defined(MIOS32_FAMILY_EMULATION) && (configGENERATE_RUN_TIME_STATS || configUSE_TRACE_FACILITY)
944 tk 996
  // send Run Time Stats to MIOS terminal
1866 tk 997
  out("FreeRTOS Task RunTime Stats:");
944 tk 998
  FREERTOS_UTILS_RunTimeStats();
999
#endif
1000
 
1866 tk 1001
  out("done.");
944 tk 1002
 
1003
  return 0; // no error
1004
}
1005
 
1006
 
1052 tk 1007
s32 SEQ_TERMINAL_PrintGlobalConfig(void *_output_function)
944 tk 1008
{
1049 tk 1009
  void (*out)(char *format, ...) = _output_function;
1010
 
1866 tk 1011
  out("Global Configuration:");
1012
  out("=====================");
1052 tk 1013
  SEQ_FILE_GC_Debug();
1014
 
1866 tk 1015
  out("done.");
1052 tk 1016
 
1017
  return 0; // no error
1018
}
1019
 
1203 tk 1020
s32 SEQ_TERMINAL_PrintBookmarks(void *_output_function)
1021
{
1022
  void (*out)(char *format, ...) = _output_function;
1023
 
1866 tk 1024
  out("Global Bookmarks:");
1025
  out("=================");
1205 tk 1026
  SEQ_FILE_BM_Debug(1);
1203 tk 1027
 
1866 tk 1028
  out("");
1205 tk 1029
 
1866 tk 1030
  out("Session Bookmarks:");
1031
  out("==================");
1205 tk 1032
  SEQ_FILE_BM_Debug(0);
1033
 
1866 tk 1034
  out("done.");
1203 tk 1035
 
1036
  return 0; // no error
1037
}
1038
 
1052 tk 1039
s32 SEQ_TERMINAL_PrintSessionConfig(void *_output_function)
1040
{
1041
  void (*out)(char *format, ...) = _output_function;
1042
 
1866 tk 1043
  out("Session Configuration:");
1044
  out("======================");
944 tk 1045
  SEQ_FILE_C_Debug();
1046
 
1866 tk 1047
  out("done.");
944 tk 1048
 
1049
  return 0; // no error
1050
}
1051
 
1049 tk 1052
s32 SEQ_TERMINAL_PrintTracks(void *_output_function)
944 tk 1053
{
1049 tk 1054
  void (*out)(char *format, ...) = _output_function;
944 tk 1055
  char str_buffer[128];
1056
 
1866 tk 1057
  out("Track Overview:");
1058
  out("===============");
944 tk 1059
 
1866 tk 1060
  out("| Track | Mode  | Layer P/T/I | Steps P/T | Length | Port  | Chn. | Muted |");
1061
  out("+-------+-------+-------------+-----------+--------+-------+------+-------+");
944 tk 1062
 
1063
  u8 track;
1064
  for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) {
1065
    seq_event_mode_t event_mode = SEQ_CC_Get(track, SEQ_CC_MIDI_EVENT_MODE);
1066
    u16 num_instruments = SEQ_TRG_NumInstrumentsGet(track);
1067
    u16 num_par_layers = SEQ_PAR_NumLayersGet(track);
1068
    u16 num_par_steps = SEQ_PAR_NumStepsGet(track);
1069
    u16 num_trg_layers = SEQ_TRG_NumLayersGet(track);
1070
    u16 num_trg_steps = SEQ_TRG_NumStepsGet(track);
1071
    u16 length = (u16)SEQ_CC_Get(track, SEQ_CC_LENGTH) + 1;
1072
    mios32_midi_port_t midi_port = SEQ_CC_Get(track, SEQ_CC_MIDI_PORT);
1073
    u8 midi_chn = SEQ_CC_Get(track, SEQ_CC_MIDI_CHANNEL) + 1;
1074
 
1075
    sprintf(str_buffer, "| G%dT%d  | %s |",
1076
        (track/4)+1, (track%4)+1,
1077
        SEQ_LAYER_GetEvntModeName(event_mode));
1078
 
1079
    sprintf((char *)(str_buffer + strlen(str_buffer)), "   %2d/%2d/%2d  |  %3d/%3d  |   %3d  | %s%c |  %2d  |",
1080
        num_par_layers, num_trg_layers, num_instruments,
1081
        num_par_steps, num_trg_steps,
1082
        length,
1083
        SEQ_MIDI_PORT_OutNameGet(SEQ_MIDI_PORT_OutIxGet(midi_port)),
1084
        SEQ_MIDI_PORT_OutCheckAvailable(midi_port) ? ' ' : '*',
1085
        midi_chn);
1086
 
1015 tk 1087
    if( seq_core_trk_muted & (1 << track) )
1866 tk 1088
      sprintf((char *)(str_buffer + strlen(str_buffer)), "  yes  |");
944 tk 1089
    else if( seq_core_trk[track].layer_muted )
1866 tk 1090
      sprintf((char *)(str_buffer + strlen(str_buffer)), " layer |");
944 tk 1091
    else
1866 tk 1092
      sprintf((char *)(str_buffer + strlen(str_buffer)), "  no   |");
944 tk 1093
 
1049 tk 1094
    out(str_buffer);
944 tk 1095
  }
1096
 
1866 tk 1097
  out("+-------+-------+-------------+-----------+--------+-------+------+-------+");
944 tk 1098
 
1866 tk 1099
  out("done.");
944 tk 1100
 
1101
  return 0; // no error
1102
}
1103
 
1049 tk 1104
s32 SEQ_TERMINAL_PrintTrack(void *_output_function, u8 track)
944 tk 1105
{
1049 tk 1106
  void (*out)(char *format, ...) = _output_function;
1107
 
1108
  out("Track Parameters of G%dT%d", (track/4)+1, (track%4)+1);
1866 tk 1109
  out("========================");
944 tk 1110
 
1111
  SEQ_FILE_T_Debug(track);
1112
 
1866 tk 1113
  out("done.");
944 tk 1114
 
1115
  return 0; // no error
1116
}
1117
 
1049 tk 1118
s32 SEQ_TERMINAL_PrintCurrentMixerMap(void *_output_function)
944 tk 1119
{
1049 tk 1120
  void (*out)(char *format, ...) = _output_function;
944 tk 1121
 
1316 tk 1122
  char str_buffer[128];
944 tk 1123
  u8 map = SEQ_MIXER_NumGet();
1124
  int i;
1125
 
1049 tk 1126
  out("Mixer Map #%3d\n", map+1);
1866 tk 1127
  out("==============");
944 tk 1128
 
1866 tk 1129
  out("|Num|Port|Chn|Prg|Vol|Pan|Rev|Cho|Mod|CC1|CC2|CC3|CC4|C1A|C2A|C3A|C4A|");
1130
  out("+---+----+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+");
944 tk 1131
 
1132
  for(i=0; i<16; ++i) {
1133
    sprintf(str_buffer, "|%3d|%s|", i, SEQ_MIDI_PORT_OutNameGet(SEQ_MIDI_PORT_OutIxGet(SEQ_MIXER_Get(i, SEQ_MIXER_PAR_PORT))));
1134
 
1135
    int par;
1136
 
1137
    for(par=1; par<2; ++par)
1138
      sprintf((char *)(str_buffer + strlen(str_buffer)), "%3d|", SEQ_MIXER_Get(i, par)+1);
1139
 
1140
    for(par=2; par<12; ++par) {
1141
      u8 value = SEQ_MIXER_Get(i, par);
1142
      if( value )
1143
    sprintf((char *)(str_buffer + strlen(str_buffer)), "%3d|", value-1);
1144
      else
1145
    sprintf((char *)(str_buffer + strlen(str_buffer)), " - |");
1146
    }
1147
 
1148
    for(par=12; par<16; ++par)
1149
      sprintf((char *)(str_buffer + strlen(str_buffer)), "%3d|", SEQ_MIXER_Get(i, par));
1150
 
1049 tk 1151
    out("%s\n", str_buffer);
944 tk 1152
  }
1153
 
1866 tk 1154
  out("+---+----+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+");
1155
  out("done.");
944 tk 1156
 
1157
  return 0; // no error
1158
}
1159
 
1160
 
1049 tk 1161
s32 SEQ_TERMINAL_PrintCurrentSong(void *_output_function)
944 tk 1162
{
1049 tk 1163
  void (*out)(char *format, ...) = _output_function;
944 tk 1164
 
1316 tk 1165
  u8 song = SEQ_SONG_NumGet();
944 tk 1166
 
1049 tk 1167
  out("Song #%2d\n", song+1);
1866 tk 1168
  out("========");
944 tk 1169
 
1049 tk 1170
  out("Name: '%s'\n", seq_song_name);
944 tk 1171
  MIOS32_MIDI_SendDebugHexDump((u8 *)&seq_song_steps[0], SEQ_SONG_NUM_STEPS*sizeof(seq_song_step_t));
1172
 
1866 tk 1173
  out("done.");
944 tk 1174
 
1175
  return 0; // no error
1176
}
1177
 
1049 tk 1178
s32 SEQ_TERMINAL_PrintGrooveTemplates(void *_output_function)
944 tk 1179
{
1049 tk 1180
  void (*out)(char *format, ...) = _output_function;
1181
 
1866 tk 1182
  out("Groove Templates:");
1183
  out("=================");
944 tk 1184
  SEQ_FILE_G_Debug();
1185
 
1866 tk 1186
  out("done.");
944 tk 1187
 
1188
  return 0; // no error
1189
}
1190
 
1049 tk 1191
s32 SEQ_TERMINAL_PrintMemoryInfo(void *_output_function)
1019 tk 1192
{
2425 tk 1193
  void (*out)(char *format, ...) = _output_function;
1049 tk 1194
 
2425 tk 1195
  out("Not supported yet");
944 tk 1196
 
1019 tk 1197
  return 0; // no error
1198
}
974 tk 1199
 
1200
 
1201
///////////////////////////////////////////////////////////////////
1202
// These time and date functions and other bits of following code were adapted from 
1203
// Rickey's world of Microelectronics under the creative commons 2.5 license.
1204
// http://www.8051projects.net/mmc-sd-interface-fat16/final-code.php
1205
static void ShowFatTime(u32 ThisTime, char* msg)
1206
{
1207
   u8 AM = 1;
1208
 
1209
   int Hour, Minute, Second;
1210
 
1211
   Hour = ThisTime >> 11;        // bits 15 through 11 hold Hour...
1212
   Minute = ThisTime & 0x07E0;   // bits 10 through 5 hold Minute... 0000 0111 1110 0000
1213
   Minute = Minute >> 5;
1214
   Second = ThisTime & 0x001F;   //bits 4 through 0 hold Second...   0000 0000 0001 1111
1215
 
1216
   if( Hour > 11 )
1217
   {
1218
      AM = 0;
1219
      if( Hour > 12 )
1220
         Hour -= 12;
1221
   }
1222
 
1223
   sprintf( msg, "%02d:%02d:%02d %s", Hour, Minute, Second*2,
1224
         (AM)?"AM":"PM");
1225
   return;
1226
}
1227
 
1228
static void ShowFatDate(u32 ThisDate, char* msg)
1229
{
1230
 
1231
   int Year, Month, Day;
1232
 
1233
   Year = ThisDate >> 9;         // bits 15 through 9 hold year...
1234
   Month = ThisDate & 0x01E0;    // bits 8 through 5 hold month... 0000 0001 1110 0000
1235
   Month = Month >> 5;
1236
   Day = ThisDate & 0x001F;      //bits 4 through 0 hold day...    0000 0000 0001 1111
1237
   sprintf( msg, "%02d/%02d/%02d", Month, Day, Year-20);
1238
   return;
1239
}
1240
 
1019 tk 1241
 
1049 tk 1242
s32 SEQ_TERMINAL_PrintSdCardInfo(void *_output_function)
944 tk 1243
{
1049 tk 1244
  void (*out)(char *format, ...) = _output_function;
1245
 
974 tk 1246
  FRESULT res;
1247
  FILINFO fno;
1248
  DIR dir;
1249
  char *fn;
944 tk 1250
  char str_buffer[128];
1251
 
1866 tk 1252
  out("SD Card Informations");
1253
  out("====================");
944 tk 1254
 
1255
#if !defined(MIOS32_FAMILY_EMULATION)
1256
  // this yield ensures, that Debug Messages are sent before we continue the execution
1257
  // Since MIOS Studio displays the time at which the messages arrived, this allows
1258
  // us to measure the delay of following operations
1259
  taskYIELD();
1260
 
1261
  MUTEX_SDCARD_TAKE;
1261 tk 1262
  FILE_PrintSDCardInfos();
944 tk 1263
  MUTEX_SDCARD_GIVE;
983 tk 1264
#endif
944 tk 1265
 
1866 tk 1266
  out("");
1267
  out("Reading Root Directory");
1268
  out("======================");
944 tk 1269
 
1270
  taskYIELD();
1271
 
1261 tk 1272
  if( !FILE_SDCardAvailable() ) {
944 tk 1273
    sprintf(str_buffer, "not connected");
1261 tk 1274
  } else if( !FILE_VolumeAvailable() ) {
944 tk 1275
    sprintf(str_buffer, "Invalid FAT");
1276
  } else {
1866 tk 1277
    out("Retrieving SD Card informations - please wait!");
944 tk 1278
    MUTEX_MIDIOUT_GIVE;
1279
    MUTEX_SDCARD_TAKE;
1261 tk 1280
    FILE_UpdateFreeBytes();
944 tk 1281
    MUTEX_SDCARD_GIVE;
1282
    MUTEX_MIDIOUT_TAKE;
1283
 
1284
    sprintf(str_buffer, "'%s': %u of %u MB free",
1261 tk 1285
        FILE_VolumeLabel(),
1286
        (unsigned int)(FILE_VolumeBytesFree()/1000000),
1287
        (unsigned int)(FILE_VolumeBytesTotal()/1000000));
944 tk 1288
  }
1049 tk 1289
  out("SD Card: %s\n", str_buffer);
944 tk 1290
 
1291
  taskYIELD();
974 tk 1292
 
1293
#if _USE_LFN
1294
  static char lfn[_MAX_LFN * (_DF1S ? 2 : 1) + 1];
1295
  fno.lfname = lfn;
1296
  fno.lfsize = sizeof(lfn);
944 tk 1297
#endif
1298
 
974 tk 1299
  MUTEX_SDCARD_TAKE;
1300
  if( (res=f_opendir(&dir, "/")) != FR_OK ) {
1049 tk 1301
    out("Failed to open root directory - error status: %d\n", res);
974 tk 1302
  } else {
1303
    while( (f_readdir(&dir, &fno) == FR_OK) && fno.fname[0] ) {
1304
#if _USE_LFN
1305
      fn = *fno.lfname ? fno.lfname : fno.fname;
1306
#else
1307
      fn = fno.fname;
1308
#endif
1309
      char date[10];
1310
      ShowFatDate(fno.fdate,(char*)&date);
1311
      char time[12];
1312
      ShowFatTime(fno.ftime,(char*)&time);
1049 tk 1313
      out("[%s%s%s%s%s%s%s] %s  %s   %s %u %s\n",
974 tk 1314
        (fno.fattrib & AM_RDO ) ? "r" : ".",
1315
        (fno.fattrib & AM_HID ) ? "h" : ".",
1316
        (fno.fattrib & AM_SYS ) ? "s" : ".",
1317
        (fno.fattrib & AM_VOL ) ? "v" : ".",
1318
        (fno.fattrib & AM_LFN ) ? "l" : ".",
1319
        (fno.fattrib & AM_DIR ) ? "d" : ".",
1320
        (fno.fattrib & AM_ARC ) ? "a" : ".",
1321
        date,time,
1322
        (fno.fattrib & AM_DIR) ? "<DIR>" : " ",
1323
        fno.fsize,fn);
1324
    }
1325
  }
1326
  MUTEX_SDCARD_GIVE;
983 tk 1327
 
974 tk 1328
  taskYIELD();
1329
 
1866 tk 1330
  out("");
1331
  out("Checking SD Card at application layer");
1332
  out("=====================================");
974 tk 1333
 
1081 tk 1334
  out("Current session: /SESSIONS/%s\n", seq_file_session_name);
974 tk 1335
 
944 tk 1336
  {
1337
    u8 bank;
1338
    for(bank=0; bank<SEQ_FILE_B_NUM_BANKS; ++bank) {
1339
      int num_patterns = SEQ_FILE_B_NumPatterns(bank);
1340
      if( num_patterns )
1081 tk 1341
    out("File /SESSIONS/%s/MBSEQ_B%d.V4: valid (%d patterns)\n", seq_file_session_name, bank+1, num_patterns);
944 tk 1342
      else
1081 tk 1343
    out("File /SESSIONS/%s/MBSEQ_B%d.V4: doesn't exist\n", seq_file_session_name, bank+1, num_patterns);
944 tk 1344
    }
1345
 
1346
    int num_maps = SEQ_FILE_M_NumMaps();
1347
    if( num_maps )
1443 tk 1348
      out("File /SESSIONS/%s/MBSEQ_M.V4: valid (%d mixer maps)\n", seq_file_session_name, num_maps);
944 tk 1349
    else
1081 tk 1350
      out("File /SESSIONS/%s/MBSEQ_M.V4: doesn't exist\n", seq_file_session_name);
944 tk 1351
 
1352
    int num_songs = SEQ_FILE_S_NumSongs();
1353
    if( num_songs )
1081 tk 1354
      out("File /SESSIONS/%s/MBSEQ_S.V4: valid (%d songs)\n", seq_file_session_name, num_songs);
944 tk 1355
    else
1081 tk 1356
      out("File /SESSIONS/%s/MBSEQ_S.V4: doesn't exist\n", seq_file_session_name);
944 tk 1357
 
1358
    if( SEQ_FILE_G_Valid() )
1081 tk 1359
      out("File /SESSIONS/%s/MBSEQ_G.V4: valid\n", seq_file_session_name);
944 tk 1360
    else
1081 tk 1361
      out("File /SESSIONS/%s/MBSEQ_G.V4: doesn't exist\n", seq_file_session_name);
944 tk 1362
 
1444 tk 1363
    if( SEQ_FILE_BM_Valid(0) )
1364
      out("File /SESSIONS/%s/MBSEQ_BM.V4: valid\n", seq_file_session_name);
1365
    else
1366
      out("File /SESSIONS/%s/MBSEQ_BM.V4: doesn't exist\n", seq_file_session_name);
1367
 
944 tk 1368
    if( SEQ_FILE_C_Valid() )
1081 tk 1369
      out("File /SESSIONS/%s/MBSEQ_C.V4: valid\n", seq_file_session_name);
944 tk 1370
    else
1081 tk 1371
      out("File /SESSIONS/%s/MBSEQ_C.V4: doesn't exist\n", seq_file_session_name);
1319 tk 1372
 
1444 tk 1373
    if( SEQ_FILE_GC_Valid() )
1866 tk 1374
      out("File /MBSEQ_C.V4: valid");
1444 tk 1375
    else
1866 tk 1376
      out("File /MBSEQ_C.V4: doesn't exist");
1444 tk 1377
 
1378
    if( SEQ_FILE_BM_Valid(1) )
1866 tk 1379
      out("File /MBSEQ_BM.V4: valid");
1444 tk 1380
    else
1866 tk 1381
      out("File /MBSEQ_BM.V4: doesn't exist");
1444 tk 1382
 
1319 tk 1383
#ifndef MBSEQV4L    
944 tk 1384
    if( SEQ_FILE_HW_Valid() )
1866 tk 1385
      out("File /MBSEQ_HW.V4: valid");
944 tk 1386
    else
1866 tk 1387
      out("File /MBSEQ_HW.V4: doesn't exist or hasn't been re-loaded");
1319 tk 1388
#else
1389
    if( SEQ_FILE_HW_Valid() )
1866 tk 1390
      out("File /MBSEQ_HW.V4L: valid");
1319 tk 1391
    else
1866 tk 1392
      out("File /MBSEQ_HW.V4L: doesn't exist or hasn't been re-loaded");
1319 tk 1393
#endif
944 tk 1394
  }
1395
 
1866 tk 1396
  out("done.");
944 tk 1397
 
1398
  return 0; // no error
1399
}
1049 tk 1400
 
1401
 
1390 tk 1402
s32 SEQ_TERMINAL_PrintRouterInfo(void *_output_function)
1403
{
1404
  void (*out)(char *format, ...) = _output_function;
1405
 
1779 tk 1406
  out("MIDI Router Nodes (change with 'set router <node> <in-port> <channel> <out-port> <channel>)");
1407
  out("Example: set router 1 IN1 all USB1 all");
1390 tk 1408
 
1409
  u8 node;
1410
  seq_midi_router_node_t *n = &seq_midi_router_node[0];
1411
  for(node=0; node<SEQ_MIDI_ROUTER_NUM_NODES; ++node, ++n) {
1412
 
1413
    char src_chn[10];
1414
    if( !n->src_chn )
1415
      sprintf(src_chn, "off");
1416
    else if( n->src_chn > 16 )
1417
      sprintf(src_chn, "all");
1418
    else
1419
      sprintf(src_chn, "#%2d", n->src_chn);
1420
 
1421
    char dst_chn[10];
1422
    if( !n->dst_chn )
1423
      sprintf(dst_chn, "off");
1713 tk 1424
    else if( n->dst_chn == 17 )
1425
      sprintf(dst_chn, "All");
1746 tk 1426
    else if( n->dst_chn == 18 )
1713 tk 1427
      sprintf(dst_chn, "Trk");
1746 tk 1428
    else if( n->dst_chn >= 19 )
1429
      sprintf(dst_chn, "STk");
1390 tk 1430
    else
1431
      sprintf(dst_chn, "#%2d", n->dst_chn);
1432
 
1433
    out("  %2d  SRC:%s %s  DST:%s %s",
1434
    node+1,
1435
    SEQ_MIDI_PORT_InNameGet(SEQ_MIDI_PORT_InIxGet(n->src_port)),
1436
    src_chn,
1437
    SEQ_MIDI_PORT_OutNameGet(SEQ_MIDI_PORT_OutIxGet(n->dst_port)),
1438
    dst_chn);
1439
  }
1440
 
1441
  out("");
1442
  out("MIDI Clock (change with 'set mclk_in <in-port> <on|off>' resp. 'set mclk_out <out-port> <on|off>')");
1443
 
1444
  int num_mclk_ports = SEQ_MIDI_PORT_ClkNumGet();
1445
  int port_ix;
1446
  for(port_ix=0; port_ix<num_mclk_ports; ++port_ix) {
1447
    mios32_midi_port_t mclk_port = SEQ_MIDI_PORT_ClkPortGet(port_ix);
1448
 
1449
    s32 enab_rx = SEQ_MIDI_ROUTER_MIDIClockInGet(mclk_port);
1450
    if( !SEQ_MIDI_PORT_ClkCheckAvailable(mclk_port) )
1451
      enab_rx = -1; // MIDI In port not available
1452
 
1453
    s32 enab_tx = SEQ_MIDI_ROUTER_MIDIClockOutGet(mclk_port);
1454
    if( !SEQ_MIDI_PORT_ClkCheckAvailable(mclk_port) )
1455
      enab_tx = -1; // MIDI In port not available
1456
 
1457
    out("  %s  IN:%s  OUT:%s\n",
1458
    SEQ_MIDI_PORT_ClkNameGet(port_ix),
1459
    (enab_rx == 0) ? "off" : ((enab_rx == 1) ? "on " : "---"),
1460
    (enab_tx == 0) ? "off" : ((enab_tx == 1) ? "on " : "---"));
1461
  }
1462
 
1463
  return 0; // no error
1464
}