Playing and controlling MP3s works great. \o/
This commit is contained in:
parent
fcf0e8b7d3
commit
815f11591c
@ -1,14 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "controller.h"
|
|
||||||
|
|
||||||
class Buttons {
|
|
||||||
private:
|
|
||||||
unsigned long _debounce_until = 0;
|
|
||||||
Controller* _controller;
|
|
||||||
void _debounce();
|
|
||||||
public:
|
|
||||||
Buttons(Controller* c) : _controller(c) {}
|
|
||||||
void setup();
|
|
||||||
void loop();
|
|
||||||
};
|
|
@ -1,17 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "config.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "sd_card.h"
|
#include <MFRC522.h>
|
||||||
|
|
||||||
class Controller {
|
class Controller {
|
||||||
private:
|
private:
|
||||||
|
MFRC522* _rfid;
|
||||||
|
bool _rfid_enabled = true;
|
||||||
|
void _check_rfid();
|
||||||
|
void _check_serial();
|
||||||
Player* _player;
|
Player* _player;
|
||||||
SDCard* _sd_card;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Controller(Player* p, SDCard* c) : _player(p), _sd_card(c) {}
|
Controller(Player* p);
|
||||||
void vol_up();
|
void loop();
|
||||||
void vol_down();
|
|
||||||
void track_next();
|
|
||||||
void track_prev();
|
|
||||||
};
|
};
|
||||||
|
@ -1,29 +1,80 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "sd_card.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <SD.h>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#define SCI_MODE 0x00
|
#define SCI_MODE 0x00
|
||||||
#define SCI_STATUS 0x01
|
#define SCI_STATUS 0x01
|
||||||
#define SCI_CLOCKF 0x03
|
#define SCI_CLOCKF 0x03
|
||||||
|
#define SCI_DECODE_TIME 0x04
|
||||||
|
#define SCI_VOL 0x0B
|
||||||
|
#define SCI_WRAMADDR 0x07
|
||||||
|
#define SCI_WRAM 0x06
|
||||||
|
|
||||||
#define CMD_WRITE 0x02
|
#define CMD_WRITE 0x02
|
||||||
#define CMD_READ 0x03
|
#define CMD_READ 0x03
|
||||||
|
|
||||||
|
#define ADDR_ENDBYTE 0x1E06
|
||||||
|
|
||||||
|
#define SM_CANCEL 0x0008
|
||||||
|
#define SS_DO_NOT_JUMP 0x8000
|
||||||
|
|
||||||
#define XRESET PIN_VS1053_XRESET
|
#define XRESET PIN_VS1053_XRESET
|
||||||
#define DREQ PIN_VS1053_DREQ
|
#define DREQ PIN_VS1053_DREQ
|
||||||
|
#define XCS PIN_VS1053_XCS
|
||||||
|
#define XDCS PIN_VS1053_XDCS
|
||||||
|
|
||||||
class Player {
|
class Player {
|
||||||
private:
|
private:
|
||||||
SDCard* _sd_card;
|
enum state { uninitialized, idle, playing, stopping };
|
||||||
|
struct album_state {
|
||||||
|
uint8_t index;
|
||||||
|
uint32_t position;
|
||||||
|
};
|
||||||
void _reset();
|
void _reset();
|
||||||
void _init();
|
void _init();
|
||||||
void _wait();
|
void _wait();
|
||||||
uint16_t _read_register(uint8_t address, uint32_t spi_speed, uint16_t t);//=SPI_CLOCK_DIV4);
|
uint16_t _read_control_register(uint8_t address);
|
||||||
void _write_register(uint8_t address, uint16_t value, uint32_t spi_speed);//=SPI_CLOCK_DIV2);
|
void _write_control_register(uint8_t address, uint16_t value);
|
||||||
|
void _write_data(uint8_t* data);
|
||||||
|
uint16_t _read_wram(uint16_t address);
|
||||||
|
state _state = state::uninitialized;
|
||||||
|
void _refill();
|
||||||
|
void _flush_and_cancel();
|
||||||
|
void _flush(uint bytes);
|
||||||
|
void _set_last_track(const char* album, uint8_t track, uint32_t position);
|
||||||
|
std::map<String, album_state> _last_tracks;
|
||||||
|
void _finish_playing();
|
||||||
|
void _finish_stopping();
|
||||||
|
void _mute();
|
||||||
|
void _unmute();
|
||||||
|
|
||||||
|
SPISettings _spi_settings_slow = SPISettings(250000, MSBFIRST, SPI_MODE0);
|
||||||
|
SPISettings _spi_settings_fast = SPISettings(4000000, MSBFIRST, SPI_MODE0);
|
||||||
|
SPISettings* _spi_settings = &_spi_settings_slow;
|
||||||
|
|
||||||
|
std::list<String> _files_in_dir(String dir);
|
||||||
|
File _file;
|
||||||
|
uint8_t _buffer[32];
|
||||||
|
String _playing_album;
|
||||||
|
uint8_t _playing_index;
|
||||||
|
uint _refills;
|
||||||
|
int8_t _end_byte;
|
||||||
|
uint8_t _volume;
|
||||||
|
uint16_t _stop_delay;
|
||||||
|
uint32_t _skip_to;
|
||||||
public:
|
public:
|
||||||
Player(SDCard* c);
|
Player();
|
||||||
void vol_up();
|
void vol_up();
|
||||||
void vol_down();
|
void vol_down();
|
||||||
void track_next();
|
void track_next();
|
||||||
void track_prev();
|
void track_prev();
|
||||||
|
|
||||||
|
bool play_album(String album);
|
||||||
|
bool play_song(String album, uint8_t song_index, uint32_t offset=0);
|
||||||
|
void stop();
|
||||||
|
bool loop();
|
||||||
|
void set_volume(uint8_t vol, bool save = true);
|
||||||
};
|
};
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <SD.h>
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
class SDCard {
|
|
||||||
public:
|
|
||||||
SDCard();
|
|
||||||
};
|
|
@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
class SPIMaster {
|
class SPIMaster {
|
||||||
public:
|
public:
|
||||||
static void init() {
|
static void init() {
|
||||||
@ -16,9 +20,9 @@ public:
|
|||||||
|
|
||||||
static void printStatus() {
|
static void printStatus() {
|
||||||
Serial.printf("CS state: SD:%d, VS1053_XCS:%d, VS1053_XDCS:%d\n",
|
Serial.printf("CS state: SD:%d, VS1053_XCS:%d, VS1053_XDCS:%d\n",
|
||||||
digitalRead(PIN_SD_CS),
|
digitalRead(PIN_SD_CS),
|
||||||
digitalRead(PIN_VS1053_XCS),
|
digitalRead(PIN_VS1053_XCS),
|
||||||
digitalRead(PIN_VS1053_XDCS));
|
digitalRead(PIN_VS1053_XDCS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable() {
|
static void disable() {
|
||||||
|
@ -12,5 +12,6 @@
|
|||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
board = esp12e
|
board = esp12e
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
upload_speed = 512000
|
||||||
|
lib_deps = 63
|
||||||
upload_port = /dev/cu.wchusbserial1420
|
upload_port = /dev/cu.wchusbserial1420
|
||||||
upload_speed = 921600
|
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
#include <Arduino.h>
|
|
||||||
#include "buttons.h"
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
void Buttons::setup() {
|
|
||||||
pinMode(PIN_BTN_VOL_UP, INPUT);
|
|
||||||
pinMode(PIN_BTN_VOL_DOWN, INPUT);
|
|
||||||
pinMode(PIN_BTN_TRACK_NEXT, INPUT);
|
|
||||||
pinMode(PIN_BTN_TRACK_PREV, INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Buttons::_debounce() {
|
|
||||||
unsigned long now = millis();
|
|
||||||
_debounce_until = now + DEBOUNCE_MILLIS;
|
|
||||||
if (_debounce_until < now) _debounce_until = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Buttons::loop() {
|
|
||||||
bool vol_up = digitalRead(PIN_BTN_VOL_UP);
|
|
||||||
bool vol_down = digitalRead(PIN_BTN_VOL_DOWN);
|
|
||||||
bool track_next = digitalRead(PIN_BTN_TRACK_NEXT);
|
|
||||||
bool track_prev = digitalRead(PIN_BTN_TRACK_PREV);
|
|
||||||
|
|
||||||
if (_debounce_until > millis()) {
|
|
||||||
if (vol_up || vol_down || track_next || track_prev) {
|
|
||||||
_debounce();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vol_up) {
|
|
||||||
_controller->vol_up();
|
|
||||||
} else if (vol_down) {
|
|
||||||
_controller->vol_down();
|
|
||||||
} else if (track_next) {
|
|
||||||
_controller->track_next();
|
|
||||||
} else if (track_prev) {
|
|
||||||
_controller->track_prev();
|
|
||||||
} else {
|
|
||||||
// If we reach this, no button was pressed and we are not debouncing -> do nothing.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we reach this, some button was pressed. So enable debouncing.
|
|
||||||
_debounce();
|
|
||||||
}
|
|
@ -1,17 +1,49 @@
|
|||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
|
#include "spi_master.h"
|
||||||
|
|
||||||
void Controller::vol_up() {
|
Controller::Controller(Player* p) {
|
||||||
_player->vol_up();
|
_player = p;
|
||||||
|
_rfid = new MFRC522(PIN_RC522_CS, MFRC522::UNUSED_PIN);
|
||||||
|
|
||||||
|
SPIMaster::enable(PIN_RC522_CS);
|
||||||
|
Serial.println("Initializing MFRC522...");
|
||||||
|
_rfid->PCD_Init();
|
||||||
|
_rfid->PCD_DumpVersionToSerial();
|
||||||
|
SPIMaster::disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::vol_down() {
|
void Controller::loop() {
|
||||||
_player->vol_down();
|
_check_rfid();
|
||||||
|
_check_serial();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::track_next() {
|
void Controller::_check_rfid() {
|
||||||
_player->track_next();
|
SPIMaster::enable(PIN_RC522_CS);
|
||||||
|
if (!_rfid->PICC_IsNewCardPresent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_rfid->PICC_ReadCardSerial()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_rfid->PICC_DumpToSerial(&(_rfid->uid));
|
||||||
|
SPIMaster::disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::track_prev() {
|
void Controller::_check_serial() {
|
||||||
_player->track_prev();
|
if (Serial.available() > 0) {
|
||||||
|
char c = Serial.read();
|
||||||
|
if (c == 'n') {
|
||||||
|
_player->track_next();
|
||||||
|
} else if (c=='p') {
|
||||||
|
_player->track_prev();
|
||||||
|
} else if (c=='s') {
|
||||||
|
_player->stop();
|
||||||
|
} else if (c=='+') {
|
||||||
|
_player->vol_up();
|
||||||
|
} else if (c=='-') {
|
||||||
|
_player->vol_down();
|
||||||
|
} else if (c==' ') {
|
||||||
|
_player->play_album("12345678");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
48
src/main.cpp
48
src/main.cpp
@ -1,42 +1,16 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
#include <SD.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "buttons.h"
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "sd_card.h"
|
|
||||||
#include "spi_master.h"
|
#include "spi_master.h"
|
||||||
|
|
||||||
Buttons* buttons;
|
|
||||||
Controller* controller;
|
Controller* controller;
|
||||||
Player* player;
|
Player* player;
|
||||||
SDCard* sd;
|
|
||||||
|
|
||||||
void printDirectory(File dir, int numTabs) {
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
File entry = dir.openNextFile();
|
|
||||||
if (! entry) {
|
|
||||||
// no more files
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (uint8_t i = 0; i < numTabs; i++) {
|
|
||||||
Serial.print('\t');
|
|
||||||
}
|
|
||||||
Serial.print(entry.name());
|
|
||||||
if (entry.isDirectory()) {
|
|
||||||
Serial.println("/");
|
|
||||||
printDirectory(entry, numTabs + 1);
|
|
||||||
} else {
|
|
||||||
// files have sizes, directories do not
|
|
||||||
Serial.print("\t\t");
|
|
||||||
Serial.println(entry.size(), DEC);
|
|
||||||
}
|
|
||||||
entry.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
delay(500);
|
||||||
Serial.begin(74880);
|
Serial.begin(74880);
|
||||||
Serial.println("Starting.");
|
Serial.println("Starting.");
|
||||||
|
|
||||||
@ -44,12 +18,22 @@ void setup() {
|
|||||||
SPI.begin();
|
SPI.begin();
|
||||||
SPIMaster::init();
|
SPIMaster::init();
|
||||||
|
|
||||||
sd = new SDCard();
|
SPIMaster::enable(PIN_SD_CS);
|
||||||
player = new Player(sd);
|
if (SD.begin(PIN_SD_CS)) {
|
||||||
controller = new Controller(player, sd);
|
Serial.println("SD card initialized.");
|
||||||
buttons = new Buttons(controller);
|
} else {
|
||||||
|
Serial.println("Could not initialize SD card. Halting.");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
player = new Player();
|
||||||
|
controller = new Controller(player);
|
||||||
|
|
||||||
|
//player->play_album("12345678");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
bool more_data_needed = player->loop();
|
||||||
|
if (more_data_needed) return;
|
||||||
|
|
||||||
|
controller->loop();
|
||||||
}
|
}
|
||||||
|
357
src/player.cpp
357
src/player.cpp
@ -3,7 +3,9 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "spi_master.h"
|
#include "spi_master.h"
|
||||||
|
|
||||||
Player::Player(SDCard* c) {
|
//Player::_spi_settings
|
||||||
|
|
||||||
|
Player::Player() {
|
||||||
pinMode(XRESET, OUTPUT);
|
pinMode(XRESET, OUTPUT);
|
||||||
digitalWrite(XRESET, HIGH);
|
digitalWrite(XRESET, HIGH);
|
||||||
pinMode(DREQ, INPUT);
|
pinMode(DREQ, INPUT);
|
||||||
@ -13,87 +15,324 @@ Player::Player(SDCard* c) {
|
|||||||
|
|
||||||
void Player::_reset() {
|
void Player::_reset() {
|
||||||
digitalWrite(XRESET, LOW);
|
digitalWrite(XRESET, LOW);
|
||||||
delay(50);
|
delay(100);
|
||||||
digitalWrite(XRESET, HIGH);
|
digitalWrite(XRESET, HIGH);
|
||||||
delay(50);
|
delay(100);
|
||||||
|
_state = uninitialized;
|
||||||
|
_spi_settings = &_spi_settings_slow; // After reset, communication has to be slow
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::_init() {
|
void Player::_init() {
|
||||||
SPI.setClockDivider(SPI_CLOCK_DIV16);
|
SPIMaster::disable();
|
||||||
|
|
||||||
_reset();
|
_reset();
|
||||||
uint16_t result;
|
|
||||||
for(uint8_t x=0; x<255; x++) {
|
uint16_t result = _read_control_register(SCI_MODE);
|
||||||
result = _read_register(SCI_MODE, 0, x);
|
Serial.printf("SCI_MODE: 0x%04X\n", result);
|
||||||
if (result != 0) Serial.printf("Try %3d: 0x%04X\n", x, result);
|
if (result != 0x4800) {
|
||||||
|
Serial.printf("Error: SCI_MODE was 0x%04X, expected was 0x4800.\n", result);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
delay(10);
|
result = _read_control_register(SCI_STATUS);
|
||||||
/*_read_register(SCI_MODE, SPI_CLOCK_DIV16); // First read fails for some unknown reason...
|
Serial.printf("SCI_STATUS: 0x%04X\n", result);
|
||||||
_read_register(SCI_MODE, SPI_CLOCK_DIV16);
|
if (result != 0x0040 && result != 0x0048) {
|
||||||
_read_register(SCI_STATUS, SPI_CLOCK_DIV16);
|
Serial.printf("Error: SCI_STATUS was 0x%04X, expected was 0x0040 or 0x0048.\n", result);
|
||||||
|
|
||||||
_read_register(SCI_STATUS, SPI_CLOCK_DIV16);
|
|
||||||
|
|
||||||
|
|
||||||
_read_register(SCI_MODE, SPI_CLOCK_DIV16);
|
|
||||||
_read_register(SCI_MODE, SPI_CLOCK_DIV16);
|
|
||||||
uint16_t response = _read_register(SCI_MODE, SPI_CLOCK_DIV16);
|
|
||||||
if (response != 0x4800) {
|
|
||||||
Serial.printf("Initialization failed. SCI_MODE was: 0x%04X. Expected: 0x4800\n", response);
|
|
||||||
return;
|
return;
|
||||||
}*/
|
}
|
||||||
/*_write_register(SCI_CLOCKF, 0x6000); // Set multiplier to 3x
|
result = _read_control_register(SCI_CLOCKF);
|
||||||
|
Serial.printf("SCI_CLOCKF: 0x%04X\n", result);
|
||||||
|
|
||||||
|
Serial.println("VS1053 Init looking good.");
|
||||||
|
Serial.println("Upping VS1053 multiplier...");
|
||||||
|
|
||||||
|
_write_control_register(SCI_CLOCKF, 0x6000);
|
||||||
delay(10);
|
delay(10);
|
||||||
response = _read_register(SCI_CLOCKF);
|
|
||||||
if (response != 0x6000) {
|
_spi_settings = &_spi_settings_fast;
|
||||||
Serial.printf("Initialization failed. SCI_CLOCKF was: 0x%04X. Expected: 0x6000\n", response);
|
|
||||||
|
result = _read_control_register(SCI_CLOCKF);
|
||||||
|
Serial.printf("SCI_CLOCKF: 0x%04X\n", result);
|
||||||
|
if (result != 0x6000) {
|
||||||
|
Serial.printf("Error: SCI_CLOCKF was 0x%04X, expected was 0x6000.\n", result);
|
||||||
return;
|
return;
|
||||||
}*/
|
}
|
||||||
//Serial.println(result, HEX);
|
|
||||||
|
_end_byte = (int8_t)(_read_wram(ADDR_ENDBYTE) & 0xFF);
|
||||||
|
|
||||||
|
set_volume(VOLUME_DEFAULT);
|
||||||
|
|
||||||
|
Serial.println("VS1053 initialization completed.");
|
||||||
|
_state = idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Player::_wait() {
|
inline void Player::_wait() {
|
||||||
delayMicroseconds(100);
|
|
||||||
//Serial.print("Waiting for DREQ...");
|
|
||||||
while(!digitalRead(DREQ));
|
while(!digitalRead(DREQ));
|
||||||
//Serial.printf(" done (%d cycles).\n", i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t Player::_read_register(uint8_t address, uint32_t spi_speed, uint16_t t) {
|
uint16_t Player::_read_control_register(uint8_t address) {
|
||||||
Serial.printf("Try %03d, querying register 0x%02X...", t, address);
|
_wait();
|
||||||
//SPI.setClockDivider(spi_speed);
|
SPIMaster::enable(XCS);
|
||||||
if (t & (1<<1)) _wait();
|
SPI.beginTransaction(*_spi_settings);
|
||||||
SPIMaster::enable(PIN_VS1053_XCS);
|
|
||||||
if (t & (1<<2)) _wait();
|
|
||||||
//_wait();
|
|
||||||
SPI.transfer(CMD_READ);
|
SPI.transfer(CMD_READ);
|
||||||
if (t & (1<<3)) _wait();
|
|
||||||
SPI.transfer(address);
|
SPI.transfer(address);
|
||||||
if (t & (1<<4)) _wait();
|
|
||||||
uint8_t b1 = SPI.transfer(0xFF);
|
uint8_t b1 = SPI.transfer(0xFF);
|
||||||
if (t & (1<<5)) _wait();
|
_wait();
|
||||||
uint8_t b2 = SPI.transfer(0xFF);
|
uint8_t b2 = SPI.transfer(0xFF);
|
||||||
if (t & (1<<6)) _wait();
|
_wait();
|
||||||
|
SPI.endTransaction();
|
||||||
|
SPIMaster::disable();
|
||||||
|
|
||||||
uint16_t result = b1 << 8 | b2;
|
return (b1 << 8) | b2;
|
||||||
Serial.printf("Response: 0x%02X 0x%02X -> 0x%04X\n", b1, b2, result);
|
}
|
||||||
if (t & (1<<7)) delay(10);
|
|
||||||
|
|
||||||
//_wait();
|
void Player::_write_control_register(uint8_t address, uint16_t value) {
|
||||||
//SPIMaster::disable();
|
uint8_t b1 = value >> 8;
|
||||||
|
uint8_t b2 = value & 0xFF;
|
||||||
|
_wait();
|
||||||
|
SPIMaster::enable(XCS);
|
||||||
|
SPI.beginTransaction(*_spi_settings);
|
||||||
|
SPI.transfer(CMD_WRITE);
|
||||||
|
SPI.transfer(address);
|
||||||
|
SPI.transfer(b1);
|
||||||
|
SPI.transfer(b2);
|
||||||
|
_wait();
|
||||||
|
SPI.endTransaction();
|
||||||
|
SPIMaster::disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::_write_data(uint8_t* buffer) {
|
||||||
|
SPIMaster::enable(XDCS);
|
||||||
|
SPI.beginTransaction(*_spi_settings);
|
||||||
|
for (uint i=0; i<sizeof(_buffer); i++) {
|
||||||
|
SPI.transfer(_buffer[i]);
|
||||||
|
}
|
||||||
|
SPI.endTransaction();
|
||||||
|
SPIMaster::disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Player::_read_wram(uint16_t address) {
|
||||||
|
Serial.printf("Reading WRAM address 0x%04X... ", address);
|
||||||
|
_write_control_register(SCI_WRAMADDR, address);
|
||||||
|
uint16_t r1 = _read_control_register(SCI_WRAM);
|
||||||
|
_write_control_register(SCI_WRAMADDR, address);
|
||||||
|
uint16_t r2 = _read_control_register(SCI_WRAM);
|
||||||
|
Serial.printf("Got 0x%04X and 0x%04X.\n", r1, r2);
|
||||||
|
return r1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::set_volume(uint8_t vol, bool save) {
|
||||||
|
if (save) {
|
||||||
|
_volume = vol;
|
||||||
|
}
|
||||||
|
Serial.printf("Setting volume to 0x%02X\n", vol);
|
||||||
|
vol = 0xFF - vol;
|
||||||
|
if (vol==0xFF) vol=0xFE;
|
||||||
|
uint16_t value = (vol<<8)|vol;
|
||||||
|
Serial.printf("Setting volume register to 0x%04X\n", value);
|
||||||
|
_write_control_register(SCI_VOL, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::vol_up() {
|
||||||
|
if (_volume + VOLUME_STEP > VOLUME_MAX) set_volume(VOLUME_MAX);
|
||||||
|
else set_volume(_volume + VOLUME_STEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::vol_down() {
|
||||||
|
if (_volume >= VOLUME_MIN + VOLUME_STEP) set_volume(_volume - VOLUME_STEP);
|
||||||
|
else set_volume(VOLUME_MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::_mute() {
|
||||||
|
Serial.println("Muting.");
|
||||||
|
set_volume(0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::_unmute() {
|
||||||
|
Serial.println("Unmuting.");
|
||||||
|
set_volume(_volume, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::track_next() {
|
||||||
|
if (_state != playing) return;
|
||||||
|
stop();
|
||||||
|
play_song(_playing_album, _playing_index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::track_prev() {
|
||||||
|
if (_state != playing) return;
|
||||||
|
if (_playing_index == 0) _playing_index=1;
|
||||||
|
stop();
|
||||||
|
play_song(_playing_album, _playing_index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<String> Player::_files_in_dir(String path) {
|
||||||
|
Serial.printf("Examining folder %s...\n", path.c_str());
|
||||||
|
if (!path.startsWith("/")) path = String("/") + path;
|
||||||
|
if (!path.endsWith("/")) path.concat("/");
|
||||||
|
std::list<String> result;
|
||||||
|
if (!SD.exists(path)) return result;
|
||||||
|
File dir = SD.open(path);
|
||||||
|
File entry;
|
||||||
|
while (entry = dir.openNextFile()) {
|
||||||
|
String filename = entry.name();
|
||||||
|
if (!entry.isDirectory() && !filename.startsWith(".") && filename.endsWith(".mp3")) {
|
||||||
|
//Serial.printf("Adding file %s\n", filename.c_str());
|
||||||
|
result.push_back(path + filename);
|
||||||
|
} else {
|
||||||
|
//Serial.printf("Ignoring entry %s\n", filename.c_str());
|
||||||
|
}
|
||||||
|
entry.close();
|
||||||
|
}
|
||||||
|
dir.close();
|
||||||
|
result.sort();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::_write_register(uint8_t address, uint16_t value, uint32_t spi_speed) {
|
bool Player::play_album(String album) {
|
||||||
Serial.printf("Writing to register 0x%02X...", address);
|
album_state s = _last_tracks[album.c_str()];
|
||||||
SPI.setClockDivider(spi_speed);
|
Serial.printf("Last index for album %s was %d,%d\n", album.c_str(), s.index, s.position);
|
||||||
SPIMaster::enable(PIN_VS1053_XCS);
|
return play_song(album, s.index, s.position);
|
||||||
SPI.transfer(CMD_WRITE);
|
}
|
||||||
SPI.transfer(address);
|
|
||||||
SPI.transfer(value >> 8);
|
bool Player::play_song(String album, uint8_t index, uint32_t skip_to) {
|
||||||
SPI.transfer(value & 0xFF);
|
if (_state != idle) return false;
|
||||||
_wait();
|
Serial.printf("Playing song at index %d, offset %d of album %s\n", index, skip_to, album.c_str());
|
||||||
SPIMaster::disable();
|
std::list<String> files = _files_in_dir(album);
|
||||||
Serial.println(" done.");
|
Serial.printf("Found %d songs in album\n", files.size());
|
||||||
|
if (index >= files.size()) {
|
||||||
|
Serial.println("No matching file found - not playing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//std::list<String>::iterator it = files.begin();
|
||||||
|
//std::advance(it, index);
|
||||||
|
String file = *(std::next(files.begin(), index));
|
||||||
|
Serial.printf("Opening file %s for playback...\n", file.c_str());
|
||||||
|
|
||||||
|
_file = SD.open(file);
|
||||||
|
|
||||||
|
Serial.println("Resetting SCI_DECODE_TIME...");
|
||||||
|
_write_control_register(SCI_DECODE_TIME, 0);
|
||||||
|
Serial.println("Resetting SS_DO_NOT_JUMP...");
|
||||||
|
_write_control_register(SCI_STATUS, _read_control_register(SCI_STATUS) & ~SS_DO_NOT_JUMP);
|
||||||
|
delay(100);
|
||||||
|
_state = playing;
|
||||||
|
_playing_album = album;
|
||||||
|
_playing_index = index;
|
||||||
|
_refills = 0;
|
||||||
|
_skip_to = skip_to;
|
||||||
|
if (_skip_to>0) _mute();
|
||||||
|
Serial.println("Now playing.");
|
||||||
|
_set_last_track(album.c_str(), index, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::_flush(uint bytes) {
|
||||||
|
SPIMaster::enable(XDCS);
|
||||||
|
SPI.beginTransaction(*_spi_settings);
|
||||||
|
for(uint i=0; i<bytes; i++) {
|
||||||
|
_wait();
|
||||||
|
SPI.transfer(_end_byte);
|
||||||
|
}
|
||||||
|
SPI.endTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::_finish_playing() {
|
||||||
|
_flush(2052);
|
||||||
|
_write_control_register(SCI_MODE, _read_control_register(SCI_MODE) | SM_CANCEL);
|
||||||
|
for (int i=0; i<64; i++) {
|
||||||
|
_flush(32);
|
||||||
|
uint16_t mode = _read_control_register(SCI_MODE);
|
||||||
|
if ((mode & SM_CANCEL) == 0) return;
|
||||||
|
}
|
||||||
|
// If we reached this, the Chip didn't stop. That should not happen.
|
||||||
|
// (That's written in the manual.)
|
||||||
|
// Reset the chip.
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::_flush_and_cancel() {
|
||||||
|
Serial.println("In flush_and_cancel()");
|
||||||
|
//_flush(2052);
|
||||||
|
for (int i=0; i<64; i++) {
|
||||||
|
_write_control_register(SCI_MODE, _read_control_register(SCI_MODE) | SM_CANCEL);
|
||||||
|
}
|
||||||
|
_flush(2052);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::stop() {
|
||||||
|
if (_state != playing) return;
|
||||||
|
Serial.println("Stopping.");
|
||||||
|
_set_last_track(_playing_album.c_str(), _playing_index, (uint32_t)_file.position());
|
||||||
|
_state = stopping;
|
||||||
|
_stop_delay = 0;
|
||||||
|
_write_control_register(SCI_MODE, _read_control_register(SCI_MODE) | SM_CANCEL);
|
||||||
|
while (true) {
|
||||||
|
_refill();
|
||||||
|
uint16_t mode = _read_control_register(SCI_MODE);
|
||||||
|
if ((mode & SM_CANCEL) == 0) {
|
||||||
|
_flush(2052);
|
||||||
|
_finish_stopping();
|
||||||
|
break;
|
||||||
|
} else if (_stop_delay > 2048) {
|
||||||
|
init();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_stop_delay++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::_finish_stopping() {
|
||||||
|
_state = idle;
|
||||||
|
if (_file) {
|
||||||
|
_file.close();
|
||||||
|
}
|
||||||
|
Serial.println("Stopped.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::_refill() {
|
||||||
|
SPIMaster::enable(PIN_SD_CS);
|
||||||
|
_refills++;
|
||||||
|
if (_refills % 1000 == 0) Serial.print(".");
|
||||||
|
uint8_t result = _file.read(_buffer, sizeof(_buffer));
|
||||||
|
if (result == 0) {
|
||||||
|
// File is over.
|
||||||
|
Serial.println("EOF reached.");
|
||||||
|
_finish_playing();
|
||||||
|
_finish_stopping();
|
||||||
|
bool result = play_song(_playing_album, _playing_index + 1);
|
||||||
|
if (!result) {
|
||||||
|
_set_last_track(_playing_album.c_str(), 0, 0);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_write_data(_buffer);
|
||||||
|
|
||||||
|
if (_skip_to > 0) {
|
||||||
|
if (_skip_to > _file.position()) {
|
||||||
|
uint16_t status = _read_control_register(SCI_STATUS);
|
||||||
|
if ((status & SS_DO_NOT_JUMP) == 0) {
|
||||||
|
Serial.printf("Skipping to %d.\n", _skip_to);
|
||||||
|
_flush(2048);
|
||||||
|
_file.seek(_skip_to);
|
||||||
|
_skip_to = 0;
|
||||||
|
_unmute();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_skip_to = 0;
|
||||||
|
_unmute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Player::loop() {
|
||||||
|
if (digitalRead(DREQ) && (_state==playing || _state==stopping)) {
|
||||||
|
_refill();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::_set_last_track(const char* album, uint8_t index, uint32_t position) {
|
||||||
|
Serial.printf("Setting _last_track[%s]=%d,%d.\n", album, index, position);
|
||||||
|
_last_tracks[album] = {index, position};
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
#include "sd_card.h"
|
|
||||||
|
|
||||||
SDCard::SDCard() {
|
|
||||||
if (!SD.begin(PIN_SD_CS)) {
|
|
||||||
Serial.println("Could not initialize SD card.");
|
|
||||||
} else {
|
|
||||||
Serial.println("SD card successfully initialized.");
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user