Subversion Repositories svn.mios32

Rev

Rev 1299 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1298 tk 1
// $Id: app.c 1298 2011-08-16 22:41:29Z 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 <msd.h>
20
#include <aout.h>
21
#include "app.h"
22
#include "tasks.h"
23
 
24
#include "mbcv_sysex.h"
25
#include "mbcv_patch.h"
26
#include "mbcv_router.h"
27
#include "mbcv_port.h"
28
 
29
// include source of the SCS
30
#include <scs.h>
31
#include "scs_config.h"
32
 
33
#include "file.h"
34
#include "mbcv_file.h"
35
#include "mbcv_file_p.h"
36
 
37
#include <seq_bpm.h>
38
#include <seq_midi_out.h>
39
 
40
#include "terminal.h"
41
#include "midimon.h"
42
 
43
#include "uip_task.h"
44
#include "osc_client.h"
45
 
46
 
47
// define priority level for sequencer
48
// use same priority as MIOS32 specific tasks
49
#define PRIORITY_TASK_PERIOD_1mS ( tskIDLE_PRIORITY + 3 )
50
 
51
// local prototype of the task function
52
static void TASK_Period_1mS(void *pvParameters);
53
 
54
// define priority level for control surface handler
55
// use lower priority as MIOS32 specific tasks (2), so that slow LCDs don't affect overall performance
56
#define PRIORITY_TASK_PERIOD_1mS_LP ( tskIDLE_PRIORITY + 2 )
57
 
58
// SD Card with lower priority
59
#define PRIORITY_TASK_PERIOD_1mS_SD ( tskIDLE_PRIORITY + 2 )
60
 
61
// local prototype of the task function
62
static void TASK_Period_1mS_LP(void *pvParameters);
63
static void TASK_Period_1mS_SD(void *pvParameters);
64
 
65
/////////////////////////////////////////////////////////////////////////////
66
// Local types
67
/////////////////////////////////////////////////////////////////////////////
68
 
69
typedef enum {
70
  MSD_DISABLED,
71
  MSD_INIT,
72
  MSD_READY,
73
  MSD_SHUTDOWN
74
} msd_state_t;
75
 
76
 
77
/////////////////////////////////////////////////////////////////////////////
78
// local variables
79
/////////////////////////////////////////////////////////////////////////////
80
static u8 hw_enabled;
81
 
82
// for mutual exclusive SD Card access between different tasks
83
// The mutex is handled with MUTEX_SDCARD_TAKE and MUTEX_SDCARD_GIVE
84
// macros inside the application, which contain a different implementation 
85
// for emulation
86
xSemaphoreHandle xSDCardSemaphore;
87
 
88
// Mutex for MIDI IN/OUT handler
89
xSemaphoreHandle xMIDIINSemaphore;
90
xSemaphoreHandle xMIDIOUTSemaphore;
91
 
92
 
93
static u32 ms_counter;
94
 
95
static msd_state_t msd_state;
96
 
97
 
98
/////////////////////////////////////////////////////////////////////////////
99
// Local prototypes
100
/////////////////////////////////////////////////////////////////////////////
101
static void APP_Periodic_100uS(void);
102
static s32 NOTIFY_MIDI_Rx(mios32_midi_port_t port, u8 byte);
103
 
104
 
105
 
