Subversion Repositories svn.mios32

Rev

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