Subversion Repositories svn.mios32

Rev

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

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