106
/////////////////////////////////////////////////////////////////////////////
107
// This hook is called after startup to initialize the application
108
/////////////////////////////////////////////////////////////////////////////
109
void APP_Init(void)
110
{
111
  // initialize all LEDs
112
  MIOS32_BOARD_LED_Init(0xffffffff);
113
 
114
  // disable MSD by default (has to be enabled in SEQ_UI_FILE menu)
115
  msd_state = MSD_DISABLED;
116
 
117
  // hardware will be enabled once configuration has been loaded from SD Card
118
  // (resp. no SD Card is available)
119
  hw_enabled = 0;
120
 
121
  // initialize all J10 pins as inputs with internal Pull-Up
122
  int pin;
123
  for(pin=0; pin<8; ++pin)
124
    MIOS32_BOARD_J10_PinInit(pin, MIOS32_BOARD_PIN_MODE_INPUT_PU);
125
 
126
 
127
  // create semaphores
128
  xSDCardSemaphore = xSemaphoreCreateRecursiveMutex();
129
  xMIDIINSemaphore = xSemaphoreCreateRecursiveMutex();
130
  xMIDIOUTSemaphore = xSemaphoreCreateRecursiveMutex();
131
 
132
  // install SysEx callback
133
  MIOS32_MIDI_SysExCallback_Init(APP_SYSEX_Parser);
134
 
135
  // install MIDI Rx callback function
136
  MIOS32_MIDI_DirectRxCallback_Init(NOTIFY_MIDI_Rx);
137
 
138
  // initialize code modules
139
  MBCV_PORT_Init(0);
140
  MBCV_SYSEX_Init(0);
141
  MBCV_ROUTER_Init(0);
142
  MBCV_PATCH_Init(0);
143
  UIP_TASK_Init(0);
144
  SCS_Init(0);
145
  SCS_CONFIG_Init(0);
146
  TERMINAL_Init(0);
147
  MIDIMON_Init(0);
148
  MBCV_FILE_Init(0);
149
  SEQ_MIDI_OUT_Init(0);
150
 
151
  // initialize AOUT module
152
  AOUT_Init(0);
153
 
154
  // configure interface (will be changed again once config file has been loaded from SD Card, or via SCS)
155
  aout_config_t config;
156
  config = AOUT_ConfigGet();
157
  config.if_type = AOUT_IF_MAX525;
158
  config.if_option = 0;
159
  config.num_channels = 8;
160
  config.chn_inverted = 0;
161
  AOUT_ConfigSet(config);
162
  AOUT_IF_Init(0);
163
 
164
  // install timer function which is called each 100 uS
165
  MIOS32_TIMER_Init(1, 100, APP_Periodic_100uS, MIOS32_IRQ_PRIO_MID);
166
 
167
  // start tasks
168
  xTaskCreate(TASK_Period_1mS, (signed portCHAR *)"1mS", configMINIMAL_STACK_SIZE, NULL, PRIORITY_TASK_PERIOD_1mS, NULL);
169
  xTaskCreate(TASK_Period_1mS_LP, (signed portCHAR *)"1mS_LP", 2*configMINIMAL_STACK_SIZE, NULL, PRIORITY_TASK_PERIOD_1mS_LP, NULL);
170
  xTaskCreate(TASK_Period_1mS_SD, (signed portCHAR *)"1mS_SD", 2*configMINIMAL_STACK_SIZE, NULL, PRIORITY_TASK_PERIOD_1mS_SD, NULL);
171
 
172
}
173
 
174
 
175
/////////////////////////////////////////////////////////////////////////////
176
// This task is running endless in background
177
/////////////////////////////////////////////////////////////////////////////
178
void APP_Background(void)
179
{
180
  // endless loop
181
  while( 1 ) {
182
    // toggle the state of all LEDs (allows to measure the execution speed with a scope)
183
    MIOS32_BOARD_LED_Set(0xffffffff, ~MIOS32_BOARD_LED_Get());
184
  }
185
}
186
 
187
 
188
/////////////////////////////////////////////////////////////////////////////
189
// This hook is called when a MIDI package has been received
190
/////////////////////////////////////////////////////////////////////////////
191
void APP_MIDI_NotifyPackage(mios32_midi_port_t port, mios32_midi_package_t midi_package)
192
{
193
  // -> MIDI Router
194
  MBCV_ROUTER_Receive(port, midi_package);
195
 
196
  // forward to MIDI Monitor
197
  // SysEx messages have to be filtered for USB0 and UART0 to avoid data corruption
198
  // (the SysEx stream would interfere with monitor messages)
199
  u8 filter_sysex_message = (port == USB0) || (port == UART0);
200
  MIDIMON_Receive(port, midi_package, ms_counter, filter_sysex_message);
201
}
202
 
203
/////////////////////////////////////////////////////////////////////////////
204
// This function parses an incoming sysex stream for MIOS32 commands
205
/////////////////////////////////////////////////////////////////////////////
206
s32 APP_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in)
207
{
208
  // -> MBCV
209
  MBCV_SYSEX_Parser(port, midi_in);
210
 
211
  // -> MIDI Router
212
  MBCV_ROUTER_ReceiveSysEx(port, midi_in);
213
 
214
  return 0; // no error
215
}
216
 
217
/////////////////////////////////////////////////////////////////////////////
218
// This hook is called before the shift register chain is scanned
219
/////////////////////////////////////////////////////////////////////////////
220
void APP_SRIO_ServicePrepare(void)
221
{
222
  // pass current pin state of J10
223
  // only available for LPC17xx, all others (like STM32) default to SRIO
224
  SCS_AllPinsSet(0xff00 | MIOS32_BOARD_J10_Get());
225
 
226
  // update encoders/buttons of SCS
227
  SCS_EncButtonUpdate_Tick();
228
}
229
 
230
 
