Use events to start and stop playing. Clean up and reorder the code.
[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 <string.h>
87
88 // Keyboard
89 #define KEY_MASK (K_LEFT | K_RIGHT)
90
91 /*
92  * Codec has 7-bit address, the eighth is the R/W bit, so we
93  * write the codec address with one bit shifted left
94  */
95 #define CODEC_ADDR 0x36
96
97 // Kernel
98 static PROC_DEFINE_STACK(play_proc_stack, 2048);
99 MsgPort proc_play_inPort;
100
101 #define PLAY_SIGNAL    SIG_USER3
102
103 #define MAX_ITEM_NODES    30
104 #define MAX_ITEMS_ROW     15
105 #define NEXT_ITEM_COL     10
106
107 typedef struct FileItemNode
108 {
109         Node n;
110         char file_name[13];
111 } FileItemNode;
112
113 typedef struct PlayMsg
114 {
115         Msg msg;
116         char file_name[13];
117 } PlayMsg;
118
119 FileItemNode item_nodes[MAX_ITEM_NODES];
120
121 uint8_t tmp[4096];
122
123 // SD fat filesystem context
124 FATFS fs;
125 FatFile play_file;
126 FatFile rec_file;
127
128 static Sd sd;
129 static I2c i2c;
130 static I2s i2s;
131 static Wm8731 wm8731_ctx;
132
133 static uint8_t raster[RAST_SIZE(LCD_WIDTH, LCD_HEIGHT)];
134 static Bitmap lcd_bitmap;
135 extern Font font_gohu;
136 static int lcd_brightness = LCD_BACKLIGHT_MAX;
137 static uint16_t headphone_volume = 90;
138 static size_t played_size = 0;
139 static bool is_playing = false;
140
141 static void codec_play(struct I2s *i2s, void *_buf, size_t len)
142 {
143         played_size += kfile_read(&play_file.fd, _buf, len);
144         if (played_size >= play_file.fat_file.fsize - sizeof(WavHdr))
145         {
146                 kprintf("stop %d\n", played_size);
147                 i2s_dmaTxStop(i2s);
148                 is_playing = false;
149                 played_size = 0;
150         }
151 }
152
153 static void codec_rec(struct I2s *i2s, void *_buf, size_t len)
154 {
155         played_size += kfile_write(&rec_file.fd, _buf, len);
156         if (played_size >= 1024 * 1024)
157         {
158                 kprintf("stop %d\n", played_size);
159                 i2s_dmaRxStop(i2s);
160                 played_size = 0;
161         }
162 }
163
164 static void NORETURN play_proc(void)
165 {
166         while (1)
167         {
168                 event_wait(&proc_play_inPort.event);
169                 PlayMsg *play;
170                 play = (PlayMsg *)msg_get(&proc_play_inPort);
171                 if (play && SD_CARD_PRESENT())
172                 {
173                         timer_delay(10);
174
175                         bool sd_ok = sd_init(&sd, NULL, 0);
176                         FRESULT result;
177
178                         if (sd_ok)
179                         {
180                                 kprintf("Mount FAT filesystem.\n");
181
182                                 result = f_mount(0, &fs);
183                                 if (result != FR_OK)
184                                 {
185                                         kprintf("Mounting FAT volumes error[%d]\n", result);
186                                         sd_ok = false;
187                                 }
188
189                                 if (sd_ok)
190                                 {
191                                         result = fatfile_open(&play_file, play->file_name,  FA_OPEN_EXISTING | FA_READ);
192                                         if (result == FR_OK)
193                                         {
194                                                 kprintf("Open file: %s size %ld\n", play->file_name, play_file.fat_file.fsize);
195                                                 WavHdr wav;
196                                                 kfile_read(&play_file.fd, &wav, sizeof(WavHdr));
197                                                 if (wav_checkHdr(&wav, 1, CONFIG_CHANNEL_NUM, CONFIG_SAMPLE_FREQ, CONFIG_WORD_BIT_SIZE) != -1)
198                                                 {
199                                                         kputs("Wav file play..\n");
200
201                                                         wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, headphone_volume);
202                                                         is_playing = true;
203                                                         i2s_dmaStartTxStreaming(&i2s, tmp, sizeof(tmp), sizeof(tmp) / 4, codec_play);
204
205                                                         wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0);
206                                                 }
207
208                                                 // Flush data and close the files.
209                                                 kfile_flush(&play_file.fd);
210                                                 kfile_close(&play_file.fd);
211                                         }
212                                         else
213                                         {
214                                                 kprintf("Unable to open file: '%s' error[%d]\n", play->file_name, result);
215                                         }
216                                 }
217                                 f_mount(0, NULL);
218                         }
219                 }
220                 kputs("no message\n");
221         }
222 }
223
224 INLINE void start_play(char *file_name)
225 {
226         PlayMsg play_msg;
227         memcpy(play_msg.file_name, file_name, sizeof(play_msg.file_name));
228         msg_put(&proc_play_inPort, &play_msg.msg);
229 }
230
231 INLINE void stop_play(void)
232 {
233         i2s_dmaTxStop(&i2s);
234         played_size = 0;
235         is_playing = false;
236 }
237
238
239 INLINE FileItemNode *select_item(Bitmap *bm, List *file_list, int select_idx)
240 {
241         FileItemNode *item;
242         FileItemNode *select_node;
243         int col = 0;
244         int row = 0;
245
246         gfx_bitmapClear(bm);
247         select_node = (FileItemNode *)LIST_HEAD(file_list);
248     FOREACH_NODE(item, file_list)
249         {
250                 if (row > MAX_ITEMS_ROW)
251                 {
252                         row = 1;
253                         col = NEXT_ITEM_COL;
254                 }
255
256                 text_style(bm, 0, STYLEF_MASK);
257                 if (select_idx <= MAX_ITEMS_ROW)
258                 {
259                         if (row == select_idx && col == 0)
260                         {
261                                 text_style(bm, STYLEF_INVERT, STYLEF_INVERT);
262                                 select_node = item;
263                         }
264                 }
265                 else
266                 {
267                         if (row == (select_idx - MAX_ITEMS_ROW) && col == NEXT_ITEM_COL)
268                         {
269                                 text_style(bm, STYLEF_INVERT, STYLEF_INVERT);
270                                 select_node = item;
271                         }
272                 }
273
274                 text_xprintf(bm, row, col, TEXT_NORMAL, "%s", item->file_name);
275                 row++;
276         }
277
278         lcd_hx8347_blitBitmap(bm);
279
280         return select_node;
281 }
282
283 static void sd_explorer(Bitmap *bm)
284 {
285         List file_list;
286         LIST_INIT(&file_list);
287         int file_list_size = 0;
288         gfx_bitmapClear(bm);
289
290         memcpy (&item_nodes[0].file_name, "<- Return..", sizeof(item_nodes[0].file_name));
291         ADDTAIL(&file_list, &item_nodes[0].n);
292
293         if (SD_CARD_PRESENT())
294         {
295                 timer_delay(10);
296
297                 bool sd_ok = sd_init(&sd, NULL, 0);
298                 FRESULT result;
299
300                 if (sd_ok)
301                 {
302                         kprintf("Mount FAT filesystem.\n");
303                         result = f_mount(0, &fs);
304                         if (result != FR_OK)
305                         {
306                                 kprintf("Mounting FAT volumes error[%d]\n", result);
307                                 sd_ok = false;
308                         }
309
310                         if (sd_ok)
311                         {
312                                 FILINFO fno;
313                                 DIR dir;
314
315                                 kputs("open dir\n");
316                                 /* Open the directory */
317                                 result = f_opendir(&dir, "/");
318                                 if (result == FR_OK)
319                                 {
320                                         // First element is reserved for "return" label
321                                         for (int i = 1;; i++)
322                                         {
323                                                 /* Read a directory item */
324                                                 result = f_readdir(&dir, &fno);
325                                                 if (result != FR_OK || fno.fname[0] == 0)
326                                                         break;  /* Break on error or end of dir */
327                                                 if (fno.fname[0] == '.')
328                                                         continue; /* Ignore dot entry */
329                                                 if (fno.fattrib & AM_DIR)
330                                                         continue;
331                                                 else
332                                                 {
333                                                         if (i < MAX_ITEM_NODES)
334                                                         {
335                                                                 memcpy (&item_nodes[i].file_name, fno.fname, sizeof(item_nodes[i].file_name));
336                                                                 ADDTAIL(&file_list, &item_nodes[i].n);
337                                                                 file_list_size++;
338                                                                 kprintf("%s\n", item_nodes[i].file_name);
339                                                         }
340                                                         else
341                                                         {
342                                                                 kputs("No enought space to store items in list\n");
343                                                                 break;
344                                                         }
345                                                 }
346                                         }
347                                 }
348                         }
349                         f_mount(0, NULL);
350                         kprintf("Umount\n");
351                 }
352         }
353         else
354         {
355                 kputs("No card insert..\n");
356                 text_xprintf(bm, 5, 0, TEXT_CENTER | TEXT_FILL, "%s", "No card insert..");
357         }
358
359         int idx = 0;
360         FileItemNode *selected_node = NULL;
361         select_item(bm, &file_list, idx);
362         while (1)
363         {
364                 keymask_t key = kbd_peek();
365                 if (key & K_LEFT)
366                 {
367                         idx++;
368                         if (idx > file_list_size)
369                                 idx = 0;
370
371                         selected_node = select_item(bm, &file_list, idx);
372                         kprintf("lidx[%d] %s\n", idx, selected_node->file_name);
373                 }
374                 if (key & K_RIGHT)
375                 {
376                         if (idx == 0)
377                                 break;
378
379                         if (!is_playing)
380                                 start_play(selected_node->file_name);
381                         else
382                                 stop_play();
383                 }
384
385                 cpu_relax();
386         }
387 }
388
389 /*
390  * Lcd
391  */
392 static void setBrightness(Bitmap *bm)
393 {
394         while (1)
395         {
396                 gfx_bitmapClear(bm);
397                 text_xprintf(bm, 1, 0, TEXT_FILL | TEXT_CENTER, "Brightness: %d", lcd_brightness);
398                 text_xprintf(bm, 3, 0, TEXT_FILL | TEXT_CENTER, "RIGHT key: change");
399                 text_xprintf(bm, 4, 0, TEXT_FILL | TEXT_CENTER, "LEFT  key: back  ");
400                 lcd_hx8347_blitBitmap(bm);
401
402                 keymask_t mask = kbd_get();
403
404                 if (mask & K_LEFT)
405                         break;
406                 else if (mask & K_RIGHT)
407                 {
408                         if (++lcd_brightness > LCD_BACKLIGHT_MAX)
409                                 lcd_brightness = 0;
410                         lcd_setBacklight(lcd_brightness);
411                 }
412         }
413 }
414
415 static void setVolume(Bitmap *bm)
416 {
417         gfx_bitmapClear(bm);
418         text_style(bm, STYLEF_BOLD | STYLEF_UNDERLINE, STYLEF_BOLD | STYLEF_UNDERLINE);
419         text_xprintf(bm, 0, 0, TEXT_CENTER, "Headphone Volume");
420         text_style(bm, 0, STYLEF_MASK);
421         text_xprintf(bm, 2, 0, TEXT_NORMAL, "Turn VR1 potentiometer to adjust it.");
422
423         while (1)
424         {
425                 headphone_volume = ADC_RANGECONV(adc_read(1), 0, 100);
426                 text_xprintf(bm, 5, 0, TEXT_FILL | TEXT_CENTER, "Volume %d%%", headphone_volume);
427                 lcd_hx8347_blitBitmap(bm);
428
429                 timer_delay(400);
430                 if (kbd_peek() & KEY_MASK)
431                         break;
432         }
433 }
434
435 static void NORETURN soft_reset(Bitmap * bm)
436 {
437         int i;
438
439         gfx_bitmapClear(bm);
440         for (i = 5; i; --i)
441         {
442                 text_xprintf(bm, 2, 0, TEXT_FILL | TEXT_CENTER, "%d", i);
443                 lcd_hx8347_blitBitmap(bm);
444                 timer_delay(1000);
445         }
446         text_xprintf(bm, 2, 0, TEXT_FILL | TEXT_CENTER, "REBOOT");
447         lcd_hx8347_blitBitmap(bm);
448         timer_delay(1000);
449
450         /* Perform a software reset request */
451         HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ;
452         UNREACHABLE();
453 }
454
455
456 static struct MenuItem main_items[] =
457 {
458         { (const_iptr_t)"Play SD file",       0, (MenuHook)sd_explorer,   (iptr_t)&lcd_bitmap },
459         { (const_iptr_t)"Set brightness",     0, (MenuHook)setBrightness, (iptr_t)&lcd_bitmap },
460         { (const_iptr_t)"Set volume",         0, (MenuHook)setVolume,     (iptr_t)&lcd_bitmap },
461         { (const_iptr_t)"Reboot",             0, (MenuHook)soft_reset,    (iptr_t)&lcd_bitmap },
462         { (const_iptr_t)0,                    0, NULL,                    (iptr_t)0   }
463 };
464 static struct Menu main_menu = { main_items, "BeRTOS", MF_STICKY | MF_SAVESEL, &lcd_bitmap, 0, lcd_hx8347_blitBitmap };
465
466
467 int main(void)
468 {
469         IRQ_ENABLE;
470         kdbg_init();
471
472         LED_INIT();
473         timer_init();
474
475         proc_init();
476         sdram_init();
477         adc_init();
478
479         kprintf("sam3x %s: %d times\n", VERS_HOST, VERS_BUILD);
480
481         dmac_init();
482         i2c_init(&i2c, I2C_BITBANG0, CONFIG_I2C_FREQ);
483         i2s_init(&i2s, SSC0);
484
485         wm8731_init(&wm8731_ctx, &i2c, CODEC_ADDR);
486         wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0);
487
488         kprintf("CPU Frequecy:%ld\n", CPU_FREQ);
489
490         lcd_hx8347_init();
491         lcd_setBacklight(lcd_brightness);
492
493         gfx_bitmapInit(&lcd_bitmap, raster, LCD_WIDTH, LCD_HEIGHT);
494         gfx_setFont(&lcd_bitmap, &font_luBS14);
495         lcd_hx8347_blitBitmap(&lcd_bitmap);
496
497         kbd_init();
498
499         proc_new(play_proc, NULL, sizeof(play_proc_stack), play_proc_stack);
500         msg_initPort(&proc_play_inPort, event_createGeneric());
501
502         lcd_hx8347_blitBitmap24(10, 52, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, bmp_logo);
503         timer_delay(500);
504
505
506         while (1)
507         {
508                 menu_handle(&main_menu);
509                 cpu_relax();
510         }
511
512 }