Subversion Repositories svn.mios32

Rev

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