Subversion Repositories svn.mios32

Rev

Rev 1118 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1089 tk 1
// $Id: app.c 1932 2014-01-15 22:25:13Z tk $
2
/*
3
 * Clock Accuracy Tester
4
 * See README.txt for details
5
 *
6
 * ==========================================================================
7
 *
8
 *  Copyright (C) 2010 Thorsten Klose (tk@midibox.org)
9
 *  Licensed for personal non-commercial use only.
10
 *  All other rights reserved.
11
 *
12
 * ==========================================================================
13
 */
14
 
15
/////////////////////////////////////////////////////////////////////////////
16
// Include files
17
/////////////////////////////////////////////////////////////////////////////
18
 
19
#include <mios32.h>
20
#include <string.h>
21
#include "app.h"
22
 
23
 
24
/////////////////////////////////////////////////////////////////////////////
25
// Local defines
26
/////////////////////////////////////////////////////////////////////////////
27
#define STRING_MAX 80
28
 
29
 
30
/////////////////////////////////////////////////////////////////////////////
31
// Local types
32
/////////////////////////////////////////////////////////////////////////////
33
 
34
typedef struct {
35
  u32 timestamp_last;
36
  u32 delay_last;
37
  u32 delay_min;
38
  u32 delay_max;
39
} delay_t;
40
 
41
 
42
/////////////////////////////////////////////////////////////////////////////
43
// Local prototypes
44
/////////////////////////////////////////////////////////////////////////////
45
 
46
static s32 DelayInit(delay_t* d, u8 including_min_max);
47
static s32 DelayUpdate(delay_t* d, u32 timestamp);
48
 
49
static s32 CONSOLE_Parse(mios32_midi_port_t port, u8 byte);
50
 
51
static s32 NOTIFY_MIDI_Rx(mios32_midi_port_t port, u8 byte);
52
 
53
 
54
/////////////////////////////////////////////////////////////////////////////
55
// Local variables
56
/////////////////////////////////////////////////////////////////////////////
57
 
58
static u32 timestamp_midi_start;
59
 
60
static delay_t d_tick;
61
static delay_t d_beat;
62
static delay_t d_measure;
63
 
64
static u32 total_delay;
65
static u32 midi_clock_ctr;
66
 
67
static volatile u8 print_message; // notifier
68
 
1118 tk 69
static char line_buffer[STRING_MAX];
1089 tk 70
static u16 line_ix;
71
 
72
/////////////////////////////////////////////////////////////////////////////
73
// This hook is called after startup to initialize the application
74
/////////////////////////////////////////////////////////////////////////////
75
void APP_Init(void)
76
{
77
  // initialize all LEDs
78
  MIOS32_BOARD_LED_Init(0xffffffff);
79
 
80
  // install MIDI Rx callback function
81
  MIOS32_MIDI_DirectRxCallback_Init(&NOTIFY_MIDI_Rx);
82
 
83
  // print welcome message on MIOS terminal
84
  MIOS32_MIDI_SendDebugMessage("\n");
85
  MIOS32_MIDI_SendDebugMessage("====================\n");
86
  MIOS32_MIDI_SendDebugMessage("%s\n", MIOS32_LCD_BOOT_MSG_LINE1);
87
  MIOS32_MIDI_SendDebugMessage("====================\n");
88
  MIOS32_MIDI_SendDebugMessage("\n");
89
  MIOS32_MIDI_SendDebugMessage("Measurement results will be displayed once a MIDI clock is received.");
90
  MIOS32_MIDI_SendDebugMessage("Type \"reset\" in MIOS terminal to reset the current measurements!");
91
 
92
  // clear line buffer
93
  line_buffer[0] = 0;
94
  line_ix = 0;
95
 
96
  // install the callback function which is called on incoming characters
97
  // from MIOS Terminal
98
  MIOS32_MIDI_DebugCommandCallback_Init(CONSOLE_Parse);
99
}
100
 
101
 
