hxcodec.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. /*
  2. * Copyright (C) 2008-2009 by egnite GmbH.
  3. * Copyright (C) 2001-2007 by egnite Software GmbH.
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. /*
  36. * $Log$
  37. * Revision 1.4 2009/02/13 14:46:19 haraldkipp
  38. * Using the VS10xx driver as a template for redesign.
  39. *
  40. * Revision 1.3 2009/01/17 11:26:46 haraldkipp
  41. * Getting rid of two remaining BSD types in favor of stdint.
  42. * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
  43. *
  44. * Revision 1.2 2008/10/23 08:54:07 haraldkipp
  45. * Include the correct header file.
  46. *
  47. * Revision 1.1 2008/10/05 16:56:15 haraldkipp
  48. * Added Helix audio device.
  49. *
  50. */
  51. #include <sys/atom.h>
  52. #include <sys/event.h>
  53. #include <sys/timer.h>
  54. #include <sys/heap.h>
  55. #include <cfg/arch/gpio.h>
  56. #include <cfg/audio.h>
  57. #include <dev/irqreg.h>
  58. #include <contrib/hxmp3/mp3dec.h>
  59. #include <contrib/hxmp3/hermite.h>
  60. #include <dev/hxcodec.h>
  61. #include <dev/tlv320dac.h>
  62. #include <sys/bankmem.h>
  63. #include <stdlib.h>
  64. #include <stddef.h>
  65. #include <string.h>
  66. #include <memdebug.h>
  67. #if 0
  68. /* Use for local debugging. */
  69. #define NUTDEBUG
  70. #include <stdio.h>
  71. #endif
  72. #ifndef NUT_THREAD_HXCODEC0STACK
  73. /* arm-elf-gcc optimized code used 540 bytes. */
  74. #define NUT_THREAD_HXCODEC0STACK 768
  75. #endif
  76. #ifndef HXCODEC0_MAX_OUTPUT_BUFSIZ
  77. /*! \brief Output buffer size limit. */
  78. #define HXCODEC0_MAX_OUTPUT_BUFSIZ 393216
  79. #endif
  80. #ifndef DAC_OUTPUT_RATE
  81. #if defined (AT91SAM9260_EK)
  82. #define DAC_OUTPUT_RATE 44100
  83. #else
  84. #define DAC_OUTPUT_RATE 8000
  85. #endif
  86. #endif
  87. #ifndef MP3_BUFSIZ
  88. #if defined (AT91SAM9260_EK)
  89. #define MP3_BUFSIZ 1048576
  90. #else
  91. #define MP3_BUFSIZ (4 * MAINBUF_SIZE)
  92. #endif
  93. #endif
  94. #ifdef HXCODEC0_RESAMPLER
  95. static int rs_maxout;
  96. static short *rs_pcmbuf;
  97. #endif
  98. /*! \name Internal Command Flags */
  99. /*@{*/
  100. /*! \brief Force immediate player start. */
  101. #define HXREQ_PLAY 0x00000001
  102. /*! \brief Force immediate player stop. */
  103. #define HXREQ_CANCEL 0x00000002
  104. /*! \brief Volume update. */
  105. #define HXREQ_VOLUPD 0x00000004
  106. /*! \brief Sine wave test. */
  107. #define HXREQ_BEEP 0x00000008
  108. /*@}*/
  109. /*!
  110. * \addtogroup xgHelixCodec
  111. */
  112. /*@{*/
  113. typedef struct _HXDCB {
  114. int dcb_pbstat; /*!< \brief Playback status. */
  115. uint32_t dcb_scmd; /*!< \brief Requested command flags, see HXREQ_ flags. */
  116. int dcb_rvol; /*!< \brief Volume of right channel. */
  117. int dcb_lvol; /*!< \brief Volume of left channel. */
  118. uint32_t dcb_pbwlo; /*!< \brief Playback buffer low watermark. */
  119. uint32_t dcb_pbwhi; /*!< \brief Playback buffer high watermark. */
  120. uint32_t dcb_wtmo; /*!< \brief Write timeout. */
  121. HANDLE dcb_bufque; /*!< \brief Buffer change event. */
  122. HANDLE dcb_feedme; /*!< \brief Decoder hungry event. */
  123. } HXDCB;
  124. static HXDCB dcb;
  125. typedef struct _MP3PLAYERINFO {
  126. HMP3Decoder mpi_mp3dec;
  127. MP3FrameInfo mpi_frameinfo;
  128. } MP3PLAYERINFO;
  129. static MP3PLAYERINFO mpi;
  130. static short pi_pcmbuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP];
  131. static int first_frame;
  132. static int samprate;
  133. /*!
  134. * \brief Set volume.
  135. *
  136. * \param dev Specifies the audio codec device.
  137. * \param left Left channel gain in db.
  138. * \param right Right channel gain in db.
  139. *
  140. * \return Always 0.
  141. */
  142. static int HelixPlayerSetVolume(NUTDEVICE *dev, int left, int right)
  143. {
  144. HXDCB *dcb = (HXDCB *)dev->dev_dcb;
  145. /* Honor limits. */
  146. left = left > AUDIO_DAC_MAX_GAIN ? AUDIO_DAC_MAX_GAIN : left;
  147. left = left < AUDIO_DAC_MIN_GAIN ? AUDIO_DAC_MIN_GAIN : left;
  148. right = right > AUDIO_DAC_MAX_GAIN ? AUDIO_DAC_MAX_GAIN : right;
  149. right = right < AUDIO_DAC_MIN_GAIN ? AUDIO_DAC_MIN_GAIN : right;
  150. Tlv320DacSetVolume(left, right);
  151. dcb->dcb_lvol = left;
  152. dcb->dcb_rvol = right;
  153. return 0;
  154. }
  155. static int DecodeFrame(uint8_t *buf, int len)
  156. {
  157. int rc = len;
  158. int skip;
  159. static void *hres;
  160. while (len > 2 * MAINBUF_SIZE) {
  161. if ((skip = MP3FindSyncWord(buf, len)) < 0) {
  162. return len;
  163. }
  164. if (skip) {
  165. len -= skip;
  166. buf += skip;
  167. } else {
  168. if (MP3Decode(mpi.mpi_mp3dec, &buf, &len, pi_pcmbuf, 0)) {
  169. return -1;
  170. }
  171. if (first_frame) {
  172. MP3GetLastFrameInfo(mpi.mpi_mp3dec, &mpi.mpi_frameinfo);
  173. if (mpi.mpi_frameinfo.nChans == 1) {
  174. samprate = mpi.mpi_frameinfo.samprate / 2;
  175. }
  176. else if (mpi.mpi_frameinfo.nChans == 2) {
  177. samprate = mpi.mpi_frameinfo.samprate;
  178. }
  179. else {
  180. return -1;
  181. }
  182. if (mpi.mpi_frameinfo.samprate < 8000 || samprate > DAC_OUTPUT_RATE) {
  183. return -1;
  184. }
  185. if (mpi.mpi_frameinfo.bitsPerSample != 16) {
  186. return -1;
  187. }
  188. #ifdef HXCODEC0_RESAMPLER
  189. /* If needed, initialize resampler. */
  190. if (samprate != DAC_OUTPUT_RATE) {
  191. if ((hres = RAInitResamplerHermite(samprate, DAC_OUTPUT_RATE, mpi.mpi_frameinfo.nChans)) == NULL) {
  192. return -1;
  193. }
  194. rs_maxout = RAGetMaxOutputHermite(mpi.mpi_frameinfo.outputSamps, hres);
  195. if ((rs_pcmbuf = malloc(rs_maxout * 2)) == NULL) {
  196. return -1;
  197. }
  198. }
  199. #else
  200. (void)hres;
  201. #endif
  202. first_frame = 0;
  203. }
  204. #ifdef HXCODEC0_RESAMPLER
  205. if (hres) {
  206. int os;
  207. if (mpi.mpi_frameinfo.nChans == 1) {
  208. os = RAResampleMonoHermite(pi_pcmbuf, mpi.mpi_frameinfo.outputSamps, rs_pcmbuf, hres);
  209. }
  210. else {
  211. os = RAResampleStereoHermite(pi_pcmbuf, mpi.mpi_frameinfo.outputSamps, rs_pcmbuf, hres);
  212. }
  213. if (os <= 0) {
  214. break;
  215. }
  216. if (Tlv320DacWrite(rs_pcmbuf, os)) {
  217. break;
  218. }
  219. } else
  220. #endif
  221. {
  222. if (Tlv320DacWrite(pi_pcmbuf, mpi.mpi_frameinfo.outputSamps)) {
  223. return -1;
  224. }
  225. }
  226. break;
  227. }
  228. }
  229. return rc - len;
  230. }
  231. /*
  232. * Initialize the stream output buffer with a given size.
  233. *
  234. * \param dev Specifies the audio codec device.
  235. */
  236. static int HelixPlayerBufferInit(NUTDEVICE *dev, uint32_t size)
  237. {
  238. HXDCB *dcb = (HXDCB *)dev->dev_dcb;
  239. /* Make sure that the decoder is idle. */
  240. if (dcb->dcb_pbstat != CODEC_STATUS_IDLE) {
  241. return -1;
  242. }
  243. /* Set new buffer size. */
  244. if (NutSegBufInit((size_t)size) == NULL) {
  245. return -1;
  246. }
  247. /* Set watermark defaults. */
  248. dcb->dcb_pbwlo = NutSegBufAvailable() / 3;
  249. dcb->dcb_pbwhi = dcb->dcb_pbwlo * 2;
  250. return 0;
  251. }
  252. /*
  253. * VLSI decoder feeding thread.
  254. */
  255. THREAD(FeederThread, arg)
  256. {
  257. uint8_t *bp;
  258. uint8_t *backbuf = NULL;
  259. int backcnt = 0;
  260. size_t avail;
  261. int filled;
  262. NUTDEVICE *dev = (NUTDEVICE *)arg;
  263. HXDCB *dcb = (HXDCB *)dev->dev_dcb;
  264. /* We are a high priority thread. */
  265. NutThreadSetPriority(7);
  266. for (;;) {
  267. /*
  268. ** Idle mode processing.
  269. */
  270. if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
  271. /* Wait for a request or a buffer update. */
  272. NutEventWait(&dcb->dcb_feedme, NUT_WAIT_INFINITE);
  273. /* Check if we should change to play mode. This will happen
  274. ** if we receive a play request or if the buffer contents
  275. ** reaches the high watermark. */
  276. if ((dcb->dcb_scmd & HXREQ_PLAY) != 0 || NutSegBufUsed() >= dcb->dcb_pbwhi) {
  277. dcb->dcb_scmd &= ~(HXREQ_PLAY | HXREQ_CANCEL);
  278. dcb->dcb_pbstat = CODEC_STATUS_PLAYING;
  279. HelixPlayerSetVolume(dev, dcb->dcb_lvol, dcb->dcb_rvol);
  280. }
  281. }
  282. /*
  283. ** Play mode processing.
  284. */
  285. if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
  286. /* Process cancel requests. */
  287. if (dcb->dcb_scmd & HXREQ_CANCEL) {
  288. dcb->dcb_scmd &= ~HXREQ_CANCEL;
  289. NutSegBufReset();
  290. }
  291. if (dcb->dcb_scmd & HXREQ_VOLUPD) {
  292. HelixPlayerSetVolume(dev, dcb->dcb_lvol, dcb->dcb_rvol);
  293. dcb->dcb_scmd &= ~HXREQ_VOLUPD;
  294. }
  295. /* Retrieve new data from the input buffer. */
  296. bp = (uint8_t *) NutSegBufReadRequest(&avail);
  297. if (backcnt && backcnt + avail >= 4 * MAINBUF_SIZE) {
  298. memcpy(&backbuf[backcnt], bp, 4 * MAINBUF_SIZE - backcnt);
  299. filled = DecodeFrame(backbuf, 4 * MAINBUF_SIZE);
  300. if (filled < 0) {
  301. backcnt = 0;
  302. free(backbuf);
  303. } else if (filled < backcnt) {
  304. bp = backbuf;
  305. backcnt -= filled;
  306. backbuf = malloc(4 * MAINBUF_SIZE);
  307. memcpy(backbuf, &bp[filled], backcnt);
  308. free(bp);
  309. } else {
  310. if (filled > backcnt) {
  311. NutSegBufReadLast(filled - backcnt);
  312. }
  313. backcnt = 0;
  314. free(backbuf);
  315. }
  316. } else if (avail > 2 * MAINBUF_SIZE) {
  317. filled = DecodeFrame(bp, avail);
  318. if (filled < 0) {
  319. NutSegBufReadLast(1);
  320. } else if (filled) {
  321. NutSegBufReadLast(filled);
  322. }
  323. NutEventPost(&dcb->dcb_bufque);
  324. }
  325. else if (NutSegBufUsed() == 0) {
  326. /* Finally we reached idle mode. */
  327. dcb->dcb_pbstat = CODEC_STATUS_IDLE;
  328. NutEventPost(&dcb->dcb_bufque);
  329. } else if (avail && backcnt == 0) {
  330. backcnt = avail;
  331. backbuf = malloc(4 * MAINBUF_SIZE);
  332. memcpy(backbuf, bp, backcnt);
  333. NutSegBufReadLast(backcnt);
  334. NutEventPost(&dcb->dcb_bufque);
  335. } else {
  336. /* Wait for a request or a buffer update. */
  337. NutEventWait(&dcb->dcb_feedme, 1000);
  338. }
  339. }
  340. }
  341. }
  342. /*!
  343. * \brief Handle I/O controls for audio codec.
  344. *
  345. * - AUDIO_PLAY Force playback start, even if the buffer level is too lower.
  346. * - AUDIO_CANCEL Cancel playback and discard all buffered data.
  347. * - AUDIO_GET_STATUS Sets an int to 1 if the player is running, 0 if idle.
  348. * - AUDIO_GET_PLAYGAIN Sets an int to the current playback gain, 0..-127.
  349. * - AUDIO_SET_PLAYGAIN Reads the requested playback gain from an int, 0..-127.
  350. * - AUDIO_GET_PBSIZE Sets an unsigned long with the size of the playback buffer.
  351. * - AUDIO_SET_PBSIZE Sets the size the playback buffer using an unsigned long.
  352. * - AUDIO_GET_PBLEVEL Sets an unsigned long with the number of bytes in the playback buffer.
  353. * - AUDIO_GET_PBWLOW Sets an unsigned long with the low watermark of the playback buffer.
  354. * - AUDIO_SET_PBWLOW Sets the low watermark (unsigned long) of the playback buffer.
  355. * - AUDIO_GET_PBWHIGH Sets an unsigned long with the high watermark of the playback buffer.
  356. * - AUDIO_SET_PBWHIGH Sets the high watermark (unsigned long) of the playback buffer.
  357. * - AUDIO_BEEP Plays a short sine wave beep.
  358. *
  359. * \return 0 on success, -1 otherwise.
  360. */
  361. static int HelixIOCtl(NUTDEVICE * dev, int req, void *conf)
  362. {
  363. int rc = 0;
  364. uint32_t *lvp = (uint32_t *) conf;
  365. int *ivp = (int *) conf;
  366. HXDCB *dcb = (HXDCB *)dev->dev_dcb;
  367. switch (req) {
  368. case AUDIO_PLAY:
  369. if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
  370. /* Immediately start playing. */
  371. dcb->dcb_scmd |= HXREQ_PLAY;
  372. }
  373. NutEventPost(&dcb->dcb_feedme);
  374. break;
  375. case AUDIO_CANCEL:
  376. if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
  377. /* Immediately stop playing and discard buffer. */
  378. dcb->dcb_scmd |= HXREQ_CANCEL;
  379. }
  380. NutEventPost(&dcb->dcb_feedme);
  381. break;
  382. case AUDIO_GET_STATUS:
  383. *ivp = dcb->dcb_pbstat;
  384. break;
  385. case AUDIO_GET_PLAYGAIN:
  386. *ivp = dcb->dcb_rvol > dcb->dcb_lvol ? dcb->dcb_rvol : dcb->dcb_lvol;
  387. break;
  388. case AUDIO_SET_PLAYGAIN:
  389. dcb->dcb_lvol = *ivp;
  390. dcb->dcb_rvol = *ivp;
  391. dcb->dcb_scmd |= HXREQ_VOLUPD;
  392. break;
  393. case AUDIO_GET_PBSIZE:
  394. *lvp = NutSegBufAvailable() + NutSegBufUsed();
  395. break;
  396. case AUDIO_SET_PBSIZE:
  397. rc = HelixPlayerBufferInit(dev, *lvp);
  398. break;
  399. case AUDIO_GET_PBLEVEL:
  400. *lvp = NutSegBufUsed();
  401. break;
  402. case AUDIO_GET_PBWLOW:
  403. *lvp = dcb->dcb_pbwlo;
  404. break;
  405. case AUDIO_SET_PBWLOW:
  406. dcb->dcb_pbwlo = *lvp;
  407. break;
  408. case AUDIO_GET_PBWHIGH:
  409. *lvp = dcb->dcb_pbwhi;
  410. break;
  411. case AUDIO_SET_PBWHIGH:
  412. dcb->dcb_pbwhi = *lvp;
  413. break;
  414. case AUDIO_SETWRITETIMEOUT:
  415. dcb->dcb_wtmo = *lvp;
  416. break;
  417. case AUDIO_GETWRITETIMEOUT:
  418. *lvp = dcb->dcb_wtmo;
  419. break;
  420. default:
  421. rc = -1;
  422. break;
  423. }
  424. return rc;
  425. }
  426. /*!
  427. * \brief Flush VLSI audio decoder buffer.
  428. *
  429. * Waits until all currently buffered data had been processed by the
  430. * decoder. This makes sure that the end of the stream will not be
  431. * cut off.
  432. *
  433. * \param dev Specifies the audio codec device.
  434. * \param tmo Timeout in milliseconds.
  435. *
  436. * \return 0 on success, -1 on timeout.
  437. */
  438. static int HelixPlayerFlush(NUTDEVICE *dev, uint32_t tmo)
  439. {
  440. int rc = 0;
  441. HXDCB *dcb = dev->dev_dcb;
  442. for (;;) {
  443. /* Keep the player running if the buffer contains data. */
  444. if (NutSegBufUsed()) {
  445. HelixIOCtl(dev, AUDIO_PLAY, NULL);
  446. }
  447. /* No data in buffer. If idle, then we are done. */
  448. else if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
  449. /* No data and player is idle. */
  450. break;
  451. }
  452. /* Wait for a new buffer update. */
  453. rc = NutEventWait(&dcb->dcb_bufque, tmo);
  454. if (rc) {
  455. break;
  456. }
  457. }
  458. Tlv320DacFlush();
  459. return rc;
  460. }
  461. /*!
  462. * \brief Send data to the decoder.
  463. *
  464. * A carriage return character will be automatically appended
  465. * to any linefeed.
  466. *
  467. * \return Number of characters sent.
  468. */
  469. static int HelixWrite(NUTFILE * nfp, const void *data, int len)
  470. {
  471. int rc = 0;
  472. uint8_t *bp;
  473. const uint8_t *dp;
  474. size_t rbytes;
  475. HXDCB *dcb = nfp->nf_dev->dev_dcb;
  476. dcb->dcb_wtmo = 3000; //DEBUG
  477. /* Flush buffer if data pointer is a NULL pointer. */
  478. if (data == NULL || len == 0) {
  479. return HelixPlayerFlush(nfp->nf_dev, dcb->dcb_wtmo);
  480. }
  481. dp = data;
  482. while (len) {
  483. bp = (uint8_t *)NutSegBufWriteRequest(&rbytes);
  484. if (rbytes == 0) {
  485. /* No buffer space, wait for change. */
  486. if (NutEventWait(&dcb->dcb_bufque, dcb->dcb_wtmo)) {
  487. /* Write timeout. */
  488. break;
  489. }
  490. } else {
  491. if (rbytes > len) {
  492. rbytes = len;
  493. }
  494. memcpy(bp, dp, rbytes);
  495. NutSegBufWriteLast(rbytes);
  496. NutEventPost(&dcb->dcb_feedme);
  497. len -= rbytes;
  498. rc += rbytes;
  499. dp += rbytes;
  500. }
  501. }
  502. return rc;
  503. }
  504. #ifdef __HARVARD_ARCH__
  505. /*!
  506. * \brief Write to device.
  507. *
  508. * Similar to HelixWrite() except that the data is expected in program memory.
  509. *
  510. * This function is implemented for CPUs with Harvard Architecture only.
  511. *
  512. * This function is called by the low level output routines of the
  513. * \ref xrCrtLowio "C runtime library", using the
  514. * \ref _NUTDEVICE::dev_write_P entry.
  515. *
  516. * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
  517. * call to PnutFileOpen().
  518. * \param buffer Pointer to the data in program space. If zero, then the
  519. * output buffer will be flushed.
  520. * \param len Number of bytes to write.
  521. *
  522. * \return The number of bytes written. A return value of -1 indicates an
  523. * error. Currently this function is not implemented and always
  524. * returns -1.
  525. *
  526. */
  527. static int HelixWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
  528. {
  529. return -1;
  530. }
  531. #endif
  532. /*!
  533. * \brief Open codec device.
  534. *
  535. * \return Pointer to a static NUTFILE structure.
  536. */
  537. static NUTFILE *HelixOpen(NUTDEVICE * dev, const char *name, int mode, int acc)
  538. {
  539. NUTFILE *nfp;
  540. if ((mpi.mpi_mp3dec = MP3InitDecoder()) == NULL) {
  541. return NUTFILE_EOF;
  542. }
  543. first_frame = 1;
  544. NutSleep(2);
  545. nfp = malloc(sizeof(NUTFILE));
  546. nfp->nf_dev = dev;
  547. nfp->nf_fcb = NULL;
  548. NutSegBufReset();
  549. return nfp;
  550. }
  551. /*!
  552. * \brief Close codec device.
  553. */
  554. static int HelixClose(NUTFILE * nfp)
  555. {
  556. HXDCB *dcb = nfp->nf_dev->dev_dcb;
  557. int rc;
  558. rc = HelixPlayerFlush(nfp->nf_dev, dcb->dcb_wtmo);
  559. if (nfp) {
  560. if (mpi.mpi_mp3dec) {
  561. MP3FreeDecoder(mpi.mpi_mp3dec);
  562. mpi.mpi_mp3dec = NULL;
  563. }
  564. free(nfp);
  565. }
  566. return rc;
  567. }
  568. /*
  569. * Called via dev_init pointer when the device is registered.
  570. */
  571. static int HelixInit(NUTDEVICE * dev)
  572. {
  573. size_t avail;
  574. Tlv320DacInit(DAC_OUTPUT_RATE);
  575. dcb.dcb_rvol = -32;
  576. dcb.dcb_lvol = -32;
  577. Tlv320DacSetVolume(dcb.dcb_lvol, dcb.dcb_rvol);
  578. /*
  579. ** Initialize the decoder stream buffer.
  580. */
  581. #ifdef HXCODEC0_OUTPUT_BUFSIZ
  582. avail = HXCODEC0_OUTPUT_BUFSIZ;
  583. #else
  584. avail = NutHeapAvailable() / 2;
  585. if (avail > HXCODEC0_MAX_OUTPUT_BUFSIZ) {
  586. avail = HXCODEC0_MAX_OUTPUT_BUFSIZ;
  587. }
  588. #endif
  589. if (HelixPlayerBufferInit(dev, avail)) {
  590. return -1;
  591. }
  592. /* Start the feeder thread. */
  593. if (NutThreadCreate(dev->dev_name, FeederThread, dev,
  594. (NUT_THREAD_HXCODEC0STACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == 0) {
  595. return -1;
  596. }
  597. return 0;
  598. }
  599. /*!
  600. * \brief Device information structure.
  601. *
  602. * An application must pass a pointer to this structure to
  603. * NutRegisterDevice() before using this driver.
  604. *
  605. * The device is named \b audio0.
  606. *
  607. * \showinitializer
  608. */
  609. NUTDEVICE devHelixCodec = {
  610. 0, /* Pointer to next device, dev_next. */
  611. {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0}, /* Unique device name, dev_name. */
  612. IFTYP_CHAR, /* Type of device, dev_type. */
  613. 0, /* Base address, dev_base (not used). */
  614. 0, /* First interrupt number, dev_irq (not used). */
  615. 0, /* Interface control block, dev_icb (not used). */
  616. &dcb, /* Driver control block, dev_dcb. */
  617. HelixInit, /* Driver initialization routine, dev_init. */
  618. HelixIOCtl, /* Driver specific control function, dev_ioctl. */
  619. NULL, /* Read from device, dev_read. */
  620. HelixWrite, /* Write to device, dev_write. */
  621. #ifdef __HARVARD_ARCH__
  622. HelixWrite_P, /* Write data from program space to device, dev_write_P. */
  623. #endif
  624. HelixOpen, /* Open a device or file, dev_open. */
  625. HelixClose, /* Close a device or file, dev_close. */
  626. NULL, /* Request file size, dev_size. */
  627. NULL, /* Select function, optional, not yet implemented */
  628. };
  629. /*@}*/