231
/////////////////////////////////////////////////////////////////////////////
232
// This hook is called after the shift register chain has been scanned
233
/////////////////////////////////////////////////////////////////////////////
234
void APP_SRIO_ServiceFinish(void)
235
{
236
}
237
 
238
 
239
/////////////////////////////////////////////////////////////////////////////
240
// This hook is called when a button has been toggled
241
// pin_value is 1 when button released, and 0 when button pressed
242
/////////////////////////////////////////////////////////////////////////////
243
void APP_DIN_NotifyToggle(u32 pin, u32 pin_value)
244
{
245
}
246
 
247
 
248
/////////////////////////////////////////////////////////////////////////////
249
// This hook is called when an encoder has been moved
250
// incrementer is positive when encoder has been turned clockwise, else
251
// it is negative
252
/////////////////////////////////////////////////////////////////////////////
253
void APP_ENC_NotifyChange(u32 encoder, s32 incrementer)
254
{
255
  // pass encoder event to SCS handler
256
  if( encoder == SCS_ENC_MENU_ID )
257
    SCS_ENC_MENU_NotifyChange(incrementer);
258
}
259
 
260
 
261
/////////////////////////////////////////////////////////////////////////////
262
// This hook is called when a pot has been moved
263
/////////////////////////////////////////////////////////////////////////////
264
void APP_AIN_NotifyChange(u32 pin, u32 pin_value)
265
{
266
}
267
 
268
 
269
 
270
 
271
/////////////////////////////////////////////////////////////////////////////
272
// This task handles the control surface
273
/////////////////////////////////////////////////////////////////////////////
274
static void TASK_Period_1mS_LP(void *pvParameters)
275
{
276
  MIOS32_LCD_Clear();
277
 
278
  while( 1 ) {
279
    vTaskDelay(1 / portTICK_RATE_MS);
280
 
281
    // call SCS handler
282
    SCS_Tick();
283
 
284
  }
285
 
286
}
287
 
288
 
289
/////////////////////////////////////////////////////////////////////////////
290
// This task handles the SD Card
291
/////////////////////////////////////////////////////////////////////////////
292
static void TASK_Period_1mS_SD(void *pvParameters)
293
{
294
  u16 sdcard_check_ctr = 0;
295
  u8 lun_available = 0;
296
 
297
  while( 1 ) {
298
    vTaskDelay(1 / portTICK_RATE_MS);
299
 
300
    // each second: check if SD Card (still) available
301
    if( ++sdcard_check_ctr >= 1000 ) {
302
      sdcard_check_ctr = 0;
303
 
304
      MUTEX_SDCARD_TAKE;
305
      s32 status = FILE_CheckSDCard();
306
 
307
      hw_enabled = 1; // enable hardware after first read...
308
 
309
      if( status == 1 ) {
310
    DEBUG_MSG("SD Card connected: %s\n", FILE_VolumeLabel());
311
    // load all file infos
312
    MBCV_FILE_LoadAllFiles(1); // including HW info
313
      } else if( status == 2 ) {
314
    DEBUG_MSG("SD Card disconnected\n");
315
    // invalidate all file infos
316
    MBCV_FILE_UnloadAllFiles();
317
 
318
    // change status
319
    MBCV_FILE_StatusMsgSet("No SD Card");
320
      } else if( status == 3 ) {
321
    if( !FILE_SDCardAvailable() ) {
322
      DEBUG_MSG("SD Card not found\n");
323
      MBCV_FILE_StatusMsgSet("No SD Card");
324
    } else if( !FILE_VolumeAvailable() ) {
325
      DEBUG_MSG("ERROR: SD Card contains invalid FAT!\n");
326
      MBCV_FILE_StatusMsgSet("No FAT");
327
    } else {
328
      // check if patch file exists
329
      if( !MBCV_FILE_P_Valid() ) {
330
        // create new one
331
        DEBUG_MSG("Creating initial DEFAULT.CV2 file\n");
332
 
333
        if( (status=MBCV_FILE_P_Write("DEFAULT")) < 0 ) {
334
          DEBUG_MSG("Failed to create file! (status: %d)\n", status);
335
        }
336
      }
337
 
338
      // disable status message and print patch
339
      MBCV_FILE_StatusMsgSet(NULL);
340
    }
341
      }
342
 
343
      MUTEX_SDCARD_GIVE;
344
    }
345
 
346
    // MSD driver
347
    if( msd_state != MSD_DISABLED ) {
348
      MUTEX_SDCARD_TAKE;
349
 
350
      switch( msd_state ) {
351
      case MSD_SHUTDOWN:
352
    // switch back to USB MIDI
353
    MIOS32_USB_Init(1);
354
    msd_state = MSD_DISABLED;
355
    break;
356
 
357
      case MSD_INIT:
358
    // LUN not mounted yet
359
    lun_available = 0;
360
 
361
    // enable MSD USB driver
362
    //MUTEX_J16_TAKE;
363
    if( MSD_Init(0) >= 0 )
364
      msd_state = MSD_READY;
365
    else
366
      msd_state = MSD_SHUTDOWN;
367
    //MUTEX_J16_GIVE;
368
    break;
369
 
370
      case MSD_READY:
371
    // service MSD USB driver
372
    MSD_Periodic_mS();
373
 
374
    // this mechanism shuts down the MSD driver if SD card has been unmounted by OS
375
    if( lun_available && !MSD_LUN_AvailableGet(0) )
376
      msd_state = MSD_SHUTDOWN;
377
    else if( !lun_available && MSD_LUN_AvailableGet(0) )
378
      lun_available = 1;
379
    break;
380
      }
381
 
382
      MUTEX_SDCARD_GIVE;
383
    }
384
  }
385
 
386
}
387
 