102
/////////////////////////////////////////////////////////////////////////////
103
// This task is running endless in background
104
/////////////////////////////////////////////////////////////////////////////
105
void APP_Background(void)
106
{
107
  // clear LCD screen
108
  MIOS32_LCD_Clear();
109
 
110
  MIOS32_LCD_CursorSet(0, 0);
111
  MIOS32_LCD_PrintString("see README.txt   ");
112
  MIOS32_LCD_CursorSet(0, 1);
113
  MIOS32_LCD_PrintString("for details     ");
114
 
115
  // send delay min/max changes to MIOS terminal
116
  while( 1 ) {
117
    if( print_message ) {
118
      MIOS32_IRQ_Disable();
119
      u32 c_total_delay = total_delay;
120
      u32 c_midi_clock_ctr = midi_clock_ctr;
121
      delay_t c_d_tick = d_tick;
122
      delay_t c_d_beat = d_beat;
123
      print_message = 0;
124
      MIOS32_IRQ_Enable();
125
 
126
      u32 bpm = 60000000 / c_d_beat.delay_last;
127
      u32 avg = c_midi_clock_ctr ? (c_total_delay / c_midi_clock_ctr) : 0;
128
 
129
      MIOS32_MIDI_SendDebugMessage("BPM %d.%d  -  tick min/avg/max = %d.%03d/%d.%03d/%d.%03d\n",
130
                   bpm / 1000, bpm % 1000,
131
                   c_d_tick.delay_min / 1000, c_d_tick.delay_min % 1000,
132
                   avg / 1000, avg % 1000,
133
                   c_d_tick.delay_max / 1000, c_d_tick.delay_max % 1000);
1932 tk 134
 
135
      MIOS32_LCD_Clear();
136
      MIOS32_LCD_CursorSet(0, 0);
137
      MIOS32_LCD_PrintFormattedString("  BPM    Min    Avg    Max     ");
138
      MIOS32_LCD_CursorSet(0, 1);
139
      MIOS32_LCD_PrintFormattedString("%3d.%03d %2d.%03d %2d.%03d %2d.%03d",
140
                      bpm / 1000, bpm % 1000,
141
                      c_d_tick.delay_min / 1000, c_d_tick.delay_min % 1000,
142
                      avg / 1000, avg % 1000,
143
                      c_d_tick.delay_max / 1000, c_d_tick.delay_max % 1000);
1089 tk 144
    }
145
  }
146
}
147
 
148
 
149
/////////////////////////////////////////////////////////////////////////////
150
// This hook is called when a MIDI package has been received
151
/////////////////////////////////////////////////////////////////////////////
152
void APP_MIDI_NotifyPackage(mios32_midi_port_t port, mios32_midi_package_t midi_package)
153
{
154
}
155
 
156
 
157
/////////////////////////////////////////////////////////////////////////////
158
// This hook is called before the shift register chain is scanned
159
/////////////////////////////////////////////////////////////////////////////
160
void APP_SRIO_ServicePrepare(void)
161
{
162
}
163
 
164
 
165
/////////////////////////////////////////////////////////////////////////////
166
// This hook is called after the shift register chain has been scanned
167
/////////////////////////////////////////////////////////////////////////////
168
void APP_SRIO_ServiceFinish(void)
169
{
170
}
171
 
172
 
173
/////////////////////////////////////////////////////////////////////////////
174
// This hook is called when a button has been toggled
175
// pin_value is 1 when button released, and 0 when button pressed
176
/////////////////////////////////////////////////////////////////////////////
177
void APP_DIN_NotifyToggle(u32 pin, u32 pin_value)
178
{
179
}
180
 
181
 
182
/////////////////////////////////////////////////////////////////////////////
183
// This hook is called when an encoder has been moved
184
// incrementer is positive when encoder has been turned clockwise, else
185
// it is negative
186
/////////////////////////////////////////////////////////////////////////////
187
void APP_ENC_NotifyChange(u32 encoder, s32 incrementer)
188
{
189
}
190
 
191
 
192
/////////////////////////////////////////////////////////////////////////////
193
// This hook is called when a pot has been moved
194
/////////////////////////////////////////////////////////////////////////////
195
void APP_AIN_NotifyChange(u32 pin, u32 pin_value)
196
{
197
}
198
 
199
 
