spi_vscodec.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  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. * $Id: spi_vscodec.c 5472 2013-12-06 00:16:28Z olereinhardt $
  37. */
  38. #include <dev/vscodec.h>
  39. #include <sys/event.h>
  40. #include <sys/timer.h>
  41. #include <sys/nutdebug.h>
  42. #include <sys/bankmem.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include <memdebug.h>
  46. #include <fcntl.h>
  47. /*!
  48. * \addtogroup xgVsCodec
  49. */
  50. /*@{*/
  51. /*! \name Internal Command Flags */
  52. /*@{*/
  53. /*! \brief Force immediate player start. */
  54. #define VSREQ_PLAY 0x00000001
  55. /*! \brief Force immediate player stop. */
  56. #define VSREQ_CANCEL 0x00000002
  57. /*! \brief Volume update. */
  58. #define VSREQ_VOLUPD 0x00000004
  59. /*! \brief Audio enhancement update. */
  60. #define VSREQ_AUDIOE 0x00000008
  61. /*! \brief Sine wave test. */
  62. #define VSREQ_BEEP 0x00000010
  63. /*! \brief Start recording. */
  64. #define VSREQ_RECORD 0x00000020
  65. /*@}*/
  66. /* Used to send zeros to the decoder. */
  67. uint8_t zero_chunk[VSCODEC_DATA_CHUNK_SIZE];
  68. /*!
  69. * \brief Wait until codec is ready.
  70. *
  71. * \param dev Sepcifies the codec device.
  72. * \param tmo Maximum number of milliseconds to wait.
  73. *
  74. * \return 0 on success, -1 on time out.
  75. */
  76. int VsCodecWaitReady(NUTDEVICE *dev, uint32_t tmo)
  77. {
  78. VSDCB *dcb = (VSDCB *) dev->dev_dcb;
  79. while (!(* dcb->dcb_isready)()) {
  80. if (NutEventWait(&dcb->dcb_feedme, tmo)) {
  81. return -1;
  82. }
  83. }
  84. return 0;
  85. }
  86. /*
  87. * \brief Read from or write to a VLSI audio codec register.
  88. *
  89. * \param dev Specifies the codec device.
  90. * \param op Operation, either \ref VS_OPCODE_READ or
  91. * \ref VS_OPCODE_WRITE.
  92. * \param reg The register index.
  93. * \param val This value will be stored in the register on a write
  94. * operation. It is ignored on read operations.
  95. *
  96. * \return Register contents. On write operations, the contents before
  97. * the modification is returned.
  98. */
  99. uint16_t VsCodecReg(NUTDEVICE *dev, uint_fast8_t op, uint_fast8_t reg, uint_fast16_t val)
  100. {
  101. uint8_t cmd[4];
  102. VSDCB *dcb = (VSDCB *) dev->dev_dcb;
  103. /* Assemble command buffer. */
  104. cmd[0] = (uint8_t) op;
  105. cmd[1] = (uint8_t) reg;
  106. cmd[2] = (uint8_t) (val >> 8);
  107. cmd[3] = (uint8_t) val;
  108. VsCodecWaitReady(dev, VSCODEC_CMD_TIMEOUT);
  109. (*dcb->dcb_sendcmd)(cmd, 4);
  110. val = cmd[2];
  111. val <<= 8;
  112. val |= cmd[3];
  113. return (uint16_t) val;
  114. }
  115. /*!
  116. * \brief Read and modify VLSI audio codec mode flags.
  117. *
  118. * Set both, flags and mask to zero to read the flags without change.
  119. *
  120. * \param dev Specifies the audio codec device.
  121. * \param flags Mode flags to set. All other flags are disabled, if they
  122. * appear in the mask.
  123. * \param mask Mode flags to update. All other flags are left unchanged.
  124. *
  125. * \return Previous mode flags.
  126. */
  127. uint16_t VsCodecMode(NUTDEVICE *dev, uint_fast16_t flags, uint_fast16_t mask)
  128. {
  129. uint16_t rc;
  130. /* Read the mode register. */
  131. rc = VsCodecReg(dev, VS_OPCODE_READ, VS_MODE_REG, 0);
  132. if (mask | flags) {
  133. VsCodecReg(dev, VS_OPCODE_WRITE, VS_MODE_REG, (rc & ~mask) | flags);
  134. /* Add delay after software reset, if configured. */
  135. #if defined(VSCODEC_SWRST_RECOVER)
  136. if (flags & VS_SM_RESET) {
  137. NutSleep(VSCODEC_SWRST_RECOVER);
  138. }
  139. #endif
  140. }
  141. return rc;
  142. }
  143. /*!
  144. * \brief Set volume.
  145. *
  146. * \param dev Specifies the audio codec device.
  147. * \param left Left channel gain in db.
  148. * \param right Right channel gain in db.
  149. *
  150. * \return Always 0.
  151. */
  152. int VsDecoderSetVolume(NUTDEVICE *dev, int left, int right)
  153. {
  154. VSDCB *dcb = (VSDCB *)dev->dev_dcb;
  155. uint16_t l;
  156. uint16_t r;
  157. /* Honor limits. */
  158. left = left > AUDIO_DAC_MAX_GAIN ? AUDIO_DAC_MAX_GAIN : left;
  159. left = left < AUDIO_DAC_MIN_GAIN ? AUDIO_DAC_MIN_GAIN : left;
  160. right = right > AUDIO_DAC_MAX_GAIN ? AUDIO_DAC_MAX_GAIN : right;
  161. right = right < AUDIO_DAC_MIN_GAIN ? AUDIO_DAC_MIN_GAIN : right;
  162. /* Convert to register values. */
  163. l = (uint16_t)(-2 * left);
  164. r = (uint16_t)(-2 * right);
  165. VsCodecReg(dev, VS_OPCODE_WRITE, VS_VOL_REG, (l << VS_VOL_LEFT_LSB) | (r << VS_VOL_RIGHT_LSB));
  166. dcb->dcb_lvol = left;
  167. dcb->dcb_rvol = right;
  168. return 0;
  169. }
  170. /*!
  171. * \brief Set Bass.
  172. *
  173. * \param dev Specifies the audio codec device.
  174. * \param treb Treble amplitude x 1.5dB.
  175. * \param tset Treble frequency limit x 1000Hz
  176. * \param bass Bass amplitude x 1dB.
  177. * \param bset Bass frequency limit x 10Hz
  178. *
  179. * \return Always 0.
  180. */
  181. int VsDecoderSetBass(NUTDEVICE *dev, int treb, int tfin, int bass, int bfin)
  182. {
  183. #ifdef VS_HAS_BASS_REG
  184. VSDCB *dcb = (VSDCB *)dev->dev_dcb;
  185. // uint16_t t;
  186. // uint16_t b;
  187. //printf("bass: t:%ddB tf:%dHz b:%ddB bf:%dHz\n", treb, tfin*1000, bass, bfin);
  188. /* Honor limits. */
  189. treb = treb > AUDIO_DAC_MAX_TREB ? AUDIO_DAC_MAX_TREB : treb;
  190. treb = treb < 0 ? 0 : treb;
  191. tfin = tfin > AUDIO_DAC_MAX_TFIN ? AUDIO_DAC_MAX_TFIN : tfin;
  192. tfin = tfin < 0 ? 0 : tfin;
  193. bass = bass > AUDIO_DAC_MAX_BASS ? AUDIO_DAC_MAX_BASS : bass;
  194. bass = bass < 0 ? 0 : bass;
  195. bfin = bfin > AUDIO_DAC_MAX_BFIN ? AUDIO_DAC_MAX_BFIN : bfin;
  196. bfin = bfin < 0 ? 0 : bfin;
  197. /* Convert to register values. */
  198. /*
  199. l = (uint16_t)(-2 * left);
  200. r = (uint16_t)(-2 * right);
  201. */
  202. VsCodecReg(dev, VS_OPCODE_WRITE, VS_BASS_REG,
  203. (treb << VS_ST_AMPLITUDE_LSB) | (tfin << VS_ST_FREQLIMIT_LSB) |
  204. (treb << VS_SB_AMPLITUDE_LSB) | (tfin << VS_SB_FREQLIMIT_LSB)
  205. );
  206. dcb->dcb_treb = treb;
  207. dcb->dcb_tfin = tfin;
  208. dcb->dcb_bass = bass;
  209. dcb->dcb_bfin = bfin;
  210. #endif
  211. return 0;
  212. }
  213. /*!
  214. * \brief Start or stop sine wave beeper.
  215. *
  216. * Old, VS1001 compatible routine, which supports a limit number of
  217. * frequencies only. It will try to find the best value.
  218. *
  219. * \param dev Specifies the audio codec device.
  220. * \param fsin Frequency, or 0 to switch beeper off.
  221. *
  222. * \return Actual frequency set.
  223. */
  224. uint16_t VsCodecBeep(NUTDEVICE *dev, uint16_t fsin)
  225. {
  226. uint16_t rc = 0;
  227. static uint8_t on[] = { 0x53, 0xEF, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00 };
  228. static const uint8_t off[] = { 0x45, 0x78, 0x69, 0x74, 0x00, 0x00, 0x00, 0x00 };
  229. static const uint16_t ftab[] = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000 };
  230. static uint16_t mode;
  231. VSDCB *dcb = (VSDCB *)dev->dev_dcb;
  232. if (fsin) {
  233. uint_fast16_t s;
  234. uint32_t f;
  235. uint_fast16_t d;
  236. int_fast8_t i = sizeof(ftab) / sizeof(ftab[0]);
  237. int_fast8_t ie = 0;
  238. int_fast16_t dmin = fsin;
  239. uint32_t fs = (long)fsin * 128;
  240. while (--i >= ie) {
  241. /* Calculate skip speed. */
  242. f = ftab[i];
  243. s = (fs + f / 2) / f;
  244. /* Check that skip is within 5-bit range. */
  245. if (s && s < 32) {
  246. /* Calculate the absolute deviation. */
  247. f *= s;
  248. f += 64;
  249. f >>= 7;
  250. d = (uint_fast16_t)(fsin > f ? fsin - f : f - fsin);
  251. /* Check if this is a new minimum. */
  252. if (d < dmin) {
  253. dmin = d;
  254. rc = (uint16_t) f;
  255. /* Set new skip speed and frequency index. */
  256. on[3] = (i << 5) | s;
  257. /* We can stop earlier with this fit. */
  258. if (i > 1) {
  259. ie = i - 2;
  260. }
  261. }
  262. }
  263. }
  264. mode = VsCodecMode(dev, VS_SM_RESET, VS_SM_RESET);
  265. #ifdef VS_SM_TESTS
  266. VsCodecMode(dev, mode | VS_SM_TESTS, 0xffff);
  267. #endif
  268. (*dcb->dcb_senddata)(on, sizeof(on));
  269. } else {
  270. (*dcb->dcb_senddata)(off, sizeof(off));
  271. #ifdef VS_SM_TESTS
  272. VsCodecMode(dev, VS_SM_RESET, VS_SM_RESET | VS_SM_TESTS);
  273. #else
  274. VsCodecMode(dev, VS_SM_RESET, VS_SM_RESET);
  275. #endif
  276. VsCodecMode(dev, mode, 0xffff);
  277. }
  278. return rc;
  279. }
  280. /*
  281. * Initialize the stream output buffer with a given size.
  282. *
  283. * \param dev Specifies the audio codec device.
  284. */
  285. int VsDecoderBufferInit(NUTDEVICE *dev, uint32_t size)
  286. {
  287. VSDCB *dcb = (VSDCB *)dev->dev_dcb;
  288. /* Make sure that the decoder is idle. */
  289. if (dcb->dcb_pbstat != CODEC_STATUS_IDLE) {
  290. return -1;
  291. }
  292. /* Set new buffer size. */
  293. if (NutSegBufInit((size_t)size) == NULL) {
  294. return -1;
  295. }
  296. /* Set watermark defaults. */
  297. dcb->dcb_pbwlo = NutSegBufAvailable() / 3;
  298. dcb->dcb_pbwhi = dcb->dcb_pbwlo * 2;
  299. return 0;
  300. }
  301. /*
  302. * VLSI decoder feeding thread.
  303. */
  304. THREAD(FeederThread, arg)
  305. {
  306. uint8_t *bp;
  307. size_t avail;
  308. int filled;
  309. uint_fast8_t intest = 0;
  310. uint_fast16_t idlefill = 0;
  311. NUTDEVICE *dev = (NUTDEVICE *)arg;
  312. VSDCB *dcb = (VSDCB *)dev->dev_dcb;
  313. /* We are a high priority thread. */
  314. NutThreadSetPriority(7);
  315. for (;;) {
  316. /*
  317. ** Idle mode processing.
  318. */
  319. if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
  320. /* Loop while in test mode. */
  321. do {
  322. /* Wait for a request or a buffer update. */
  323. NutEventWait(&dcb->dcb_feedme, NUT_WAIT_INFINITE);
  324. /* Process beep commands. */
  325. if (dcb->dcb_scmd & VSREQ_BEEP) {
  326. if ((*dcb->dcb_isready)()) {
  327. dcb->dcb_scmd &= ~VSREQ_BEEP;
  328. intest = VsCodecBeep(dev, dcb->dcb_sinefreq) != 0;
  329. }
  330. }
  331. } while (intest);
  332. /* Check if we should change to record mode. */
  333. if (dcb->dcb_scmd & VSREQ_RECORD) {
  334. dcb->dcb_scmd &= ~(VSREQ_RECORD | VSREQ_CANCEL);
  335. dcb->dcb_pbstat = CODEC_STATUS_RECORDING;
  336. /* Activate the encoder. */
  337. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AIADDR_REG, 0x0034);
  338. }
  339. /* Check if we should change to play mode. This will happen
  340. ** if we receive a play request or if the buffer contents
  341. ** reaches the high watermark. */
  342. else if ((dcb->dcb_scmd & VSREQ_PLAY) != 0 || NutSegBufUsed() >= dcb->dcb_pbwhi) {
  343. dcb->dcb_scmd &= ~(VSREQ_PLAY | VSREQ_CANCEL);
  344. dcb->dcb_pbstat = CODEC_STATUS_PLAYING;
  345. VsDecoderSetVolume(dev, dcb->dcb_lvol, dcb->dcb_rvol);
  346. }
  347. }
  348. /*
  349. ** Play mode processing.
  350. */
  351. if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
  352. /* Wait while decoder is busy. */
  353. VsCodecWaitReady(dev, NUT_WAIT_INFINITE);
  354. /* Process cancel requests. */
  355. if (dcb->dcb_scmd & VSREQ_CANCEL) {
  356. dcb->dcb_scmd &= ~VSREQ_CANCEL;
  357. NutSegBufReset();
  358. #if VS_HAS_SM_CANCEL
  359. VsCodecMode(dev, VS_SM_CANCEL, VS_SM_CANCEL);
  360. #endif
  361. }
  362. /* Retrieve new data from the input buffer. */
  363. bp = (uint8_t *) NutSegBufReadRequest(&avail);
  364. if (avail) {
  365. /* More data available, send as much as possible to the
  366. ** decoder. If no data was sent, then the bus may be
  367. ** blocked by another device. */
  368. filled = (*dcb->dcb_senddata)(bp, avail);
  369. if (filled) {
  370. /* Update the buffer's read position. */
  371. NutSegBufReadLast(filled);
  372. NutEventPost(&dcb->dcb_bufque);
  373. idlefill = 2048;
  374. }
  375. if (dcb->dcb_scmd & VSREQ_VOLUPD) {
  376. VsDecoderSetVolume(dev, dcb->dcb_lvol, dcb->dcb_rvol);
  377. dcb->dcb_scmd &= ~VSREQ_VOLUPD;
  378. }
  379. if (dcb->dcb_scmd & VSREQ_AUDIOE) {
  380. VsDecoderSetBass( dev, dcb->dcb_treb, dcb->dcb_tfin, dcb->dcb_bass, dcb->dcb_bfin);
  381. dcb->dcb_scmd &= ~VSREQ_AUDIOE;
  382. }
  383. } else if (NutSegBufUsed() == 0) {
  384. /* Running out of data. */
  385. if (idlefill) {
  386. /* For some reason the HDAT0/HDAT1 registers in the
  387. ** VS1053 do not contain zero when the codec runs
  388. ** empty. I expected this when reading the datasheet.
  389. ** Instead we fill the buffer with zeros, to make
  390. ** sure that the whole buffer is decoded before we
  391. ** enter idle mode. */
  392. idlefill -= (*dcb->dcb_senddata)(NULL, idlefill);
  393. }
  394. if (idlefill == 0) {
  395. /* Finally we reached idle mode. */
  396. dcb->dcb_pbstat = CODEC_STATUS_IDLE;
  397. NutEventPost(&dcb->dcb_bufque);
  398. }
  399. }
  400. }
  401. /*
  402. ** Record mode processing.
  403. */
  404. else if (dcb->dcb_pbstat == CODEC_STATUS_RECORDING) {
  405. for (;;) {
  406. /* Process cancel requests. */
  407. if (dcb->dcb_scmd & VSREQ_CANCEL) {
  408. dcb->dcb_scmd &= ~VSREQ_CANCEL;
  409. dcb->dcb_pbstat = CODEC_STATUS_IDLE;
  410. break;
  411. }
  412. bp = (uint8_t *)NutSegBufWriteRequest(&avail);
  413. avail >>= 1;
  414. if (avail == 0) {
  415. /* Buffer overflow. */
  416. dcb->dcb_pbstat = CODEC_STATUS_IDLE;
  417. break;
  418. }
  419. #if defined(VS_HDAT0_REG) && defined(VS_HDAT1_REG)
  420. /* TODO: Missing register definitions give compiler error. */
  421. filled = VsCodecReg(dev, VS_OPCODE_READ, VS_HDAT1_REG, 0);
  422. if (filled > 255) {
  423. if (avail > filled) {
  424. avail = filled;
  425. } else {
  426. filled = avail;
  427. }
  428. (*dcb->dcb_recvdata)(bp, filled << 1);
  429. NutSegBufWriteLast(avail << 1);
  430. NutEventPost(&dcb->dcb_bufque);
  431. } else {
  432. NutSleep(200);
  433. }
  434. #endif
  435. }
  436. NutEventPost(&dcb->dcb_bufque);
  437. }
  438. }
  439. }
  440. /* TODO: This is a preview and may not work as expected. */
  441. static int VsCodecLoadPlugIn(NUTDEVICE *dev, VS_PLUGIN_INFO *plg)
  442. {
  443. uint_fast8_t reg;
  444. uint_fast16_t cnt;
  445. size_t i = 0;
  446. #ifdef VS_SM_ADPCM
  447. VsCodecMode(dev, 0, VS_SM_ADPCM);
  448. #endif
  449. VsCodecReg(dev, VS_OPCODE_WRITE, VS_CLOCKF_REG, 0xC000);
  450. NutSleep(100);
  451. #if VS_HAS_BASS_REG
  452. VsCodecReg(dev, VS_OPCODE_WRITE, VS_BASS_REG, 0);
  453. #endif
  454. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AIADDR_REG, 0);
  455. VsCodecReg(dev, VS_OPCODE_WRITE, VS_WRAMADDR_REG, 0xC01A);
  456. VsCodecReg(dev, VS_OPCODE_WRITE, VS_WRAM_REG, 0x0002);
  457. while (i + 3 <= plg->vsplg_size) {
  458. reg = (uint_fast8_t)plg->vsplg_data[i++];
  459. cnt = plg->vsplg_data[i++];
  460. if (cnt & 0x8000) {
  461. cnt &= 0x7FFF;
  462. while (cnt--) {
  463. VsCodecReg(dev, VS_OPCODE_WRITE, reg, plg->vsplg_data[i]);
  464. }
  465. i++;
  466. }
  467. else if (i + cnt <= plg->vsplg_size) {
  468. while (cnt--) {
  469. VsCodecReg(dev, VS_OPCODE_WRITE, reg, plg->vsplg_data[i]);
  470. i++;
  471. }
  472. }
  473. else {
  474. break;
  475. }
  476. }
  477. if (i != plg->vsplg_size) {
  478. return -1;
  479. }
  480. #ifdef VS_SM_ADPCM
  481. // set bits 12 and 13 of register SCI_MODE
  482. // 12 is the ADPCM bit, 13 is the MIC/LINE bit.
  483. VsCodecMode(dev, VS_SM_LINE_IN | VS_SM_ADPCM, VS_SM_LINE_IN | VS_SM_ADPCM);
  484. #endif
  485. #if VS_HAS_AICTRL0_REG
  486. // write 0 to SCI_AICTRL0 (maximum signal level, set by encoder to read later on)
  487. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AICTRL0_REG, 0);
  488. #endif
  489. // recording gain 0: automatic gain control on
  490. //CodecReg(&codec_node, VS_OPCODE_WRITE, VS_AICTRL1_REG, 0);
  491. #if VS_HAS_AICTRL1_REG
  492. // recording gain 1
  493. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AICTRL1_REG, 1024);
  494. #endif
  495. #if VS_HAS_AICTRL2_REG
  496. // maximum autogain amplification, 4096 (=4x) is recommended
  497. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AICTRL2_REG, 4096);
  498. #endif
  499. #if VS_HAS_AICTRL3_REG
  500. // setting SCI_AICTRL3 should be fine, too...
  501. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AICTRL3_REG, 0);
  502. #endif
  503. return 0;
  504. }
  505. static int VsCodecWriteWRam(NUTDEVICE *dev, VS_WRAM_DATA *vswd)
  506. {
  507. size_t i;
  508. if (vswd == NULL) {
  509. /*
  510. * Initialize data transfer.
  511. */
  512. #ifdef VS_SM_ADPCM
  513. VsCodecMode(dev, 0, VS_SM_ADPCM);
  514. #endif
  515. /* Set clock to 4.5x = 55.3 MHz. */
  516. VsCodecReg(dev, VS_OPCODE_WRITE, VS_CLOCKF_REG, 0xC000);
  517. NutSleep(100);
  518. #if VS_HAS_BASS_REG
  519. /* Clear SCI bass register. */
  520. VsCodecReg(dev, VS_OPCODE_WRITE, VS_BASS_REG, 0);
  521. #endif
  522. /* Disable all interrupts except SCI. */
  523. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AIADDR_REG, 0);
  524. VsCodecReg(dev, VS_OPCODE_WRITE, VS_WRAMADDR_REG, 0xC01A);
  525. VsCodecReg(dev, VS_OPCODE_WRITE, VS_WRAM_REG, 0x0002);
  526. }
  527. else if (vswd->vswd_data) {
  528. /*
  529. * Transfer data, if available.
  530. */
  531. VsCodecReg(dev, VS_OPCODE_WRITE, VS_WRAMADDR_REG, vswd->vswd_addr);
  532. for (i = 0; i < vswd->vswd_size; i++) {
  533. VsCodecReg(dev, VS_OPCODE_WRITE, VS_WRAM_REG, vswd->vswd_data[i]);
  534. }
  535. } else {
  536. /*
  537. * All data transfered.
  538. */
  539. #ifdef VS_SM_ADPCM
  540. VsCodecMode(dev, VS_SM_LINE_IN | VS_SM_ADPCM, VS_SM_LINE_IN | VS_SM_ADPCM);
  541. #endif
  542. #if VS_HAS_AICTRL0_REG
  543. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AICTRL0_REG, 0);
  544. #endif
  545. #if VS_HAS_AICTRL1_REG
  546. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AICTRL1_REG, 1024);
  547. #endif
  548. #if VS_HAS_AICTRL2_REG
  549. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AICTRL2_REG, 4096);
  550. #endif
  551. #if VS_HAS_AICTRL3_REG
  552. VsCodecReg(dev, VS_OPCODE_WRITE, VS_AICTRL3_REG, 0);
  553. #endif
  554. }
  555. return 0;
  556. }
  557. /*!
  558. * \brief Handle I/O controls for audio codec.
  559. *
  560. * \param dev Specifies the audio codec device.
  561. *
  562. * - AUDIO_PLAY Force playback start, even if the buffer level is too lower.
  563. * - AUDIO_CANCEL Cancel playback and discard all buffered data.
  564. * - AUDIO_GET_STATUS Sets an int to 1 if the player is running, 0 if idle.
  565. * - AUDIO_GET_PLAYGAIN Sets an int to the current playback gain, 0..-127.
  566. * - AUDIO_SET_PLAYGAIN Reads the requested playback gain from an int, 0..-127.
  567. * - AUDIO_GET_PBSIZE Sets an unsigned long with the size of the playback buffer.
  568. * - AUDIO_SET_PBSIZE Sets the size the playback buffer using an unsigned long.
  569. * - AUDIO_GET_PBLEVEL Sets an unsigned long with the number of bytes in the playback buffer.
  570. * - AUDIO_GET_PBWLOW Sets an unsigned long with the low watermark of the playback buffer.
  571. * - AUDIO_SET_PBWLOW Sets the low watermark (unsigned long) of the playback buffer.
  572. * - AUDIO_GET_PBWHIGH Sets an unsigned long with the high watermark of the playback buffer.
  573. * - AUDIO_SET_PBWHIGH Sets the high watermark (unsigned long) of the playback buffer.
  574. * - AUDIO_BEEP Plays a short sine wave beep.
  575. *
  576. * \return 0 on success, -1 otherwise.
  577. */
  578. int VsCodecIOCtl(NUTDEVICE * dev, int req, void *conf)
  579. {
  580. int rc = 0;
  581. uint32_t *lvp = (uint32_t *) conf;
  582. int *ivp = (int *) conf;
  583. VSDCB *dcb = (VSDCB *)dev->dev_dcb;
  584. switch (req) {
  585. case AUDIO_PLAY:
  586. if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
  587. /* Immediately start playing. */
  588. dcb->dcb_scmd |= VSREQ_PLAY;
  589. }
  590. NutEventPost(&dcb->dcb_feedme);
  591. break;
  592. case AUDIO_CANCEL:
  593. if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
  594. /* Immediately stop playing and discard buffer. */
  595. dcb->dcb_scmd |= VSREQ_CANCEL;
  596. }
  597. NutEventPost(&dcb->dcb_feedme);
  598. break;
  599. case AUDIO_GET_STATUS:
  600. *ivp = dcb->dcb_pbstat;
  601. break;
  602. case AUDIO_GET_PLAYGAIN:
  603. *ivp = dcb->dcb_rvol > dcb->dcb_lvol ? dcb->dcb_rvol : dcb->dcb_lvol;
  604. break;
  605. case AUDIO_SET_PLAYGAIN:
  606. dcb->dcb_lvol = *ivp;
  607. dcb->dcb_rvol = *ivp;
  608. dcb->dcb_scmd |= VSREQ_VOLUPD;
  609. break;
  610. case AUDIO_SET_TREB:
  611. dcb->dcb_treb = *ivp;
  612. dcb->dcb_scmd |= VSREQ_AUDIOE;
  613. break;
  614. case AUDIO_SET_TFIN:
  615. dcb->dcb_tfin = *ivp;
  616. dcb->dcb_scmd |= VSREQ_AUDIOE;
  617. break;
  618. case AUDIO_SET_BASS:
  619. dcb->dcb_bass = *ivp;
  620. dcb->dcb_scmd |= VSREQ_AUDIOE;
  621. break;
  622. case AUDIO_SET_BFIN:
  623. dcb->dcb_bfin = *ivp;
  624. dcb->dcb_scmd |= VSREQ_AUDIOE;
  625. break;
  626. case AUDIO_GET_PBSIZE:
  627. *lvp = NutSegBufAvailable() + NutSegBufUsed();
  628. break;
  629. case AUDIO_SET_PBSIZE:
  630. rc = VsDecoderBufferInit(dev, *lvp);
  631. break;
  632. case AUDIO_GET_PBLEVEL:
  633. *lvp = NutSegBufUsed();
  634. break;
  635. case AUDIO_GET_PBWLOW:
  636. *lvp = dcb->dcb_pbwlo;
  637. break;
  638. case AUDIO_SET_PBWLOW:
  639. dcb->dcb_pbwlo = *lvp;
  640. break;
  641. case AUDIO_GET_PBWHIGH:
  642. *lvp = dcb->dcb_pbwhi;
  643. break;
  644. case AUDIO_SET_PBWHIGH:
  645. dcb->dcb_pbwhi = *lvp;
  646. break;
  647. case AUDIO_SETWRITETIMEOUT:
  648. dcb->dcb_wtmo = *lvp;
  649. break;
  650. case AUDIO_GETWRITETIMEOUT:
  651. *lvp = dcb->dcb_wtmo;
  652. break;
  653. case AUDIO_BEEP:
  654. if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
  655. dcb->dcb_sinefreq = *((uint16_t *) conf);
  656. dcb->dcb_scmd |= VSREQ_BEEP;
  657. NutEventPost(&dcb->dcb_feedme);
  658. } else {
  659. rc = -1;
  660. }
  661. break;
  662. case AUDIO_GET_DECCAPS:
  663. /* Retrieve decoder capabilities. */
  664. *lvp = dcb->dcb_dec_caps;
  665. break;
  666. case AUDIO_GET_CODCAPS:
  667. /* Retrieve encoder capabilities. */
  668. *lvp = dcb->dcb_cod_caps;
  669. break;
  670. case AUDIO_GET_MIDCAPS:
  671. /* Retrieve midi capabilities. */
  672. *lvp = dcb->dcb_midi_caps;
  673. break;
  674. #if 0
  675. case AUDIO_GET_DECINFO:
  676. /* Retrieve decoder information. */
  677. break;
  678. case AUDIO_GET_CODINFO:
  679. /* Retrieve encoder information. */
  680. break;
  681. case AUDIO_GET_MIDINFO:
  682. /* Retrieve midi information. */
  683. break;
  684. #endif
  685. case AUDIO_PLUGIN_UPLOAD:
  686. rc = VsCodecLoadPlugIn(dev, (VS_PLUGIN_INFO *) conf);
  687. break;
  688. case AUDIO_WRITE_CMEM:
  689. VsCodecWriteWRam(dev, (VS_WRAM_DATA *) conf);
  690. break;
  691. default:
  692. rc = (*dcb->dcb_control)(req, conf);
  693. break;
  694. }
  695. return rc;
  696. }
  697. /*!
  698. * \brief Flush VLSI audio decoder buffer.
  699. *
  700. * Waits until all currently buffered data had been processed by the
  701. * decoder. This makes sure that the end of the stream will not be
  702. * cut off.
  703. *
  704. * \param dev Specifies the audio codec device.
  705. * \param tmo Timeout in milliseconds.
  706. *
  707. * \return 0 on success, -1 on timeout.
  708. */
  709. static int VsDecoderBufferFlush(NUTDEVICE *dev, uint32_t tmo)
  710. {
  711. int rc = 0;
  712. VSDCB *dcb = dev->dev_dcb;
  713. for (;;) {
  714. /* Keep the player running if the buffer contains data. */
  715. if (NutSegBufUsed()) {
  716. VsCodecIOCtl(dev, AUDIO_PLAY, NULL);
  717. }
  718. /* No data in buffer. If idle, then we are done. */
  719. else if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
  720. /* No data and player is idle. */
  721. break;
  722. }
  723. /* Wait for a new buffer update. */
  724. rc = NutEventWait(&dcb->dcb_bufque, tmo);
  725. if (rc) {
  726. break;
  727. }
  728. }
  729. return rc;
  730. }
  731. /*!
  732. * \brief Read from the encoder.
  733. *
  734. * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
  735. * call to VsCodecOpen().
  736. * \param data Pointer to the data buffer. If NULL, the buffered data
  737. * will be flushed.
  738. * \param len Number of bytes to read. If 0, all buffered data will be
  739. * flushed.
  740. *
  741. * \return Number of characters sent. If a read timeout had been set,
  742. * then this may be less than the specified length.
  743. */
  744. int VsCodecRead(NUTFILE * nfp, void *data, int len)
  745. {
  746. int rc = 0;
  747. uint8_t *bp;
  748. uint8_t *dp;
  749. size_t rbytes;
  750. NUTDEVICE *dev;
  751. VSDCB *dcb;
  752. dev = nfp->nf_dev;
  753. dcb = dev->dev_dcb;
  754. /* Flush buffer if data pointer is a NULL pointer. */
  755. if (data == NULL || len == 0) {
  756. return 0;
  757. }
  758. if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
  759. /* Cannot read decoder data. */
  760. return -1;
  761. } else if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
  762. /* Start recording if idle. */
  763. if (dcb->dcb_cod_mode & AUDIO_FMT_VORBIS) {
  764. }
  765. dcb->dcb_scmd |= VSREQ_RECORD;
  766. NutEventPost(&dcb->dcb_feedme);
  767. }
  768. dp = data;
  769. while (len) {
  770. /* Retrieve new data from the input buffer. */
  771. bp = (uint8_t *) NutSegBufReadRequest(&rbytes);
  772. if (rbytes) {
  773. if (rbytes > len) {
  774. rbytes = len;
  775. }
  776. memcpy(dp, bp, rbytes);
  777. NutSegBufReadLast(rbytes);
  778. NutEventPost(&dcb->dcb_feedme);
  779. len -= rbytes;
  780. rc += rbytes;
  781. dp += rbytes;
  782. }
  783. /* Wait for data. */
  784. else if (NutEventWait(&dcb->dcb_bufque, dcb->dcb_rtmo)) {
  785. /* Read timeout. */
  786. break;
  787. }
  788. }
  789. return rc;
  790. }
  791. /*!
  792. * \brief Write to decoder.
  793. *
  794. * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
  795. * call to VsCodecOpen().
  796. * \param data Pointer to the data buffer. If NULL, the buffered data
  797. * will be flushed.
  798. * \param len Number of bytes that are available in the buffer. If 0,
  799. * all buffered data will be flushed.
  800. *
  801. * \return Number of characters sent. If a write timeout had been set,
  802. * then this may be less than the specified length.
  803. */
  804. int VsCodecWrite(NUTFILE * nfp, const void *data, int len)
  805. {
  806. int rc = 0;
  807. uint8_t *bp;
  808. const uint8_t *dp;
  809. size_t rbytes;
  810. VSDCB *dcb = nfp->nf_dev->dev_dcb;
  811. /* Flush buffer if data pointer is a NULL pointer. */
  812. if (data == NULL || len == 0) {
  813. return VsDecoderBufferFlush(nfp->nf_dev, dcb->dcb_wtmo);
  814. }
  815. dp = data;
  816. while (len) {
  817. bp = (uint8_t *)NutSegBufWriteRequest(&rbytes);
  818. if (rbytes == 0) {
  819. /* No buffer space, wait for change. */
  820. if (NutEventWait(&dcb->dcb_bufque, dcb->dcb_wtmo)) {
  821. /* Write timeout. */
  822. break;
  823. }
  824. } else {
  825. if (rbytes > len) {
  826. rbytes = len;
  827. }
  828. memcpy(bp, dp, rbytes);
  829. NutSegBufWriteLast(rbytes);
  830. NutEventPost(&dcb->dcb_feedme);
  831. len -= rbytes;
  832. rc += rbytes;
  833. dp += rbytes;
  834. }
  835. }
  836. return rc;
  837. }
  838. #ifdef __HARVARD_ARCH__
  839. /*!
  840. * \brief Write program data to decoder.
  841. *
  842. * Similar to VsCodecWrite() except that the data is expected in program memory.
  843. *
  844. * This function is implemented for CPUs with Harvard Architecture only.
  845. *
  846. * This function is called by the low level output routines of the
  847. * \ref xrCrtLowio "C runtime library", using the
  848. * \ref _NUTDEVICE::dev_write_P entry.
  849. *
  850. * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
  851. * call to VsCodecOpen().
  852. * \param buffer Pointer to the data in program space. If zero, then the
  853. * output buffer will be flushed.
  854. * \param len Number of bytes to write.
  855. *
  856. * \return The number of bytes written. A return value of -1 indicates an
  857. * error. Currently this function is not implemented and always
  858. * returns -1.
  859. *
  860. */
  861. int VsCodecWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
  862. {
  863. return -1;
  864. }
  865. #endif
  866. /*
  867. * Open codec stream.
  868. */
  869. NUTFILE *VsCodecOpen(NUTDEVICE * dev, const char *name, int mode, int acc)
  870. {
  871. NUTFILE *nfp;
  872. VSDCB *dcb;
  873. #if defined(VS_SW_RESET_ON_OPEN)
  874. VsCodecMode(dev, VS_SM_RESET, VS_SM_RESET);
  875. #endif
  876. dcb = dev->dev_dcb;
  877. if (mode & _O_WRONLY) {
  878. uint32_t on = 1;
  879. /* Decoder. */
  880. if (VsCodecIOCtl(dev, AUDIO_IRQ_ENABLE, &on)) {
  881. return NULL;
  882. }
  883. } else {
  884. /* Encoder. */
  885. if (strcmp(name, "vorbis") == 0) {
  886. dcb->dcb_cod_mode = AUDIO_FMT_VORBIS;
  887. } else {
  888. dcb->dcb_cod_mode = AUDIO_FMT_WAV_IMA_ADPCM;
  889. }
  890. }
  891. nfp = malloc(sizeof(NUTFILE));
  892. if (nfp) {
  893. nfp->nf_dev = dev;
  894. nfp->nf_fcb = NULL;
  895. }
  896. NutSegBufReset();
  897. return nfp;
  898. }
  899. /*
  900. * Close codec stream.
  901. */
  902. int VsCodecClose(NUTFILE * nfp)
  903. {
  904. VSDCB *dcb = nfp->nf_dev->dev_dcb;
  905. int rc = VsDecoderBufferFlush(nfp->nf_dev, dcb->dcb_wtmo);
  906. if (nfp) {
  907. free(nfp);
  908. }
  909. return rc;
  910. }
  911. /*@}*/