Add menu and fuctions to recoder on sd microphone stream audio.
[bertos.git] / boards / sam3x-ek / examples / sam3x-ek_codec / main.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2011 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief Atmel SAM3X-EK testcase
34  *
35  * \author Stefano Fedrigo <aleph@develer.com>
36  */
37
38 #include "bitmaps.h"
39
40 #include "hw/hw_led.h"
41 #include "hw/hw_lcd.h"
42 #include "hw/hw_adc.h"
43 #include "hw/hw_sdram.h"
44 #include "hw/hw_sd.h"
45
46 #include "cfg/cfg_i2s.h"
47
48 #include <cfg/debug.h>
49
50 #include <cpu/irq.h>
51 #include <cpu/byteorder.h>
52
53 #include <drv/kbd.h>
54 #include <drv/i2c.h>
55 #include <drv/i2s.h>
56 #include <drv/sd.h>
57 #include <drv/timer.h>
58 #include <drv/lcd_hx8347.h>
59 #include <drv/adc.h>
60 #include <drv/wm8731.h>
61 #include <drv/dmac_sam3.h>
62 #include <drv/sd.h>
63
64 #include <gfx/gfx.h>
65 #include <gfx/font.h>
66 #include <gfx/text.h>
67 #include <gui/menu.h>
68 #include <icons/logo.h>
69
70 #include <io/kfile.h>
71 #include <io/kfile_block.h>
72
73 #include <kern/signal.h>
74 #include <kern/proc.h>
75 #include <kern/msg.h>
76
77 #include <fs/fat.h>
78
79 #include <algo/wav.h>
80
81 #include <struct/list.h>
82
83 #include <verstag.h>
84 #include <buildrev.h>
85
86 #include <stdio.h>
87 #include <string.h>
88
89 // Keyboard
90 #define KEY_MASK (K_LEFT | K_RIGHT)
91
92 /*
93  * Codec has 7-bit address, the eighth is the R/W bit, so we
94  * write the codec address with one bit shifted left
95  */
96 #define CODEC_ADDR 0x36
97
98 // Kernel
99 static PROC_DEFINE_STACK(play_proc_stack, 1024);
100 static PROC_DEFINE_STACK(rec_proc_stack, 1024);
101 MsgPort proc_play_inPort;
102 MsgPort proc_rec_inPort;
103
104 #define MAX_ITEM_NODES    30
105 #define MAX_ITEMS_ROW     15
106 #define NEXT_ITEM_COL     10
107
108 typedef struct FileItemNode
109 {
110         Node n;
111         char file_name[13];
112 } FileItemNode;
113
114 typedef struct AudioMsg
115 {
116         Msg msg;
117         char file_name[13];
118 } AudioMsg;
119
120 FileItemNode item_nodes[MAX_ITEM_NODES];
121
122 uint8_t tmp[4096];
123
124 // SD fat filesystem context
125 FATFS fs;
126 FatFile play_file;
127 FatFile rec_file;
128
129 static Sd sd;
130 static I2c i2c;
131 static I2s i2s;
132 static Wm8731 wm8731_ctx;
133
134 static uint8_t raster[RAST_SIZE(LCD_WIDTH, LCD_HEIGHT)];
135 static Bitmap lcd_bitmap;
136 extern Font font_gohu;
137 static int lcd_brightness = LCD_BACKLIGHT_MAX;
138 static uint16_t headphone_volume = 90;
139 static size_t played_size = 0;
140 static bool is_playing = false;
141 static bool is_recording = false;
142 static int recorderd_file_idx;
143
144 static void codec_play(struct I2s *i2s, void *_buf, size_t len)
145 {
146         played_size += kfile_read(&play_file.fd, _buf, len);
147         if (played_size >= play_file.fat_file.fsize - sizeof(WavHdr))
148         {
149                 kprintf("stop %d\n", played_size);
150                 i2s_dmaTxStop(i2s);
151                 is_playing = false;
152                 played_size = 0;
153         }
154 }
155
156 static void codec_rec(struct I2s *i2s, void *_buf, size_t len)
157 {
158         (void)i2s;
159         kfile_write(&rec_file.fd, _buf, len);
160 }
161
162 static void NORETURN play_proc(void)
163 {
164         while (1)
165         {
166                 event_wait(&proc_play_inPort.event);
167                 AudioMsg *play;
168                 play = (AudioMsg *)msg_get(&proc_play_inPort);
169                 if (play && SD_CARD_PRESENT())
170                 {
171                         timer_delay(10);
172
173                         bool sd_ok = sd_init(&sd, NULL, 0);
174                         FRESULT result;
175
176                         if (sd_ok)
177                         {
178                                 kprintf("Mount FAT filesystem.\n");
179
180                                 result = f_mount(0, &fs);
181                                 if (result != FR_OK)
182                                 {
183                                         kprintf("Mounting FAT volumes error[%d]\n", result);
184                                         sd_ok = false;
185                                 }
186
187                                 if (sd_ok)
188                                 {
189                                         result = fatfile_open(&play_file, play->file_name,  FA_OPEN_EXISTING | FA_READ);
190                                         if (result == FR_OK)
191                                         {
192                                                 kprintf("Open file: %s size %ld\n", play->file_name, play_file.fat_file.fsize);
193                                                 WavHdr wav;
194                                                 kfile_read(&play_file.fd, &wav, sizeof(WavHdr));
195                                                 if (wav_checkHdr(&wav, 1, CONFIG_CHANNEL_NUM, CONFIG_SAMPLE_FREQ, CONFIG_WORD_BIT_SIZE) != -1)
196                                                 {
197                                                         kputs("Wav file play..\n");
198
199                                                         wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, headphone_volume);
200                                                         is_playing = true;
201                                                         i2s_dmaStartTxStreaming(&i2s, tmp, sizeof(tmp), sizeof(tmp) / 4, codec_play);
202
203                                                         wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0);
204                                                 }
205
206                                                 // Flush data and close the files.
207                                                 kfile_flush(&play_file.fd);
208                                                 kfile_close(&play_file.fd);
209                                         }
210                                         else
211                                         {
212                                                 kprintf("Unable to open file: '%s' error[%d]\n", play->file_name, result);
213                                         }
214                                 }
215                                 f_mount(0, NULL);
216                         }
217                 }
218         }
219 }
220
221
222 static void NORETURN rec_proc(void)
223 {
224         while (1)
225         {
226                 event_wait(&proc_rec_inPort.event);
227                 AudioMsg *rec;
228                 rec = (AudioMsg *)msg_get(&proc_rec_inPort);
229                 if (rec && SD_CARD_PRESENT())
230                 {
231                         timer_delay(10);
232
233                         bool sd_ok = sd_init(&sd, NULL, 0);
234                         FRESULT result;
235
236                         if (sd_ok)
237                         {
238                                 kprintf("Mount FAT filesystem.\n");
239
240                                 result = f_mount(0, &fs);
241                                 if (result != FR_OK)
242                                 {
243                                         kprintf("Mounting FAT volumes error[%d]\n", result);
244                                         sd_ok = false;
245                                 }
246
247                                 if (sd_ok)
248                                 {
249                                         result = fatfile_open(&rec_file, rec->file_name,  FA_CREATE_ALWAYS | FA_WRITE);
250                                         if (result == FR_OK)
251                                         {
252                                                 kprintf("Open file: %s size %ld\n", rec->file_name, rec_file.fat_file.fsize);
253                                                 WavHdr wav;
254                                                 wav_writeHdr(&wav, 1, CONFIG_CHANNEL_NUM, CONFIG_SAMPLE_FREQ, CONFIG_WORD_BIT_SIZE);
255                                                 kfile_write(&rec_file.fd, &wav, sizeof(WavHdr));
256                                                 kputs("Rec Wav file..\n");
257                                                 is_recording = true;
258                                                 i2s_dmaStartRxStreaming(&i2s, tmp, sizeof(tmp), sizeof(tmp) / 4, codec_rec);
259
260                                                 // Flush data and close the files.
261                                                 kfile_flush(&rec_file.fd);
262                                                 kfile_close(&rec_file.fd);
263                                         }
264                                         else
265                                         {
266                                                 kprintf("Unable to open file: '%s' error[%d]\n", rec->file_name, result);
267                                         }
268                                 }
269                                 f_mount(0, NULL);
270                         }
271                 }
272         }
273 }
274
275
276 INLINE void start_play(char *file_name)
277 {
278         AudioMsg play_msg;
279         memcpy(play_msg.file_name, file_name, sizeof(play_msg.file_name));
280         msg_put(&proc_play_inPort, &play_msg.msg);
281 }
282
283 INLINE void stop_play(void)
284 {
285         i2s_dmaTxStop(&i2s);
286         played_size = 0;
287         is_playing = false;
288 }
289
290
291 INLINE void start_rec(char *file_name)
292 {
293         AudioMsg rec_msg;
294         memcpy(rec_msg.file_name, file_name, sizeof(rec_msg.file_name));
295         msg_put(&proc_rec_inPort, &rec_msg.msg);
296 }
297
298 INLINE void stop_rec(void)
299 {
300         i2s_dmaRxStop(&i2s);
301         is_recording = false;
302 }
303
304 INLINE FileItemNode *select_item(Bitmap *bm, List *file_list, int select_idx)
305 {
306         FileItemNode *item;
307         FileItemNode *select_node;
308         int col = 0;
309         int row = 0;
310
311         gfx_bitmapClear(bm);
312         select_node = (FileItemNode *)LIST_HEAD(file_list);
313     FOREACH_NODE(item, file_list)
314         {
315                 if (row > MAX_ITEMS_ROW)
316                 {
317                         row = 1;
318                         col = NEXT_ITEM_COL;
319                 }
320
321                 text_style(bm, 0, STYLEF_MASK);
322                 if (select_idx <= MAX_ITEMS_ROW)
323                 {
324                         if (row == select_idx && col == 0)
325                         {
326                                 text_style(bm, STYLEF_INVERT, STYLEF_INVERT);
327                                 select_node = item;
328                         }
329                 }
330                 else
331                 {
332                         if (row == (select_idx - MAX_ITEMS_ROW) && col == NEXT_ITEM_COL)
333                         {
334                                 text_style(bm, STYLEF_INVERT, STYLEF_INVERT);
335                                 select_node = item;
336                         }
337                 }
338
339                 text_xprintf(bm, row, col, TEXT_NORMAL, "%s", item->file_name);
340                 row++;
341         }
342
343         lcd_hx8347_blitBitmap(bm);
344
345         return select_node;
346 }
347
348 static void play_menu(Bitmap *bm)
349 {
350         List file_list;
351         LIST_INIT(&file_list);
352         int file_list_size = 0;
353         gfx_bitmapClear(bm);
354
355         memcpy (&item_nodes[0].file_name, "<- Return..", sizeof(item_nodes[0].file_name));
356         ADDTAIL(&file_list, &item_nodes[0].n);
357
358         if (SD_CARD_PRESENT())
359         {
360                 timer_delay(10);
361
362                 bool sd_ok = sd_init(&sd, NULL, 0);
363                 FRESULT result;
364
365                 if (sd_ok)
366                 {
367                         kprintf("Mount FAT filesystem.\n");
368                         result = f_mount(0, &fs);
369                         if (result != FR_OK)
370                         {
371                                 kprintf("Mounting FAT volumes error[%d]\n", result);
372                                 sd_ok = false;
373                         }
374
375                         if (sd_ok)
376                         {
377                                 FILINFO fno;
378                                 DIR dir;
379
380                                 kputs("open dir\n");
381                                 /* Open the directory */
382                                 result = f_opendir(&dir, "/");
383                                 if (result == FR_OK)
384                                 {
385                                         // First element is reserved for "return" label
386                                         for (int i = 1;; i++)
387                                         {
388                                                 /* Read a directory item */
389                                                 result = f_readdir(&dir, &fno);
390                                                 if (result != FR_OK || fno.fname[0] == 0)
391                                                         break;  /* Break on error or end of dir */
392                                                 if (fno.fname[0] == '.')
393                                                         continue; /* Ignore dot entry */
394                                                 if (fno.fattrib & AM_DIR)
395                                                         continue;
396                                                 else
397                                                 {
398                                                         if (i < MAX_ITEM_NODES)
399                                                         {
400                                                                 memcpy (&item_nodes[i].file_name, fno.fname, sizeof(item_nodes[i].file_name));
401                                                                 ADDTAIL(&file_list, &item_nodes[i].n);
402                                                                 file_list_size++;
403                                                                 kprintf("%s\n", item_nodes[i].file_name);
404                                                         }
405                                                         else
406                                                         {
407                                                                 kputs("No enought space to store items in list\n");
408                                                                 break;
409                                                         }
410                                                 }
411                                         }
412                                 }
413                         }
414                         f_mount(0, NULL);
415                         kprintf("Umount\n");
416                 }
417         }
418         else
419         {
420                 kputs("No card insert..\n");
421                 text_xprintf(bm, 5, 0, TEXT_CENTER | TEXT_FILL, "%s", "No card insert..");
422         }
423
424         int idx = 0;
425         FileItemNode *selected_node = NULL;
426         select_item(bm, &file_list, idx);
427         while (1)
428         {
429                 keymask_t key = kbd_peek();
430                 if (key & K_LEFT)
431                 {
432                         idx++;
433                         if (idx > file_list_size)
434                                 idx = 0;
435
436                         selected_node = select_item(bm, &file_list, idx);
437                 }
438                 if (key & K_RIGHT)
439                 {
440                         if (idx == 0)
441                                 break;
442
443                         if (!is_playing)
444                                 start_play(selected_node->file_name);
445                         else
446                                 stop_play();
447                 }
448
449                 cpu_relax();
450         }
451 }
452
453
454 static void rec_menu(Bitmap *bm)
455 {
456         gfx_bitmapClear(bm);
457         text_style(bm, STYLEF_BOLD | STYLEF_UNDERLINE, STYLEF_BOLD | STYLEF_UNDERLINE);
458         text_xprintf(bm, 0, 0, TEXT_CENTER | TEXT_FILL, "Microphone recorder.");
459         text_style(bm, 0, STYLEF_MASK);
460         text_xprintf(bm, 2, 0, TEXT_NORMAL, "Press RIGHT button to start recording");
461         text_xprintf(bm, 3, 0, TEXT_NORMAL, "and to stop it re-press RIGHT button.");
462         lcd_hx8347_blitBitmap(bm);
463
464         ticks_t start= 0;
465         while (1)
466         {
467                 keymask_t key = kbd_peek();
468                 if (key & K_LEFT)
469                 {
470                         break;
471                 }
472                 if (key & K_RIGHT)
473                 {
474                         char file_name[13];
475                         memset(file_name, 0, sizeof(file_name));
476                         sprintf(file_name, "REC%d.WAV", recorderd_file_idx);
477                         kprintf("rec %s\n", file_name);
478
479                         if (!is_recording)
480                         {
481                                 start_rec(file_name);
482                                 text_xprintf(bm, 5, 0, TEXT_CENTER | TEXT_FILL, "Start recording on file: %s", file_name);
483                                 lcd_hx8347_blitBitmap(bm);
484                                 start = timer_clock();
485                         }
486                         else
487                         {
488                                 stop_rec();
489                                 recorderd_file_idx++;
490                                 text_xprintf(bm, 5, 0, TEXT_CENTER | TEXT_FILL, "Stop recording: %s", file_name);
491                                 mtime_t elaps = ticks_to_ms(timer_clock() - start);
492                                 text_xprintf(bm, 6, 0, TEXT_CENTER | TEXT_FILL, "Recorded: %ld.%ldsec", elaps / 1000, elaps % 1000);
493                                 lcd_hx8347_blitBitmap(bm);
494                         }
495                 }
496
497                 cpu_relax();
498         }
499 }
500
501
502
503 /*
504  * Lcd
505  */
506 static void setBrightness(Bitmap *bm)
507 {
508         while (1)
509         {
510                 gfx_bitmapClear(bm);
511                 text_xprintf(bm, 1, 0, TEXT_FILL | TEXT_CENTER, "Brightness: %d", lcd_brightness);
512                 text_xprintf(bm, 3, 0, TEXT_FILL | TEXT_CENTER, "RIGHT key: change");
513                 text_xprintf(bm, 4, 0, TEXT_FILL | TEXT_CENTER, "LEFT  key: back  ");
514                 lcd_hx8347_blitBitmap(bm);
515
516                 keymask_t mask = kbd_get();
517
518                 if (mask & K_LEFT)
519                         break;
520                 else if (mask & K_RIGHT)
521                 {
522                         if (++lcd_brightness > LCD_BACKLIGHT_MAX)
523                                 lcd_brightness = 0;
524                         lcd_setBacklight(lcd_brightness);
525                 }
526         }
527 }
528
529 static void setVolume(Bitmap *bm)
530 {
531         gfx_bitmapClear(bm);
532         text_style(bm, STYLEF_BOLD | STYLEF_UNDERLINE, STYLEF_BOLD | STYLEF_UNDERLINE);
533         text_xprintf(bm, 0, 0, TEXT_CENTER, "Headphone Volume");
534         text_style(bm, 0, STYLEF_MASK);
535         text_xprintf(bm, 2, 0, TEXT_NORMAL, "Turn VR1 potentiometer to adjust it.");
536
537         while (1)
538         {
539                 headphone_volume = ADC_RANGECONV(adc_read(1), 0, 100);
540                 text_xprintf(bm, 5, 0, TEXT_FILL | TEXT_CENTER, "Volume %d%%", headphone_volume);
541                 lcd_hx8347_blitBitmap(bm);
542
543                 timer_delay(400);
544                 if (kbd_peek() & KEY_MASK)
545                         break;
546         }
547 }
548
549 static void NORETURN soft_reset(Bitmap * bm)
550 {
551         int i;
552
553         gfx_bitmapClear(bm);
554         for (i = 5; i; --i)
555         {
556                 text_xprintf(bm, 2, 0, TEXT_FILL | TEXT_CENTER, "%d", i);
557                 lcd_hx8347_blitBitmap(bm);
558                 timer_delay(1000);
559         }
560         text_xprintf(bm, 2, 0, TEXT_FILL | TEXT_CENTER, "REBOOT");
561         lcd_hx8347_blitBitmap(bm);
562         timer_delay(1000);
563
564         /* Perform a software reset request */
565         HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ;
566         UNREACHABLE();
567 }
568
569
570 static struct MenuItem main_items[] =
571 {
572         { (const_iptr_t)"Play SD file",       0, (MenuHook)play_menu,     (iptr_t)&lcd_bitmap },
573         { (const_iptr_t)"Record file on SD",  0, (MenuHook)rec_menu,      (iptr_t)&lcd_bitmap },
574         { (const_iptr_t)"Set brightness",     0, (MenuHook)setBrightness, (iptr_t)&lcd_bitmap },
575         { (const_iptr_t)"Set volume",         0, (MenuHook)setVolume,     (iptr_t)&lcd_bitmap },
576         { (const_iptr_t)"Reboot",             0, (MenuHook)soft_reset,    (iptr_t)&lcd_bitmap },
577         { (const_iptr_t)0,                    0, NULL,                    (iptr_t)0   }
578 };
579 static struct Menu main_menu = { main_items, "BeRTOS", MF_STICKY | MF_SAVESEL, &lcd_bitmap, 0, lcd_hx8347_blitBitmap };
580
581
582 int main(void)
583 {
584         IRQ_ENABLE;
585         kdbg_init();
586
587         LED_INIT();
588         timer_init();
589
590         proc_init();
591         sdram_init();
592         adc_init();
593
594         kprintf("sam3x %s: %d times\n", VERS_HOST, VERS_BUILD);
595
596         dmac_init();
597         i2c_init(&i2c, I2C_BITBANG0, CONFIG_I2C_FREQ);
598         i2s_init(&i2s, SSC0);
599
600         wm8731_init(&wm8731_ctx, &i2c, CODEC_ADDR);
601         wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0);
602
603         kprintf("CPU Frequecy:%ld\n", CPU_FREQ);
604
605         lcd_hx8347_init();
606         lcd_setBacklight(lcd_brightness);
607
608         gfx_bitmapInit(&lcd_bitmap, raster, LCD_WIDTH, LCD_HEIGHT);
609         gfx_setFont(&lcd_bitmap, &font_luBS14);
610         lcd_hx8347_blitBitmap(&lcd_bitmap);
611
612         kbd_init();
613
614         proc_new(play_proc, NULL, sizeof(play_proc_stack), play_proc_stack);
615         proc_new(rec_proc, NULL, sizeof(rec_proc_stack), rec_proc_stack);
616         msg_initPort(&proc_play_inPort, event_createGeneric());
617         msg_initPort(&proc_rec_inPort, event_createGeneric());
618
619         lcd_hx8347_blitBitmap24(10, 52, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, bmp_logo);
620         timer_delay(500);
621
622
623         while (1)
624         {
625                 menu_handle(&main_menu);
626                 cpu_relax();
627         }
628
629 }