Clean up, and mute codec when we don't play 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  * \author Stefano Federico <aleph@develer.com>
34  *
35  * \brief Empty project.
36  *
37  * This is a minimalist project, it just initializes the hardware of the
38  * supported board and proposes an empty main.
39  */
40
41 #include "hw/hw_led.h"
42 #include "hw/hw_sd.h"
43 #include "cfg/cfg_i2s.h"
44
45 #include <cfg/debug.h>
46
47 #include <cpu/irq.h>
48 #include <cpu/byteorder.h>
49
50 #include <io/kfile.h>
51 #include <io/kfile_block.h>
52
53 #include <drv/i2c.h>
54 #include <drv/i2s.h>
55 #include <drv/sd.h>
56 #include <drv/eeprom.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
63 #include <fs/fat.h>
64
65 #include <verstag.h>
66 #include <buildrev.h>
67
68 #include <string.h>
69
70 /*
71  * Codec has 7-bit address, the eighth is the R/W bit, so we
72  * write the codec address with one bit shifted left
73  */
74 #define CODEC_ADDR 0x36
75
76
77
78 typedef struct WavHdr
79 {
80         char chunk_id[4];
81         uint32_t chunk_size;
82         char format[4];
83
84         char subchunk1_id[4];
85         uint32_t subchunk1_size;
86         uint16_t audio_format;
87         uint16_t num_channels;
88         uint32_t sample_rate;
89         uint32_t byte_rate;
90         uint16_t block_align;
91         uint16_t bits_per_sample;
92
93         uint8_t subchunk2[8];
94 } WavHdr;
95
96
97 //#define FILE_NAME  "input0.wav"
98 //#define FILE_NAME  "due.wav"
99 //#define FILE_NAME  "sample.wav"
100 //#define FILE_NAME  "testaa"
101 #define FILE_NAME  "outfile.wav"
102 #define ACQ_FILE_NAME  "acq.wav"
103
104 uint8_t tmp[4096];
105
106 // SD fat filesystem context
107 FATFS fs;
108 FatFile log_file;
109 FatFile acq_file;
110
111 static I2c i2c;
112 static I2s i2s;
113 static Wm8731 wm8731_ctx;
114
115 static void init(void)
116 {
117         IRQ_ENABLE;
118         kdbg_init();
119         kprintf("sam3x %s: %d times\n", VERS_HOST, VERS_BUILD);
120
121         timer_init();
122         LED_INIT();
123
124         adc_init();
125         dmac_init();
126         i2c_init(&i2c, I2C_BITBANG0, CONFIG_I2C_FREQ);
127         i2s_init(&i2s, SSC0);
128
129         wm8731_init(&wm8731_ctx, &i2c, CODEC_ADDR);
130         wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0);
131 }
132
133 size_t count = 0;
134
135 static void codec(struct I2s *i2s, void *_buf, size_t len)
136 {
137         count += kfile_read(&log_file.fd, _buf, len);
138         if (count >= log_file.fat_file.fsize - sizeof(WavHdr))
139         {
140                 kprintf("stop %d\n", count);
141                 i2s_dmaTxStop(i2s);
142                 count = 0;
143         }
144 }
145
146 static int wav_check(KFile *fd)
147 {
148
149         WavHdr header;
150
151         if (kfile_read(fd, &header, sizeof(header)) != sizeof(header))
152         {
153                 kputs("Error reading wave file header\n");
154                 return EOF;
155         }
156
157         if (strncmp(header.chunk_id, "RIFF", 4))
158         {
159                 kputs("RIFF tag not found\n");
160                 goto error;
161         }
162
163         if (strncmp(header.format, "WAVE", 4))
164         {
165                 kputs("WAVE tag not found\n");
166                 goto error;
167         }
168
169         if (le16_to_cpu(header.audio_format) != 1)
170         {
171                 kprintf("Audio format not valid, found [%d]\n", le16_to_cpu(header.audio_format));
172                 goto error;
173         }
174
175         if (le16_to_cpu(header.num_channels) != 2)
176         {
177                 kprintf("Channels number not valid, found [%d]\n", le16_to_cpu(header.num_channels));
178                 goto error;
179         }
180
181
182         if (le32_to_cpu(header.sample_rate) != 44100)
183         {
184                 kprintf("Sample rate not valid, found [%ld]\n", le32_to_cpu(header.sample_rate));
185                 goto error;
186         }
187
188         if (le16_to_cpu(header.bits_per_sample) != 16)
189         {
190                 kprintf("Bits per sample not valid, found [%d]\n", le16_to_cpu(header.bits_per_sample));
191                 goto error;
192         }
193         return 0;
194
195 error:
196         return 1;
197 }
198
199 int main(void)
200 {
201         init();
202
203         for (;;)
204         {
205                 if (SD_CARD_PRESENT())
206                 {
207                         timer_delay(10);
208                         Sd sd;
209                         bool sd_ok = sd_init(&sd, NULL, 0);
210                         FRESULT result;
211
212                         if (sd_ok)
213                         {
214                                 kprintf("Mount FAT filesystem.\n");
215                                 result = f_mount(0, &fs);
216                                 if (result != FR_OK)
217                                 {
218                                         kprintf("Mounting FAT volumes error[%d]\n", result);
219                                         sd_ok = false;
220                                 }
221
222                                 if (sd_ok)
223                                 {
224                                         result = fatfile_open(&log_file, FILE_NAME,  FA_OPEN_EXISTING | FA_READ);
225                                         if (result == FR_OK)
226                                         {
227                                                 kprintf("Opened log file '%s' size %ld\n", FILE_NAME, log_file.fat_file.fsize);
228                                                 wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, adc_read(1));
229                                                 if (wav_check(&log_file.fd) >= 0)
230                                                 {
231                                                         kputs("Wav file play..\n");
232                                                         i2s_dmaStartTxStreaming(&i2s, tmp, sizeof(tmp), sizeof(tmp) / 4, codec);
233                                                 }
234
235                                                 wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0);
236
237                                                 // Flush data and close the files.
238                                                 kfile_flush(&log_file.fd);
239                                                 kfile_close(&log_file.fd);
240                                         }
241                                         else
242                                         {
243                                                 kprintf("Unable to open file: '%s' error[%d]\n", FILE_NAME, result);
244                                         }
245
246                                         //Unmount always to prevent accidental sd remove.
247                                         f_mount(0, NULL);
248                                         kprintf("Umount\n");
249
250                                 }
251                                 f_mount(0, NULL);
252                         }
253
254                         timer_delay(5000);
255                 }
256                 else
257                 {
258                         kputs("No card insert..\n");
259                         timer_delay(500);
260                 }
261         }
262
263         return 0;
264 }
265
266
267
268
269
270