388
 
389
/////////////////////////////////////////////////////////////////////////////
390
// This task is called periodically each mS to handle AOUTs
391
/////////////////////////////////////////////////////////////////////////////
392
static void TASK_Period_1mS(void *pvParameters)
393
{
394
  portTickType xLastExecutionTime;
395
 
396
  // Initialise the xLastExecutionTime variable on task entry
397
  xLastExecutionTime = xTaskGetTickCount();
398
 
399
  while( 1 ) {
400
    vTaskDelayUntil(&xLastExecutionTime, 1 / portTICK_RATE_MS);
401
 
402
    // skip delay gap if we had to wait for more than 5 ticks to avoid 
403
    // unnecessary repeats until xLastExecutionTime reached xTaskGetTickCount() again
404
    portTickType xCurrentTickCount = xTaskGetTickCount();
405
    if( xLastExecutionTime < (xCurrentTickCount-5) )
406
      xLastExecutionTime = xCurrentTickCount;
407
 
408
    if( hw_enabled ) {
409
      // update AOUT channels
410
      AOUT_Update();
411
    }
412
  }
413
}
414
 
415
 
416
/////////////////////////////////////////////////////////////////////////////
417
// This timer function is periodically called each 100 uS
418
/////////////////////////////////////////////////////////////////////////////
419
static void APP_Periodic_100uS(void)
420
{
421
  static u8 pre_ctr = 0;
422
 
423
  // increment the microsecond counter each 10th tick
424
  if( ++pre_ctr >= 10 ) {
425
    pre_ctr = 0;
426
    ++ms_counter;
427
  }
428
 
429
  // here we could do some additional high-prio jobs
430
  // (e.g. PWM LEDs)
431
}
432
 
433
/////////////////////////////////////////////////////////////////////////////
434
// Installed via MIOS32_MIDI_DirectRxCallback_Init
435
/////////////////////////////////////////////////////////////////////////////
436
static s32 NOTIFY_MIDI_Rx(mios32_midi_port_t port, u8 midi_byte)
437
{
438
  // here we could filter a certain port
439
  // The BPM generator will deliver inaccurate results if MIDI clock 
440
  // is received from multiple ports
441
  SEQ_BPM_NotifyMIDIRx(midi_byte);
442
 
443
  return 0; // no error, no filtering
444
}
445
 
446
 
447
/////////////////////////////////////////////////////////////////////////////
448
// MSD access functions
449
/////////////////////////////////////////////////////////////////////////////
450
s32 TASK_MSD_EnableSet(u8 enable)
451
{
452
  MIOS32_IRQ_Disable();
453
  if( msd_state == MSD_DISABLED && enable ) {
454
    msd_state = MSD_INIT;
455
  } else if( msd_state == MSD_READY && !enable )
456
    msd_state = MSD_SHUTDOWN;
457
  MIOS32_IRQ_Enable();
458
 
459
  return 0; // no error
460
}
461
 
462
s32 TASK_MSD_EnableGet()
463
{
464
  return (msd_state == MSD_READY) ? 1 : 0;
465
}
466
 
467
s32 TASK_MSD_FlagStrGet(char str[5])
468
{
469
  str[0] = MSD_CheckAvailable() ? 'U' : '-';
470
  str[1] = MSD_LUN_AvailableGet(0) ? 'M' : '-';
471
  str[2] = MSD_RdLEDGet(250) ? 'R' : '-';
472
  str[3] = MSD_WrLEDGet(250) ? 'W' : '-';
473
  str[4] = 0;
474
 
475
  return 0; // no error
476
}