200
/////////////////////////////////////////////////////////////////////////////
201
// Parser
202
/////////////////////////////////////////////////////////////////////////////
203
s32 CONSOLE_Parse(mios32_midi_port_t port, u8 byte)
204
{
205
  // temporary change debug port (will be restored at the end of this function)
206
  mios32_midi_port_t prev_debug_port = MIOS32_MIDI_DebugPortGet();
207
  MIOS32_MIDI_DebugPortSet(port);
208
 
209
  if( byte == '\r' ) {
210
    // ignore
211
  } else if( byte == '\n' ) {
212
    // example for parsing the command:
213
    char *separators = " \t";
214
    char *brkt;
215
    char *parameter;
216
 
1118 tk 217
    if( (parameter = strtok_r(line_buffer, separators, &brkt)) ) {
1089 tk 218
      if( strcmp(parameter, "help") == 0 ) {
219
    MIOS32_MIDI_SendDebugMessage("Welcome to " MIOS32_LCD_BOOT_MSG_LINE1 "!");
220
    MIOS32_MIDI_SendDebugMessage("Following commands are available:");
221
    MIOS32_MIDI_SendDebugMessage("  reset:          clears the current measurements\n");
222
    MIOS32_MIDI_SendDebugMessage("  help:           this page\n");
223
      } else if( strcmp(parameter, "reset") == 0 ) {
224
    MIOS32_IRQ_Disable();
225
    u8 including_min_max = 1;
226
    DelayInit(&d_tick, including_min_max);
227
    DelayInit(&d_measure, including_min_max);
228
    DelayInit(&d_beat, including_min_max);
229
    midi_clock_ctr = 0;
230
    total_delay = 0;
231
    MIOS32_IRQ_Enable();
232
 
233
    MIOS32_MIDI_SendDebugMessage("Measurements have been cleared!\n");
234
      } else {
235
    MIOS32_MIDI_SendDebugMessage("Unknown command - type 'help' to list available commands!\n");
236
      }
237
    }
238
 
239
    line_ix = 0;
240
 
241
  } else if( line_ix < (STRING_MAX-1) ) {
242
    line_buffer[line_ix++] = byte;
243
    line_buffer[line_ix] = 0;
244
  }
245
 
246
  // restore debug port
247
  MIOS32_MIDI_DebugPortSet(prev_debug_port);
248
 
249
  return 0; // no error
250
}
251
 
252
 
253
/////////////////////////////////////////////////////////////////////////////
254
// Delay Handlers
255
/////////////////////////////////////////////////////////////////////////////
256
static s32 DelayInit(delay_t* d, u8 including_min_max)
257
{
258
  d->timestamp_last = 0;
259
  d->delay_last = 0;
260
 
261
  if( including_min_max ) {
262
    d->delay_min = 0;
263
    d->delay_max = 0;
264
  }
265
 
266
  print_message = 1;
267
 
268
  return 0; // no error
269
}
270
 
271
static s32 DelayUpdate(delay_t* d, u32 timestamp)
272
{
273
  u32 delay = 0;
274
 
275
  if( d->timestamp_last ) {
276
    delay = timestamp - d->timestamp_last;
277
 
278
    if( !d->delay_min || delay < d->delay_min ) {
279
      d->delay_min = delay;
280
      print_message = 1;
281
    }
282
 
283
    if( delay > d->delay_max ) {
284
      d->delay_max = delay;
285
      print_message = 1;
286
    }
287
 
288
    d->delay_last = delay;
289
  }
290
 
291
  d->timestamp_last = timestamp;
292
  d->delay_last = delay;
293
 
294
  return 0; // no error
295
}
296
 
297
 
298
 
299
/////////////////////////////////////////////////////////////////////////////
300
// Installed via MIOS32_MIDI_DirectRxCallback_Init
301
/////////////////////////////////////////////////////////////////////////////
302
static s32 NOTIFY_MIDI_Rx(mios32_midi_port_t port, u8 midi_byte)
303
{
304
  // check for MIDI clock
305
  if( midi_byte == 0xf8 ) {
1932 tk 306
    u32 timestamp = MIOS32_TIMESTAMP_Get();
1089 tk 307
 
308
    DelayUpdate(&d_tick, timestamp);
309
 
310
    if( (midi_clock_ctr % 24) == 0 )
311
      DelayUpdate(&d_beat, timestamp);
312
 
313
    if( (midi_clock_ctr % 96) == 0 ) {
314
      DelayUpdate(&d_measure, timestamp);
315
 
316
      // force print message with each measure
317
      print_message = 1;
318
    }
319
 
320
    ++midi_clock_ctr;
321
    total_delay += d_tick.delay_last;
322
 
323
    return 0; // no error, no filtering
324
  }
325
 
326
  // check for MIDI start or continue
327
  if( midi_byte == 0xfa || midi_byte == 0xfb ) {
1932 tk 328
    u32 timestamp = MIOS32_TIMESTAMP_Get();
1089 tk 329
 
330
    timestamp_midi_start = timestamp;
331
 
332
    u8 including_min_max = 0;
333
    DelayInit(&d_tick, including_min_max);
334
    DelayInit(&d_measure, including_min_max);
335
    DelayInit(&d_beat, including_min_max);
336
 
337
    midi_clock_ctr = 0;
338
    total_delay = 0;
339
 
340
    return 0; // no error, no filtering
341
  }
342
 
343
  // check for MIDI stop
344
  if( midi_byte == 0xfc ) {
345
    // invalidate measured delays
346
    u8 including_min_max = 0;
347
    DelayInit(&d_tick, including_min_max);
348
    DelayInit(&d_measure, including_min_max);
349
    DelayInit(&d_beat, including_min_max);
350
 
351
    return 0; // no error, no filtering
352
  }
353
 
354
  return 0; // no error, no filtering
355
}