Subversion Repositories svn.mios32

Rev

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

Rev Author Line No. Line
1260 tk 1
// $Id: app.c 1264 2011-07-19 21:59:04Z tk $
2
/*
3
 * MIDIO 128 V3
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 "app.h"
20
#include "tasks.h"
21
 
22
#include "midio_sysex.h"
23
#include "midio_patch.h"
24
#include "midio_din.h"
25
#include "midio_dout.h"
26
 
27
// include source of the SCS
28
#include <scs.h>
29
#include "scs_config.h"
30
 
1261 tk 31
#include "file.h"
1260 tk 32
#include "midio_file.h"
33
#include "midio_file_p.h"
34
 
1261 tk 35
#include <seq_bpm.h>
36
#include <seq_midi_out.h>
37
#include "seq.h"
38
#include "mid_file.h"
39
 
1260 tk 40
#include "terminal.h"
41
#include "midimon.h"
42
 
43
#include "uip_task.h"
44
#include "osc_client.h"
45
 
46
 
1261 tk 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
 
1260 tk 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
// local prototype of the task function
59
static void TASK_Period_1mS_LP(void *pvParameters);
60
 
61
 
62
/////////////////////////////////////////////////////////////////////////////
63
// local variables
64
/////////////////////////////////////////////////////////////////////////////
65
static u8 din_enabled;
66
 
67
// for mutual exclusive SD Card access between different tasks
68
// The mutex is handled with MUTEX_SDCARD_TAKE and MUTEX_SDCARD_GIVE
69
// macros inside the application, which contain a different implementation 
70
// for emulation
71
xSemaphoreHandle xSDCardSemaphore;
72
 
73
// Mutex for MIDI IN/OUT handler
74
xSemaphoreHandle xMIDIINSemaphore;
75
xSemaphoreHandle xMIDIOUTSemaphore;
76
 
77
 
78
static u32 ms_counter;
79
 
80
// SysEx buffer for each input
81
#define NUM_SYSEX_BUFFERS     6
82
#define SYSEX_BUFFER_IN_USB0  0
83
#define SYSEX_BUFFER_IN_USB1  1
84
#define SYSEX_BUFFER_IN_UART0 2
85
#define SYSEX_BUFFER_IN_UART1 3
86
#define SYSEX_BUFFER_IN_OSC0  4
87
#define SYSEX_BUFFER_IN_OSC1  5
88
 
89
#define SYSEX_BUFFER_SIZE 1024
90
static u8 sysex_buffer[NUM_SYSEX_BUFFERS][SYSEX_BUFFER_SIZE];
91
static u32 sysex_buffer_len[NUM_SYSEX_BUFFERS];
92
 
93
 
94
/////////////////////////////////////////////////////////////////////////////
95
// Local prototypes
96
/////////////////////////////////////////////////////////////////////////////
97
static void APP_Periodic_100uS(void);
1261 tk 98
static s32 NOTIFY_MIDI_Rx(mios32_midi_port_t port, u8 byte);
1260 tk 99
 
100
 
101
 
102
/////////////////////////////////////////////////////////////////////////////
103
// This hook is called after startup to initialize the application
104
/////////////////////////////////////////////////////////////////////////////
105
void APP_Init(void)
106
{
107
  // initialize all LEDs
108
  MIOS32_BOARD_LED_Init(0xffffffff);
109
 
110
  // DINs will be enabled once configuration has been loaded from SD Card
111
  // (resp. no SD Card is available)
112
  din_enabled = 0;
113
 
114
  // initialize all J10 pins as inputs with internal Pull-Up
115
  int pin;
116
  for(pin=0; pin<8; ++pin)
117
    MIOS32_BOARD_J10_PinInit(pin, MIOS32_BOARD_PIN_MODE_INPUT_PU);
118
 
119
 
120
  // create semaphores
121
  xSDCardSemaphore = xSemaphoreCreateRecursiveMutex();
122
  xMIDIINSemaphore = xSemaphoreCreateRecursiveMutex();
123
  xMIDIOUTSemaphore = xSemaphoreCreateRecursiveMutex();
124
 
125
  // clear SysEx buffers
126
  int i;
127
  for(i=0; i<NUM_SYSEX_BUFFERS; ++i)
128
    sysex_buffer_len[i] = 0;
129
 
130
  // install SysEx callback
131
  MIOS32_MIDI_SysExCallback_Init(APP_SYSEX_Parser);
132
 
1261 tk 133
  // install MIDI Rx callback function
134
  MIOS32_MIDI_DirectRxCallback_Init(NOTIFY_MIDI_Rx);
135
 
1260 tk 136
  // initialize code modules
137
  MIDIO_SYSEX_Init(0);
138
  MIDIO_PATCH_Init(0);
139
  MIDIO_DIN_Init(0);
140
  MIDIO_DOUT_Init(0);
141
  UIP_TASK_Init(0);
142
  SCS_Init(0);
143
  SCS_CONFIG_Init(0);
144
  TERMINAL_Init(0);
145
  MIDIMON_Init(0);
146
  MIDIO_FILE_Init(0);
1261 tk 147
  SEQ_MIDI_OUT_Init(0);
148
  SEQ_Init(0);
1260 tk 149
 
150
  // install timer function which is called each 100 uS
1261 tk 151
  MIOS32_TIMER_Init(1, 100, APP_Periodic_100uS, MIOS32_IRQ_PRIO_MID);
1260 tk 152
 
1261 tk 153
  // start tasks
154
  xTaskCreate(TASK_Period_1mS, (signed portCHAR *)"1mS", configMINIMAL_STACK_SIZE, NULL, PRIORITY_TASK_PERIOD_1mS, NULL);
1260 tk 155
  xTaskCreate(TASK_Period_1mS_LP, (signed portCHAR *)"1mS_LP", configMINIMAL_STACK_SIZE, NULL, PRIORITY_TASK_PERIOD_1mS_LP, NULL);
156
 
157
}
158
 
159
 
160
/////////////////////////////////////////////////////////////////////////////
161
// This task is running endless in background
162
/////////////////////////////////////////////////////////////////////////////
163
void APP_Background(void)
164
{
165
  // endless loop
166
  while( 1 ) {
167
    // toggle the state of all LEDs (allows to measure the execution speed with a scope)
168
    MIOS32_BOARD_LED_Set(0xffffffff, ~MIOS32_BOARD_LED_Get());
169
  }
170
}
171
 
172
 
173
/////////////////////////////////////////////////////////////////////////////
174
// This hook is called when a MIDI package has been received
175
/////////////////////////////////////////////////////////////////////////////
176
void APP_MIDI_NotifyPackage(mios32_midi_port_t port, mios32_midi_package_t midi_package)
177
{
178
  // -> DOUT
179
  MIDIO_DOUT_MIDI_NotifyPackage(port, midi_package);
180
 
181
  // SysEx handled by APP_SYSEX_Parser()
182
  if( midi_package.type >= 4 && midi_package.type <= 7 )
183
    return;
184
 
185
  switch( port ) {
186
  case USB0:
187
    MIOS32_MIDI_SendPackage(UART0, midi_package);
188
    OSC_CLIENT_SendMIDIEvent(0, midi_package);
189
//    led_trigger[0] = LED_PWM_PERIOD; // Board LED
190
//    led_trigger[1] = LED_PWM_PERIOD; // J5A.0
191
    break;
192
 
193
  case USB1:
194
    MIOS32_MIDI_SendPackage(UART1, midi_package);
195
    OSC_CLIENT_SendMIDIEvent(1, midi_package);
196
//    led_trigger[0] = LED_PWM_PERIOD; // Board LED
197
//    led_trigger[2] = LED_PWM_PERIOD; // J5A.1
198
    break;
199
 
200
  case UART0:
201
    MIOS32_MIDI_SendPackage(USB0, midi_package);
202
    OSC_CLIENT_SendMIDIEvent(2, midi_package);
203
//    led_trigger[0] = LED_PWM_PERIOD; // Board LED
204
//    led_trigger[3] = LED_PWM_PERIOD; // J5A.2
205
    break;
206
 
207
  case UART1:
208
    MIOS32_MIDI_SendPackage(USB1, midi_package);
209
    OSC_CLIENT_SendMIDIEvent(3, midi_package);
210
//    led_trigger[0] = LED_PWM_PERIOD; // Board LED
211
//    led_trigger[4] = LED_PWM_PERIOD; // J5A.3
212
    break;
213
  }
214
 
215
  // forward to MIDI Monitor
216
  // SysEx messages have to be filtered for USB0 and UART0 to avoid data corruption
217
  // (the SysEx stream would interfere with monitor messages)
218
  u8 filter_sysex_message = (port == USB0) || (port == UART0);
219
  MIDIMON_Receive(port, midi_package, ms_counter, filter_sysex_message);
220
}
221
 
222
/////////////////////////////////////////////////////////////////////////////
223
// This function parses an incoming sysex stream for MIOS32 commands
224
/////////////////////////////////////////////////////////////////////////////
225
s32 APP_SYSEX_Parser(mios32_midi_port_t port, u8 midi_in)
226
{
227
  // -> MIDIO
228
  MIDIO_SYSEX_Parser(port, midi_in);
229
 
230
  // determine SysEx buffer
231
  int sysex_in = 0;
232
 
233
  switch( port ) {
234
  case USB0: sysex_in = SYSEX_BUFFER_IN_USB0; break;
235
  case USB1: sysex_in = SYSEX_BUFFER_IN_USB1; break;
236
  case UART0: sysex_in = SYSEX_BUFFER_IN_UART0; break;
237
  case UART1: sysex_in = SYSEX_BUFFER_IN_UART1; break;
238
  case OSC0: sysex_in = SYSEX_BUFFER_IN_OSC0; break;
239
  case OSC1: sysex_in = SYSEX_BUFFER_IN_OSC1; break;
240
  default:
241
    return -1; // not assigned
242
  }
243
 
244
  // store value into buffer, send when:
245
  //   o 0xf7 (end of stream) has been received
246
  //   o 0xf0 (start of stream) has been received although buffer isn't empty
247
  //   o buffer size has been exceeded
248
  // we check for (SYSEX_BUFFER_SIZE-1), so that we always have a free byte for F7
249
  u32 buffer_len = sysex_buffer_len[sysex_in];
250
  if( midi_in == 0xf7 || (midi_in == 0xf0 && buffer_len != 0) || buffer_len >= (SYSEX_BUFFER_SIZE-1) ) {
251
 
252
    if( midi_in == 0xf7 && buffer_len < SYSEX_BUFFER_SIZE ) // note: we always have a free byte for F7
253
      sysex_buffer[sysex_in][sysex_buffer_len[sysex_in]++] = midi_in;
254
 
255
    switch( port ) {
256
    case USB0:
257
      MIOS32_MIDI_SendSysEx(UART0, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
258
      OSC_CLIENT_SendSysEx(0, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
259
      break;
260
    case USB1:
261
      MIOS32_MIDI_SendSysEx(UART1, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
262
      OSC_CLIENT_SendSysEx(1, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
263
      break;
264
 
265
    case UART0:
266
      MIOS32_MIDI_SendSysEx(USB0, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
267
      OSC_CLIENT_SendSysEx(2, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
268
      break;
269
    case UART1:
270
      MIOS32_MIDI_SendSysEx(USB1, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
271
      OSC_CLIENT_SendSysEx(3, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
272
      break;
273
 
274
    case OSC0:
275
      MIOS32_MIDI_SendSysEx(USB0, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
276
      MIOS32_MIDI_SendSysEx(UART0, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
277
      break;
278
    case OSC1:
279
      MIOS32_MIDI_SendSysEx(USB1, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
280
      MIOS32_MIDI_SendSysEx(UART1, sysex_buffer[sysex_in], sysex_buffer_len[sysex_in]);
281
      break;
282
    }
283
 
284
    // empty buffer
285
    sysex_buffer_len[sysex_in] = 0;
286
 
287
    // fill with next byte if buffer size hasn't been exceeded
288
    if( midi_in != 0xf7 )
289
      sysex_buffer[sysex_in][sysex_buffer_len[sysex_in]++] = midi_in;
290
 
291
  } else {
292
    // add to buffer
293
    sysex_buffer[sysex_in][sysex_buffer_len[sysex_in]++] = midi_in;
294
  }
295
 
296
  return 0; // no error
297
}
298
 
299
/////////////////////////////////////////////////////////////////////////////
300
// This hook is called before the shift register chain is scanned
301
/////////////////////////////////////////////////////////////////////////////
302
void APP_SRIO_ServicePrepare(void)
303
{
304
  // pass current pin state of J10
305
  // only available for LPC17xx, all others (like STM32) default to SRIO
306
  SCS_AllPinsSet(0xff00 | MIOS32_BOARD_J10_Get());
307
 
308
  // update encoders/buttons of SCS
309
  SCS_EncButtonUpdate_Tick();
310
}
311
 
312
 
313
/////////////////////////////////////////////////////////////////////////////
314
// This hook is called after the shift register chain has been scanned
315
/////////////////////////////////////////////////////////////////////////////
316
void APP_SRIO_ServiceFinish(void)
317
{
318
}
319
 
320
 
321
/////////////////////////////////////////////////////////////////////////////
322
// This hook is called when a button has been toggled
323
// pin_value is 1 when button released, and 0 when button pressed
324
/////////////////////////////////////////////////////////////////////////////
325
void APP_DIN_NotifyToggle(u32 pin, u32 pin_value)
326
{
327
  // -> MIDIO_DIN once enabled
328
  if( din_enabled )
329
    MIDIO_DIN_NotifyToggle(pin, pin_value);
330
}
331
 
332
 
333
/////////////////////////////////////////////////////////////////////////////
334
// This hook is called when an encoder has been moved
335
// incrementer is positive when encoder has been turned clockwise, else
336
// it is negative
337
/////////////////////////////////////////////////////////////////////////////
338
void APP_ENC_NotifyChange(u32 encoder, s32 incrementer)
339
{
340
  // pass encoder event to SCS handler
341
  if( encoder == SCS_ENC_MENU_ID )
342
    SCS_ENC_MENU_NotifyChange(incrementer);
343
}
344
 
345
 
346
/////////////////////////////////////////////////////////////////////////////
347
// This hook is called when a pot has been moved
348
/////////////////////////////////////////////////////////////////////////////
349
void APP_AIN_NotifyChange(u32 pin, u32 pin_value)
350
{
351
}
352
 
353
 
1261 tk 354
 
355
 
1260 tk 356
/////////////////////////////////////////////////////////////////////////////
357
// This task handles the control surface
358
/////////////////////////////////////////////////////////////////////////////
359
static void TASK_Period_1mS_LP(void *pvParameters)
360
{
1261 tk 361
  u16 sdcard_check_ctr = 0;
362
 
1260 tk 363
  MIOS32_LCD_Clear();
364
 
365
  while( 1 ) {
366
    vTaskDelay(1 / portTICK_RATE_MS);
367
 
368
    // call SCS handler
369
    SCS_Tick();
370
 
1261 tk 371
    // each second: check if SD Card (still) available
372
    if( ++sdcard_check_ctr >= 1000 ) {
373
      sdcard_check_ctr = 0;
1260 tk 374
 
1261 tk 375
      MUTEX_SDCARD_TAKE;
376
      s32 status = FILE_CheckSDCard();
1260 tk 377
 
1261 tk 378
      din_enabled = 1; // enable the DINs after first read...
1260 tk 379
 
1261 tk 380
      if( status == 1 ) {
381
    DEBUG_MSG("SD Card connected: %s\n", FILE_VolumeLabel());
382
    // load all file infos
383
    MIDIO_FILE_LoadAllFiles(1); // including HW info
384
      } else if( status == 2 ) {
385
    DEBUG_MSG("SD Card disconnected\n");
386
    // invalidate all file infos
387
    MIDIO_FILE_UnloadAllFiles();
388
 
389
    // stop sequencer
390
    SEQ_BPM_Stop();
391
 
392
    // change filename
393
    sprintf(MID_FILE_UI_NameGet(), "No SD Card");
394
      } else if( status == 3 ) {
395
    if( !FILE_SDCardAvailable() ) {
396
      DEBUG_MSG("SD Card not found\n");
397
      // change filename
398
      sprintf(MID_FILE_UI_NameGet(), "No SD Card");
399
    } else if( !FILE_VolumeAvailable() ) {
400
      DEBUG_MSG("ERROR: SD Card contains invalid FAT!\n");
401
      // change filename
402
      sprintf(MID_FILE_UI_NameGet(), "No FAT");
403
    } else {
404
      // check if patch file exists
405
      if( !MIDIO_FILE_P_Valid() ) {
406
        // create new one
407
        DEBUG_MSG("Creating initial MIDIO_P.V3 file\n");
408
 
1264 tk 409
        if( (status=MIDIO_FILE_P_Write("DEFAULT")) < 0 ) {
1261 tk 410
          DEBUG_MSG("Failed to create file! (status: %d)\n", status);
411
        }
1260 tk 412
      }
1261 tk 413
 
414
      // change filename
415
      sprintf(MID_FILE_UI_NameGet(), "SDCard found");
1260 tk 416
    }
1261 tk 417
 
418
    // reset sequencer
419
    SEQ_Reset(0);
1260 tk 420
      }
1261 tk 421
 
422
      MUTEX_SDCARD_GIVE;
1260 tk 423
    }
1261 tk 424
  }
1260 tk 425
 
1261 tk 426
}
427
 
428
 
429
/////////////////////////////////////////////////////////////////////////////
430
// This task is called periodically each mS to handle sequencer requests
431
/////////////////////////////////////////////////////////////////////////////
432
static void TASK_Period_1mS(void *pvParameters)
433
{
434
  portTickType xLastExecutionTime;
435
 
436
  // Initialise the xLastExecutionTime variable on task entry
437
  xLastExecutionTime = xTaskGetTickCount();
438
 
439
  while( 1 ) {
440
    vTaskDelayUntil(&xLastExecutionTime, 1 / portTICK_RATE_MS);
441
 
442
    // execute sequencer handler
443
    MUTEX_SDCARD_TAKE;
444
    SEQ_Handler();
1260 tk 445
    MUTEX_SDCARD_GIVE;
1261 tk 446
 
447
    // send timestamped MIDI events
448
    MUTEX_MIDIOUT_TAKE;
449
    SEQ_MIDI_OUT_Handler();
450
    MUTEX_MIDIOUT_GIVE;
1260 tk 451
  }
452
}
453
 
454
 
455
/////////////////////////////////////////////////////////////////////////////
456
// This timer function is periodically called each 100 uS
457
/////////////////////////////////////////////////////////////////////////////
458
static void APP_Periodic_100uS(void)
459
{
460
  static u8 pre_ctr = 0;
461
 
462
  // increment the microsecond counter each 10th tick
463
  if( ++pre_ctr >= 10 ) {
464
    pre_ctr = 0;
465
    ++ms_counter;
466
  }
467
 
468
  // here we could do some additional high-prio jobs
469
  // (e.g. PWM LEDs)
470
}
1261 tk 471
 
472
/////////////////////////////////////////////////////////////////////////////
473
// Installed via MIOS32_MIDI_DirectRxCallback_Init
474
/////////////////////////////////////////////////////////////////////////////
475
static s32 NOTIFY_MIDI_Rx(mios32_midi_port_t port, u8 midi_byte)
476
{
477
  // here we could filter a certain port
478
  // The BPM generator will deliver inaccurate results if MIDI clock 
479
  // is received from multiple ports
480
  SEQ_BPM_NotifyMIDIRx(midi_byte);
481
 
482
  return 0; // no error, no filtering
483
}