Subversion Repositories svn.mios32

Rev

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

Rev Author Line No. Line
1298 tk 1
// $Id: app.cpp 1453 2012-03-23 20:49:40Z tk $
2
/*
3
 * MIDIbox CV V2
4
 *
5
 * ==========================================================================
6
 *
7
 *  Copyright (C) 2011 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 <aout.h>
1334 tk 20
#include "tasks.h"
1298 tk 21
#include "app.h"
1334 tk 22
#include "MbCvEnvironment.h"
1298 tk 23
 
1334 tk 24
#include <file.h>
25
 
26
// include source of the SCS
27
#include <scs.h>
28
#include "scs_config.h"
29
 
30
#include <seq_bpm.h>
31
#include <seq_midi_out.h>
32
 
33
// quick&dirty to simplify re-use of C modules without changing header files
34
extern "C" {
1298 tk 35
#include "mbcv_sysex.h"
36
#include "mbcv_patch.h"
1299 tk 37
#include "mbcv_map.h"
1298 tk 38
#include "mbcv_router.h"
39
#include "mbcv_port.h"
40
 
41
#include "mbcv_file.h"
42
#include "mbcv_file_p.h"
1453 tk 43
#include "mbcv_file_b.h"
1298 tk 44
 
45
#include "terminal.h"
46
#include "midimon.h"
47
 
48
#include "uip_task.h"
49
#include "osc_client.h"
1334 tk 50
}
1298 tk 51
 
52
/////////////////////////////////////////////////////////////////////////////
1334 tk 53
// for optional debugging messages via DEBUG_MSG (defined in mios32_config.h)
54
// should be at least 1 for sending error messages
1298 tk 55
/////////////////////////////////////////////////////////////////////////////
1334 tk 56
#define DEBUG_VERBOSE_LEVEL 2
1298 tk 57
 
1334 tk 58
// measure performance with the stopwatch
1394 tk 59
//#define STOPWATCH_PERFORMANCE_MEASURING 2
1401 tk 60
#define STOPWATCH_PERFORMANCE_MEASURING 0
1298 tk 61
 
62
 
63
/////////////////////////////////////////////////////////////////////////////
64
// local variables
65
/////////////////////////////////////////////////////////////////////////////
66
static u8 hw_enabled;
67
 
1334 tk 68
static u32 ms_counter;
1298 tk 69
 
1334 tk 70
static u32 stopwatch_value;
71
static u32 stopwatch_value_max;
72
static u32 stopwatch_value_accumulated;
1298 tk 73
 
1334 tk 74
static u32 cv_se_speed_factor;
1298 tk 75
 
1334 tk 76
/////////////////////////////////////////////////////////////////////////////
77
// C++ objects
78
/////////////////////////////////////////////////////////////////////////////
79
MbCvEnvironment mbCvEnvironment;
1298 tk 80
 
81
 
82
/////////////////////////////////////////////////////////////////////////////
83
// Local prototypes
84
/////////////////////////////////////////////////////////////////////////////
85
static void APP_Periodic_100uS(void);
1334 tk 86
extern void CV_TIMER_SE_Update(void);
1298 tk 87
static s32 NOTIFY_MIDI_Rx(mios32_midi_port_t port, u8 byte);
1299 tk 88
static s32 NOTIFY_MIDI_Tx(mios32_midi_port_t port, mios32_midi_package_t package);
89
static s32 NOTIFY_MIDI_TimeOut(mios32_midi_port_t port);
1298 tk 90
 
91
 
92
 
93
/////////////////////////////////////////////////////////////////////////////
1334 tk 94
// returns pointer to MbCv objects
95
/////////////////////////////////////////////////////////////////////////////
96
MbCvEnvironment *APP_GetEnv()
97
{
98
  return &mbCvEnvironment;
99
}
100
 
101
 
102
/////////////////////////////////////////////////////////////////////////////
1298 tk 103
// This hook is called after startup to initialize the application
104
/////////////////////////////////////////////////////////////////////////////
1334 tk 105
extern "C" void APP_Init(void)
1298 tk 106
{
107
  // initialize all LEDs
108
  MIOS32_BOARD_LED_Init(0xffffffff);
109
 
110
  // hardware will be enabled once configuration has been loaded from SD Card
111
  // (resp. no SD Card is available)
112
  hw_enabled = 0;
113
 
1334 tk 114
  // init Stopwatch
115
  APP_StopwatchInit();
116
 
1298 tk 117
  // initialize all J10 pins as inputs with internal Pull-Up
118
  int pin;
119
  for(pin=0; pin<8; ++pin)
120
    MIOS32_BOARD_J10_PinInit(pin, MIOS32_BOARD_PIN_MODE_INPUT_PU);
121
 
122
 
123
  // install SysEx callback
124
  MIOS32_MIDI_SysExCallback_Init(APP_SYSEX_Parser);
125
 
1299 tk 126
  // install MIDI Rx/Tx callback functions
127
  MIOS32_MIDI_DirectRxCallback_Init(&NOTIFY_MIDI_Rx);
128
  MIOS32_MIDI_DirectTxCallback_Init(&NOTIFY_MIDI_Tx);
1298 tk 129
 
1299 tk 130
  // install timeout callback function
131
  MIOS32_MIDI_TimeOutCallback_Init(&NOTIFY_MIDI_TimeOut);
1298 tk 132
 
133
  // initialize AOUT module
134
  AOUT_Init(0);
135
 
136
  // configure interface (will be changed again once config file has been loaded from SD Card, or via SCS)
137
  aout_config_t config;
138
  config = AOUT_ConfigGet();
139
  config.if_type = AOUT_IF_MAX525;
140
  config.if_option = 0;
141
  config.num_channels = 8;
142
  config.chn_inverted = 0;
143
  AOUT_ConfigSet(config);
144
  AOUT_IF_Init(0);
145
 
1299 tk 146
  // initialize code modules
147
  MBCV_PORT_Init(0);
148
  MBCV_SYSEX_Init(0);
149
  MBCV_MAP_Init(0);
150
  MBCV_ROUTER_Init(0);
151
  MBCV_PATCH_Init(0);
152
  UIP_TASK_Init(0);
153
  SCS_Init(0);
154
  SCS_CONFIG_Init(0);
155
  TERMINAL_Init(0);
156
  MIDIMON_Init(0);
157
  MBCV_FILE_Init(0);
158
  SEQ_MIDI_OUT_Init(0);
159
 
1298 tk 160
  // install timer function which is called each 100 uS
161
  MIOS32_TIMER_Init(1, 100, APP_Periodic_100uS, MIOS32_IRQ_PRIO_MID);
162
 
1334 tk 163
  // initialize MbCvEnvironment
1347 tk 164
  cv_se_speed_factor = 10;
1334 tk 165
  mbCvEnvironment.updateSpeedFactorSet(cv_se_speed_factor);
1298 tk 166
 
1334 tk 167
  // initialize tasks
168
  TASKS_Init(0);
169
 
170
  // start timer
171
  // TODO: increase  once performance has been evaluated
172
  MIOS32_TIMER_Init(2, 2000 / cv_se_speed_factor, CV_TIMER_SE_Update, MIOS32_IRQ_PRIO_MID);
1298 tk 173
}
174
 
175
 
176
/////////////////////////////////////////////////////////////////////////////
177
// This task is running endless in background
178
/////////////////////////////////////////////////////////////////////////////
1334 tk 179
extern "C" void APP_Background(void)
1298 tk 180
{
181
  // endless loop
182
  while( 1 ) {
183
    // toggle the state of all LEDs (allows to measure the execution speed with a scope)
184
    MIOS32_BOARD_LED_Set(0xffffffff, ~MIOS32_BOARD_LED_Get());
185
  }
186
}
187
 
188
 
189
/////////////////////////////////////////////////////////////////////////////
190
// This hook is called when a MIDI package has been received
191
/////////////////////////////////////////////////////////////////////////////
1334 tk 192
extern "C" void APP_MIDI_NotifyPackage(mios32_midi_port_t port, mios32_midi_package_t midi_package)
1298 tk 193
{
1299 tk 194
  // -> CV MIDI handler
1334 tk 195
  mbCvEnvironment.midiReceive(port, midi_package);
1299 tk 196
 
1298 tk 197
  // -> MIDI Router
198
  MBCV_ROUTER_Receive(port, midi_package);
199
 
1299 tk 200
  // -> MIDI Port Handler (used for MIDI monitor function)
201
  MBCV_PORT_NotifyMIDIRx(port, midi_package);
202
 
1298 tk 203
  // forward to MIDI Monitor
204
  // SysEx messages have to be filtered for USB0 and UART0 to avoid data corruption
205
  // (the SysEx stream would interfere with monitor messages)
206
  u8 filter_sysex_message = (port == USB0) || (port == UART0);
207
  MIDIMON_Receive(port, midi_package, ms_counter, filter_sysex_message);
208
}
209
 
210
/////////////////////////////////////////////////////////////////////////////
211
// This function parses an incoming sysex stream for MIOS32 commands
212
/////////////////////////////////////////////////////////////////////////////
1334 tk 213
extern "C" s32 APP_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in)
1298 tk 214
{
215
  // -> MBCV
216
  MBCV_SYSEX_Parser(port, midi_in);
217
 
218
  // -> MIDI Router
219
  MBCV_ROUTER_ReceiveSysEx(port, midi_in);
220
 
221
  return 0; // no error
222
}
223
 
224
/////////////////////////////////////////////////////////////////////////////
225
// This hook is called before the shift register chain is scanned
226
/////////////////////////////////////////////////////////////////////////////
1334 tk 227
extern "C" void APP_SRIO_ServicePrepare(void)
1298 tk 228
{
229
  // pass current pin state of J10
230
  // only available for LPC17xx, all others (like STM32) default to SRIO
231
  SCS_AllPinsSet(0xff00 | MIOS32_BOARD_J10_Get());
232
 
233
  // update encoders/buttons of SCS
234
  SCS_EncButtonUpdate_Tick();
235
}
236
 
237
 
238
/////////////////////////////////////////////////////////////////////////////
239
// This hook is called after the shift register chain has been scanned
240
/////////////////////////////////////////////////////////////////////////////
1334 tk 241
extern "C" void APP_SRIO_ServiceFinish(void)
1298 tk 242
{
243
}
244
 
245
 
246
/////////////////////////////////////////////////////////////////////////////
247
// This hook is called when a button has been toggled
248
// pin_value is 1 when button released, and 0 when button pressed
249
/////////////////////////////////////////////////////////////////////////////
1334 tk 250
extern "C" void APP_DIN_NotifyToggle(u32 pin, u32 pin_value)
1298 tk 251
{
252
}
253
 
254
 
255
/////////////////////////////////////////////////////////////////////////////
256
// This hook is called when an encoder has been moved
257
// incrementer is positive when encoder has been turned clockwise, else
258
// it is negative
259
/////////////////////////////////////////////////////////////////////////////
1334 tk 260
extern "C" void APP_ENC_NotifyChange(u32 encoder, s32 incrementer)
1298 tk 261
{
262
  // pass encoder event to SCS handler
263
  if( encoder == SCS_ENC_MENU_ID )
264
    SCS_ENC_MENU_NotifyChange(incrementer);
265
}
266
 
267
 
268
/////////////////////////////////////////////////////////////////////////////
269
// This hook is called when a pot has been moved
270
/////////////////////////////////////////////////////////////////////////////
1334 tk 271
extern "C" void APP_AIN_NotifyChange(u32 pin, u32 pin_value)
1298 tk 272
{
273
}
274
 
275
 
276
 
1334 tk 277
/////////////////////////////////////////////////////////////////////////////
278
// This timer interrupt periodically calls the sound engine update
279
/////////////////////////////////////////////////////////////////////////////
280
extern void CV_TIMER_SE_Update(void)
281
{
282
  if( !hw_enabled )
283
    return;
1298 tk 284
 
1334 tk 285
#if STOPWATCH_PERFORMANCE_MEASURING >= 1
286
  APP_StopwatchReset();
287
#endif
288
 
289
  if( !mbCvEnvironment.tick() )
290
    return; // no update required
291
 
292
#if STOPWATCH_PERFORMANCE_MEASURING == 1
293
  APP_StopwatchCapture();
294
#endif
295
 
296
  // update AOUTs
297
  MBCV_MAP_Update();
298
 
299
#if STOPWATCH_PERFORMANCE_MEASURING == 2
300
  APP_StopwatchCapture();
301
#endif
302
}
303
 
304
 
305
 
306
 
1298 tk 307
/////////////////////////////////////////////////////////////////////////////
308
// This task handles the control surface
309
/////////////////////////////////////////////////////////////////////////////
1334 tk 310
void APP_TASK_Period_1mS_LP(void)
1298 tk 311
{
1334 tk 312
  static u16 performance_print_ctr = 0;
1298 tk 313
 
1334 tk 314
  // call SCS handler
315
  SCS_Tick();
1298 tk 316
 
1334 tk 317
  // MIDI In/Out monitor
318
  MBCV_PORT_Period1mS();
1298 tk 319
 
1334 tk 320
  // output and reset current stopwatch max value each second
321
  if( ++performance_print_ctr >= 1000 ) {
322
    performance_print_ctr = 0;
323
 
324
    MUTEX_MIDIOUT_TAKE;
325
    MIOS32_IRQ_Disable();
326
    u32 max_value = stopwatch_value_max;
327
    stopwatch_value_max = 0;
328
    u32 acc_value = stopwatch_value_accumulated;
329
    stopwatch_value_accumulated = 0;
330
    MIOS32_IRQ_Enable();
331
#if DEBUG_VERBOSE_LEVEL >= 2
332
    if( acc_value || max_value )
333
      DEBUG_MSG("%d uS (max: %d uS)\n", acc_value / (1000000 / (2000/cv_se_speed_factor)), max_value);
334
#endif
335
    MUTEX_MIDIOUT_GIVE;
1298 tk 336
  }
337
 
338
}
339
 
340
 
341
/////////////////////////////////////////////////////////////////////////////
342
// This task handles the SD Card
343
/////////////////////////////////////////////////////////////////////////////
1334 tk 344
void APP_TASK_Period_1mS_SD(void)
1298 tk 345
{
1334 tk 346
  static u16 sdcard_check_ctr = 0;
1298 tk 347
 
1334 tk 348
  // each second: check if SD Card (still) available
349
  if( ++sdcard_check_ctr >= 1000 ) {
350
    sdcard_check_ctr = 0;
1298 tk 351
 
1334 tk 352
    MUTEX_SDCARD_TAKE;
353
    s32 status = FILE_CheckSDCard();
1298 tk 354
 
1334 tk 355
    hw_enabled = 1; // enable hardware after first read...
1298 tk 356
 
1334 tk 357
    if( status == 1 ) {
358
      DEBUG_MSG("SD Card connected: %s\n", FILE_VolumeLabel());
359
      // load all file infos
360
      MBCV_FILE_LoadAllFiles(1); // including HW info
361
    } else if( status == 2 ) {
362
      DEBUG_MSG("SD Card disconnected\n");
363
      // invalidate all file infos
364
      MBCV_FILE_UnloadAllFiles();
1298 tk 365
 
1334 tk 366
      // change status
367
      MBCV_FILE_StatusMsgSet("No SD Card");
368
    } else if( status == 3 ) {
369
      if( !FILE_SDCardAvailable() ) {
370
    DEBUG_MSG("SD Card not found\n");
1298 tk 371
    MBCV_FILE_StatusMsgSet("No SD Card");
1334 tk 372
      } else if( !FILE_VolumeAvailable() ) {
373
    DEBUG_MSG("ERROR: SD Card contains invalid FAT!\n");
374
    MBCV_FILE_StatusMsgSet("No FAT");
375
      } else {
376
    // check if patch file exists
377
    if( !MBCV_FILE_P_Valid() ) {
378
      // create new one
379
      DEBUG_MSG("Creating initial DEFAULT.CV2 file\n");
380
 
381
      if( (status=MBCV_FILE_P_Write("DEFAULT")) < 0 ) {
382
        DEBUG_MSG("Failed to create file! (status: %d)\n", status);
1298 tk 383
      }
384
    }
385
 
1453 tk 386
    // check if bank files exist
387
    for(int bank=0; bank<MBCV_FILE_B_NUM_BANKS; ++bank) {
388
      if( !MBCV_FILE_B_NumPatches(bank) ) {
389
        // create new one
390
        DEBUG_MSG("Creating MBCV_B%d.V2 file\n", bank+1);
391
 
392
        if( (status=MBCV_FILE_B_Create(bank)) < 0 ) {
393
          DEBUG_MSG("Failed to create file! (status: %d)\n", status);
394
        } else {
395
          for(int patch=0; patch<MBCV_FILE_B_NumPatches(bank); ++patch) {
396
        DEBUG_MSG("Creating MBCV_B%d.V2 patch %c%03d\n", bank+1, 'A'+bank, patch);
397
        if( (status=MBCV_FILE_B_PatchWrite(bank, patch, 0)) < 0 ) {
398
          DEBUG_MSG("Failed to create patch! (status: %d)\n", status);
399
        }
400
          }
401
        }
402
      }
403
    }
404
 
405
    MBCV_FILE_B_LoadAllBanks();
406
 
1334 tk 407
    // disable status message and print patch
408
    MBCV_FILE_StatusMsgSet(NULL);
1298 tk 409
      }
410
    }
1334 tk 411
 
412
    MUTEX_SDCARD_GIVE;
1298 tk 413
  }
414
}
415
 
416
 
417
/////////////////////////////////////////////////////////////////////////////
1452 tk 418
// This task is called periodically each mS
1298 tk 419
/////////////////////////////////////////////////////////////////////////////
1334 tk 420
void APP_TASK_Period_1mS(void)
1298 tk 421
{
1452 tk 422
  // e.g. for synched pattern changes
423
  mbCvEnvironment.tick_1mS();
424
 
1334 tk 425
  if( hw_enabled ) {
426
    // nothing to do... yet
1298 tk 427
  }
428
}
429
 
430
 
431
/////////////////////////////////////////////////////////////////////////////
432
// This timer function is periodically called each 100 uS
433
/////////////////////////////////////////////////////////////////////////////
434
static void APP_Periodic_100uS(void)
435
{
436
  static u8 pre_ctr = 0;
437
 
438
  // increment the microsecond counter each 10th tick
439
  if( ++pre_ctr >= 10 ) {
440
    pre_ctr = 0;
441
    ++ms_counter;
442
  }
443
 
444
  // here we could do some additional high-prio jobs
445
  // (e.g. PWM LEDs)
446
}
447
 
448
/////////////////////////////////////////////////////////////////////////////
449
// Installed via MIOS32_MIDI_DirectRxCallback_Init
450
/////////////////////////////////////////////////////////////////////////////
451
static s32 NOTIFY_MIDI_Rx(mios32_midi_port_t port, u8 midi_byte)
452
{
1299 tk 453
  // filter MIDI In port which controls the MIDI clock
454
  if( MBCV_ROUTER_MIDIClockInGet(port) == 1 )
455
    SEQ_BPM_NotifyMIDIRx(midi_byte);
1298 tk 456
 
1408 tk 457
  // TODO: better port filtering!
458
  if( port < USB1 || port >= UART0 ) {
459
    if( midi_byte >= 0xf8 ) {
460
      mbCvEnvironment.midiReceiveRealTimeEvent(port, midi_byte);
461
    }
462
  }
463
 
1298 tk 464
  return 0; // no error, no filtering
465
}
466
 
1299 tk 467
/////////////////////////////////////////////////////////////////////////////
468
// Installed via MIOS32_MIDI_DirectTxCallback_Init
469
/////////////////////////////////////////////////////////////////////////////
470
static s32 NOTIFY_MIDI_Tx(mios32_midi_port_t port, mios32_midi_package_t package)
471
{
472
  return MBCV_PORT_NotifyMIDITx(port, package);
473
}
1298 tk 474
 
475
/////////////////////////////////////////////////////////////////////////////
1299 tk 476
// Installed via MIOS32_MIDI_TimeoutCallback_Init
477
/////////////////////////////////////////////////////////////////////////////
478
static s32 NOTIFY_MIDI_TimeOut(mios32_midi_port_t port)
479
{  
480
  // forward to SysEx parser
481
  MBCV_SYSEX_TimeOut(port);
482
 
483
  // print message on screen
484
  SCS_Msg(SCS_MSG_L, 2000, "MIDI Protocol", "TIMEOUT !!!");
485
 
486
  return 0;
487
}
488
 
489
 
490
/////////////////////////////////////////////////////////////////////////////
1334 tk 491
// For performance Measurements
1298 tk 492
/////////////////////////////////////////////////////////////////////////////
1334 tk 493
s32 APP_StopwatchInit(void)
1298 tk 494
{
1334 tk 495
  stopwatch_value = 0;
496
  stopwatch_value_max = 0;
497
  stopwatch_value_accumulated = 0;
498
  return MIOS32_STOPWATCH_Init(1); // 1 uS resolution
1298 tk 499
}
500
 
1334 tk 501
s32 APP_StopwatchReset(void)
1298 tk 502
{
1334 tk 503
  return MIOS32_STOPWATCH_Reset();
1298 tk 504
}
505
 
1334 tk 506
s32 APP_StopwatchCapture(void)
1298 tk 507
{
1334 tk 508
  u32 value = MIOS32_STOPWATCH_ValueGet();
509
  MIOS32_IRQ_Disable();
510
  stopwatch_value = value;
511
  if( value > stopwatch_value_max )
512
    stopwatch_value_max = value;
513
  stopwatch_value_accumulated += value;
514
  MIOS32_IRQ_Enable();
1298 tk 515
 
516
  return 0; // no error
517
}