11use anyhow:: Result ;
2+ use core:: cmp:: max;
23use embedded_hal:: spi:: { Operation , SpiDevice } ;
34use esp_idf_hal:: gpio:: { InputPin , OutputPin , PinDriver } ;
45use log:: warn;
56use std:: { ffi:: CStr , str, thread:: sleep, time:: Duration } ;
67
78const VS1053_CHUNK_SIZE : u8 = 32 ;
9+
810// SCI Register
911const SCI_MODE : u8 = 0x0 ;
1012const SCI_STATUS : u8 = 0x1 ;
@@ -19,6 +21,7 @@ const SCI_VOL: u8 = 0xB;
1921const SCI_AICTRL0 : u8 = 0xC ;
2022const SCI_AICTRL1 : u8 = 0xD ;
2123const SCI_NUM_REGISTERS : u8 = 0xF ;
24+
2225// SCI_MODE bits
2326const SM_SDINEW : u8 = 11 ; // Bitnumber in SCI_MODE always on
2427const SM_RESET : u8 = 2 ; // Bitnumber in SCI_MODE soft reset
@@ -58,13 +61,17 @@ fn contains(str: *const u8, substr: &str) -> bool {
5861 false
5962}
6063
64+ fn map ( x : i64 , in_min : i64 , in_max : i64 , out_min : i64 , out_max : i64 ) -> i64 {
65+ ( x - in_min) * ( out_max - out_min) / ( in_max - in_min) + out_min
66+ }
67+
6168pub struct VS1053 < SPI , XCS , XDCS , DREQ > {
6269 spi : SPI ,
6370 low_spi : SPI ,
6471 xcs_pin : XCS ,
6572 xdcs_pin : XDCS ,
6673 dreq_pin : DREQ ,
67- current_volume : i8 ,
74+ current_volume : u8 ,
6875 current_balance : i8 ,
6976}
7077
@@ -274,13 +281,13 @@ where
274281 // // Will give warnings on serial output if DEBUG is active.
275282 // // A maximum of 20 errors will be reported.
276283
277- let ( mut r1, mut r2, mut cnt) : ( u16 , u16 , u16 ) = ( 0 , 0 , 0 ) ;
284+ let ( mut r1, mut r2) ;
285+ let mut cnt = 0 ;
278286 let mut delta: usize = 300 ; // 3 for fast SPI
279-
287+
280288 if contains ( header, "Fast" ) {
281289 delta = 3 ; // Fast SPI, more loops
282290 }
283-
284291 log:: info!( "header:{:?}" , header) ;
285292
286293 for i in ( 0 ..0xFFFF ) . step_by ( delta) {
@@ -296,10 +303,299 @@ where
296303 cnt += 1 ;
297304 sleep ( Duration :: from_millis ( 10 ) ) ;
298305 }
299- // yield(); // Allow ESP firmware to do some bookkeeping
306+ // yield(); // Allow ESP firmware to do some bookkeeping
300307 }
301308 return cnt == 0 ; // Return the result
302309 }
310+
311+ fn set_volume ( & mut self , vol : u8 ) -> Result < ( ) , DSPError > {
312+ // Set volume. Both left and right.
313+ // Input value is 0..100. 100 is the loudest.
314+ let ( mut value_l, mut value_r) ; // Values to send to SCI_VOL
315+
316+ self . current_volume = vol; // Save for later use
317+ value_l = vol;
318+ value_r = vol;
319+
320+ if self . current_balance < 0 {
321+ value_r = max ( 0 , vol. saturating_add ( self . current_balance as u8 ) ) ;
322+ } else if self . current_balance > 0 {
323+ value_l = max ( 0 , vol. saturating_sub ( self . current_balance as u8 ) ) ;
324+ }
325+
326+ value_l = map ( value_l. into ( ) , 0 , 100 , 0xFE , 0x00 ) as u8 ; // 0..100% to left channel
327+ value_r = map ( value_r. into ( ) , 0 , 100 , 0xFE , 0x00 ) as u8 ; // 0..100% to right channel
328+
329+ self . write_register ( true , SCI_VOL , ( ( value_l as u16 ) << 8 ) | value_r as u16 ) // Volume left and right
330+ }
331+
332+ fn set_balance ( & mut self , balance : i8 ) {
333+ if balance > 100 {
334+ self . current_balance = 100 ;
335+ } else if balance < -100 {
336+ self . current_balance = -100 ;
337+ } else {
338+ self . current_balance = balance;
339+ }
340+ }
341+
342+ // fn setTone(uint8_t *rtone) { // Set bass/treble (4 nibbles)
343+ // // Set tone characteristics. See documentation for the 4 nibbles.
344+ // uint16_t value = 0; // Value to send to SCI_BASS
345+ // int i; // Loop control
346+
347+ // for (i = 0; i < 4; i++) {
348+ // value = (value << 4) | rtone[i]; // Shift next nibble in
349+ // }
350+ // writeRegister(SCI_BASS, value); // Volume left and right
351+ // }
352+
353+ fn get_volume ( & mut self ) -> u8 { // Get the current volume setting.
354+ return self . current_volume ;
355+ }
356+
357+ fn get_balance ( & mut self ) -> i8 { // Get the current balance setting.
358+ return self . current_balance ;
359+ }
360+
361+ // fn startSong() {
362+ // sdi_send_fillers(10);
363+ // }
364+
365+ // fn playChunk(uint8_t *data, size_t len) {
366+ // sdi_send_buffer(data, len);
367+ // }
368+
369+ // fn stopSong() {
370+ // uint16_t modereg; // Read from mode register
371+ // int i; // Loop control
372+
373+ // sdi_send_fillers(2052);
374+ // delay(10);
375+ // writeRegister(SCI_MODE, _BV(SM_SDINEW) | _BV(SM_CANCEL));
376+ // for (i = 0; i < 200; i++) {
377+ // sdi_send_fillers(32);
378+ // modereg = read_register(SCI_MODE); // Read status
379+ // if ((modereg & _BV(SM_CANCEL)) == 0) {
380+ // sdi_send_fillers(2052);
381+ // LOG("Song stopped correctly after %d msec\n", i * 10);
382+ // return;
383+ // }
384+ // delay(10);
385+ // }
386+ // printDetails("Song stopped incorrectly!");
387+ // }
388+
389+ // fn softReset() {
390+ // LOG("Performing soft-reset\n");
391+ // writeRegister(SCI_MODE, _BV(SM_SDINEW) | _BV(SM_RESET));
392+ // delay(10);
393+ // await_data_request();
394+ // }
395+
396+ // /**
397+ // * VLSI datasheet: "SM_STREAM activates VS1053b’s stream mode. In this mode, data should be sent with as
398+ // * even intervals as possible and preferable in blocks of less than 512 bytes, and VS1053b makes
399+ // * every attempt to keep its input buffer half full by changing its playback speed up to 5%. For best
400+ // * quality sound, the average speed error should be within 0.5%, the bitrate should not exceed
401+ // * 160 kbit/s and VBR should not be used. For details, see Application Notes for VS10XX. This
402+ // * mode only works with MP3 and WAV files."
403+ // */
404+
405+ // fn streamModeOn() {
406+ // LOG("Performing streamModeOn\n");
407+ // writeRegister(SCI_MODE, _BV(SM_SDINEW) | _BV(SM_STREAM));
408+ // delay(10);
409+ // await_data_request();
410+ // }
411+
412+ // fn streamModeOff() {
413+ // LOG("Performing streamModeOff\n");
414+ // writeRegister(SCI_MODE, _BV(SM_SDINEW));
415+ // delay(10);
416+ // await_data_request();
417+ // }
418+
419+ // fn printDetails(const char *header) {
420+ // uint16_t regbuf[16];
421+ // uint8_t i;
422+ // (void)regbuf;
423+
424+ // LOG("%s", header);
425+ // LOG("REG Contents\n");
426+ // LOG("--- -----\n");
427+ // for (i = 0; i <= SCI_num_registers; i++) {
428+ // regbuf[i] = read_register(i);
429+ // }
430+ // for (i = 0; i <= SCI_num_registers; i++) {
431+ // delay(5);
432+ // LOG("%3X - %5X\n", i, regbuf[i]);
433+ // }
434+ // }
435+
436+ // /**
437+ // * An optional switch.
438+ // * Most VS1053 modules will start up in MIDI mode. The result is that there is no audio when playing MP3.
439+ // * You can modify the board, but there is a more elegant way without soldering.
440+ // * No side effects for boards which do not need this switch. It means you can call it just in case.
441+ // *
442+ // * Read more here: http://www.bajdi.com/lcsoft-vs1053-mp3-module/#comment-33773
443+ // */
444+ // fn switchToMp3Mode() {
445+ // wram_write(ADDR_REG_GPIO_DDR_RW, 3); // GPIO DDR = 3
446+ // wram_write(ADDR_REG_GPIO_ODATA_RW, 0); // GPIO ODATA = 0
447+ // delay(100);
448+ // LOG("Switched to mp3 mode\n");
449+ // softReset();
450+ // }
451+
452+ // fn disableI2sOut() {
453+ // wram_write(ADDR_REG_I2S_CONFIG_RW, 0x0000);
454+
455+ // // configure GPIO0 4-7 (I2S) as input (default)
456+ // // leave other GPIOs unchanged
457+ // uint16_t cur_ddr = wram_read(ADDR_REG_GPIO_DDR_RW);
458+ // wram_write(ADDR_REG_GPIO_DDR_RW, cur_ddr & ~0x00f0);
459+ // }
460+
461+ // fn enableI2sOut(VS1053_I2S_RATE i2sRate) {
462+ // // configure GPIO0 4-7 (I2S) as output
463+ // // leave other GPIOs unchanged
464+ // uint16_t cur_ddr = wram_read(ADDR_REG_GPIO_DDR_RW);
465+ // wram_write(ADDR_REG_GPIO_DDR_RW, cur_ddr | 0x00f0);
466+
467+ // uint16_t i2s_config = 0x000c; // Enable MCLK(3); I2S(2)
468+ // switch (i2sRate) {
469+ // case VS1053_I2S_RATE_192_KHZ:
470+ // i2s_config |= 0x0002;
471+ // break;
472+ // case VS1053_I2S_RATE_96_KHZ:
473+ // i2s_config |= 0x0001;
474+ // break;
475+ // default:
476+ // case VS1053_I2S_RATE_48_KHZ:
477+ // // 0x0000
478+ // break;
479+ // }
480+
481+ // wram_write(ADDR_REG_I2S_CONFIG_RW, i2s_config );
482+ // }
483+
484+ // /**
485+ // * A lightweight method to check if VS1053 is correctly wired up (power supply and connection to SPI interface).
486+ // *
487+ // * @return true if the chip is wired up correctly
488+ // */
489+ // bool VS1053::isChipConnected() {
490+ // uint16_t status = read_register(SCI_STATUS);
491+
492+ // return !(status == 0 || status == 0xFFFF);
493+ // }
494+
495+ // /**
496+ // * get the Version Number for the VLSI chip
497+ // * VLSI datasheet: 0 for VS1001, 1 for VS1011, 2 for VS1002, 3 for VS1003, 4 for VS1053 and VS8053,
498+ // * 5 for VS1033, 7 for VS1103, and 6 for VS1063.
499+ // */
500+ // uint16_t VS1053::getChipVersion() {
501+ // uint16_t status = read_register(SCI_STATUS);
502+
503+ // return ( (status & 0x00F0) >> 4);
504+ // }
505+
506+ // /**
507+ // * Provides current decoded time in full seconds (from SCI_DECODE_TIME register value)
508+ // *
509+ // * When decoding correct data, current decoded time is shown in SCI_DECODE_TIME
510+ // * register in full seconds. The user may change the value of this register.
511+ // * In that case the new value should be written twice to make absolutely certain
512+ // * that the change is not overwritten by the firmware. A write to SCI_DECODE_TIME
513+ // * also resets the byteRate calculation.
514+ // *
515+ // * SCI_DECODE_TIME is reset at every hardware and software reset. It is no longer
516+ // * cleared when decoding of a file ends to allow the decode time to proceed
517+ // * automatically with looped files and with seamless playback of multiple files.
518+ // * With fast playback (see the playSpeed extra parameter) the decode time also
519+ // * counts faster. Some codecs (WMA and Ogg Vorbis) can also indicate the absolute
520+ // * play position, see the positionMsec extra parameter in section 10.11.
521+ // *
522+ // * @see VS1053b Datasheet (1.31) / 9.6.5 SCI_DECODE_TIME (RW)
523+ // *
524+ // * @return current decoded time in full seconds
525+ // */
526+ // uint16_t VS1053::getDecodedTime() {
527+ // return read_register(SCI_DECODE_TIME);
528+ // }
529+
530+ // /**
531+ // * Clears decoded time (sets SCI_DECODE_TIME register to 0x00)
532+ // *
533+ // * The user may change the value of this register. In that case the new value
534+ // * should be written twice to make absolutely certain that the change is not
535+ // * overwritten by the firmware. A write to SCI_DECODE_TIME also resets the
536+ // * byteRate calculation.
537+ // */
538+ // fn clearDecodedTime() {
539+ // writeRegister(SCI_DECODE_TIME, 0x00);
540+ // writeRegister(SCI_DECODE_TIME, 0x00);
541+ // }
542+
543+ // /**
544+ // * Fine tune the data rate
545+ // */
546+ // fn adjustRate(long ppm2) {
547+ // writeRegister(SCI_WRAMADDR, 0x1e07);
548+ // writeRegister(SCI_WRAM, ppm2);
549+ // writeRegister(SCI_WRAM, ppm2 >> 16);
550+ // // oldClock4KHz = 0 forces adjustment calculation when rate checked.
551+ // writeRegister(SCI_WRAMADDR, 0x5b1c);
552+ // writeRegister(SCI_WRAM, 0);
553+ // // Write to AUDATA or CLOCKF checks rate and recalculates adjustment.
554+ // writeRegister(SCI_AUDATA, read_register(SCI_AUDATA));
555+ // }
556+
557+ // /**
558+ // * Load a patch or plugin
559+ // *
560+ // * Patches can be found on the VLSI Website http://www.vlsi.fi/en/support/software/vs10xxpatches.html
561+ // *
562+ // * Please note that loadUserCode only works for compressed plugins (file ending .plg).
563+ // * To include them, rename them to file ending .h
564+ // * Please also note that, in order to avoid multiple definitions, if you are using more than one patch,
565+ // * it is necessary to rename the name of the array plugin[] and the name of PLUGIN_SIZE to names of your choice.
566+ // * example: after renaming plugin[] to plugin_myname[] and PLUGIN_SIZE to PLUGIN_MYNAME_SIZE
567+ // * the method is called by player.loadUserCode(plugin_myname, PLUGIN_MYNAME_SIZE)
568+ // * It is also possible to just rename the array plugin[] to a name of your choice
569+ // * example: after renaming plugin[] to plugin_myname[]
570+ // * the method is called by player.loadUserCode(plugin_myname, sizeof(plugin_myname)/sizeof(plugin_myname[0]))
571+ // */
572+ // fn loadUserCode(const unsigned short* plugin, unsigned short plugin_size) {
573+ // int i = 0;
574+ // while (i<plugin_size) {
575+ // unsigned short addr, n, val;
576+ // addr = plugin[i++];
577+ // n = plugin[i++];
578+ // if (n & 0x8000U) { /* RLE run, replicate n samples */
579+ // n &= 0x7FFF;
580+ // val = plugin[i++];
581+ // while (n--) {
582+ // writeRegister(addr, val);
583+ // }
584+ // } else { /* Copy run, copy n samples */
585+ // while (n--) {
586+ // val = plugin[i++];
587+ // writeRegister(addr, val);
588+ // }
589+ // }
590+ // }
591+ // }
592+
593+ // /**
594+ // * Load the latest generic firmware patch
595+ // */
596+ // fn loadDefaultVs1053Patches() {
597+ // loadUserCode(PATCHES,PATCHES_SIZE);
598+ // };
303599}
304600
305601#[ derive( Copy , Clone , Debug ) ]
0 commit comments