Started rewrite for using an I2S amplifier with less unnecessary features.
This commit is contained in:
@ -1,84 +0,0 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
// This is a simple number indicating the version for the HTTP Updater.
|
||||
#define OTA_VERSION 1
|
||||
// Comment out to prevent automatic updates.
|
||||
#define OTA_UPDATE_URL "https://files.schle.nz/esmp3/update.manifest"
|
||||
#define OTA_CHECK_INTERVAL 12*60*60*1000 // 12 hours
|
||||
|
||||
#define SHOW_DEBUG
|
||||
//#define SHOW_TRACE
|
||||
#define FTP_DEBUG
|
||||
#define DELAY_AFTER_DEBUG_AND_TRACE 0
|
||||
|
||||
// Here you can define WiFi data to use. But actually, the better way to do
|
||||
// this is by using /_wifi.txt on the sd card.
|
||||
//#define WIFI_SSID "---CHANGEME---"
|
||||
//#define WIFI_PASS "---CHANGEME---"
|
||||
|
||||
#define VS1053_SLEEP_DELAY 5000
|
||||
#define POSITION_SEND_INTERVAL 5000
|
||||
|
||||
#define DEBOUNCE_MILLIS 200
|
||||
#define VOLUME_DEFAULT 230
|
||||
#define VOLUME_MIN 190
|
||||
#define VOLUME_MAX 255
|
||||
#define VOLUME_STEP 0x08
|
||||
|
||||
#define RFID_SCAN_INTERVAL 100
|
||||
|
||||
#define NUM_BUTTONS 4
|
||||
|
||||
#define PIN_SD_CS(x) (digitalWrite(16, x))
|
||||
#define PIN_SD_CS_SETUP() (pinMode(16, OUTPUT))
|
||||
|
||||
#define PIN_VS1053_XCS(x) (digitalWrite(4, x))
|
||||
#define PIN_VS1053_XCS_SETUP() (pinMode(4, OUTPUT))
|
||||
|
||||
#define PIN_VS1053_XRESET(x) (digitalWrite(0, x))
|
||||
#define PIN_VS1053_XRESET_SETUP() (pinMode(0, OUTPUT))
|
||||
|
||||
#define PIN_VS1053_XDCS(x) (digitalWrite(2, x))
|
||||
#define PIN_VS1053_XDCS_SETUP() (pinMode(2, OUTPUT))
|
||||
|
||||
#define PIN_VS1053_DREQ() (digitalRead(15))
|
||||
#define PIN_VS1053_DREQ_SETUP() (pinMode(15, INPUT))
|
||||
|
||||
#define PIN_RC522_CS(x) (digitalWrite(17, x))
|
||||
#define PIN_RC522_CS_SETUP() (pinMode(17, OUTPUT))
|
||||
|
||||
#define PIN_SPEAKER_L(x) (digitalWrite(27, x))
|
||||
#define PIN_SPEAKER_L_SETUP() (pinMode(27, OUTPUT))
|
||||
|
||||
#define PIN_SPEAKER_R(x) (digitalWrite(26, x))
|
||||
#define PIN_SPEAKER_R_SETUP() (pinMode(26, OUTPUT))
|
||||
|
||||
#define BTN_PREV() ( ! digitalRead(22))
|
||||
#define BTN_PREV_SETUP() (pinMode(22, INPUT_PULLUP))
|
||||
|
||||
#define BTN_VOL_UP() ( ! digitalRead(21))
|
||||
#define BTN_VOL_UP_SETUP() (pinMode(21, INPUT_PULLUP))
|
||||
|
||||
#define BTN_VOL_DOWN() ( ! digitalRead(32))
|
||||
#define BTN_VOL_DOWN_SETUP() (pinMode(32, INPUT_PULLUP))
|
||||
|
||||
#define BTN_NEXT() ( ! digitalRead(33))
|
||||
#define BTN_NEXT_SETUP() (pinMode(33, INPUT_PULLUP))
|
||||
|
||||
|
||||
// Other definitions
|
||||
#define INFO(x, ...) Serial.printf(x, ##__VA_ARGS__)
|
||||
#define ERROR(x, ...) Serial.printf(x, ##__VA_ARGS__)
|
||||
|
||||
#ifdef SHOW_DEBUG
|
||||
#define DEBUG(x, ...) {Serial.printf(x, ##__VA_ARGS__); delay(DELAY_AFTER_DEBUG_AND_TRACE);}
|
||||
#else
|
||||
#define DEBUG(x, ...) while(0) {}
|
||||
#endif
|
||||
|
||||
#ifdef SHOW_TRACE
|
||||
#define TRACE(x, ...) {Serial.printf(x, ##__VA_ARGS__); delay(DELAY_AFTER_DEBUG_AND_TRACE);}
|
||||
#else
|
||||
#define TRACE(x, ...) while(0) {}
|
||||
#endif
|
@ -1,61 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include "config.h"
|
||||
|
||||
class Controller;
|
||||
|
||||
#include "player.h"
|
||||
#include "playlist.h"
|
||||
#include "playlist_manager.h"
|
||||
#include "http_server.h"
|
||||
|
||||
#undef DEPRECATED
|
||||
#include <MFRC522.h>
|
||||
|
||||
enum ControllerState { NORMAL, LOCKING, LOCKED };
|
||||
|
||||
class Controller {
|
||||
private:
|
||||
MFRC522* _rfid;
|
||||
HTTPServer* _http_server;
|
||||
ControllerState _state = NORMAL;
|
||||
bool _rfid_enabled = true;
|
||||
void _check_rfid();
|
||||
void _check_serial();
|
||||
void _check_buttons();
|
||||
bool _debounce_button(uint8_t index);
|
||||
uint32_t _get_rfid_card_uid();
|
||||
String _read_rfid_data();
|
||||
bool _rfid_present = false;
|
||||
String _last_rfid_uid = "";
|
||||
String _last_rfid_data = "";
|
||||
private:
|
||||
void handle_buttons();
|
||||
void handle_rfid();
|
||||
|
||||
public:
|
||||
void handle();
|
||||
|
||||
unsigned long _last_rfid_scan_at = 0;
|
||||
unsigned long _last_position_info_at = 0;
|
||||
unsigned long _last_update_check_at = 0;
|
||||
unsigned long _last_wifi_try_at = 0;
|
||||
String _serial_buffer = String();
|
||||
String _cmd_queue = "";
|
||||
void _execute_command_ls(String path);
|
||||
void _execute_command_ids();
|
||||
void _execute_command_help();
|
||||
unsigned long _button_last_pressed_at[NUM_BUTTONS];
|
||||
bool _check_button(uint8_t btn);
|
||||
public:
|
||||
Controller(Player* p, PlaylistManager* pm);
|
||||
PlaylistManager* pm;
|
||||
Player* player;
|
||||
void register_http_server(HTTPServer* h);
|
||||
void loop();
|
||||
void send_controller_status();
|
||||
void send_player_status();
|
||||
void send_playlist_manager_status();
|
||||
void send_position();
|
||||
void inform_new_client(AsyncWebSocketClient* client);
|
||||
String json();
|
||||
bool process_message(String m);
|
||||
void queue_command(String cmd);
|
||||
void update_playlist_manager();
|
||||
};
|
||||
};
|
@ -1,54 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SD.h>
|
||||
#include "config.h"
|
||||
#include "http_client_wrapper.h"
|
||||
|
||||
class DataSource {
|
||||
private:
|
||||
public:
|
||||
DataSource() {};
|
||||
virtual ~DataSource() {};
|
||||
virtual size_t read(uint8_t* buf, size_t len) = 0;
|
||||
virtual int read() = 0;
|
||||
virtual size_t position() = 0;
|
||||
virtual void seek(size_t position) = 0;
|
||||
virtual size_t size() = 0;
|
||||
virtual void close() = 0;
|
||||
virtual void skip_id3_tag() {};
|
||||
virtual bool usable() = 0;
|
||||
};
|
||||
|
||||
class SDDataSource : public DataSource {
|
||||
private:
|
||||
File _file;
|
||||
public:
|
||||
SDDataSource(String file);
|
||||
~SDDataSource();
|
||||
size_t read(uint8_t* buf, size_t len);
|
||||
int read();
|
||||
size_t position();
|
||||
void seek(size_t position);
|
||||
size_t size();
|
||||
void close();
|
||||
void skip_id3_tag();
|
||||
bool usable();
|
||||
};
|
||||
|
||||
class HTTPSDataSource : public DataSource {
|
||||
private:
|
||||
WiFiClient* _stream = NULL;
|
||||
HTTPClientWrapper* _http = NULL;
|
||||
uint32_t _position;
|
||||
public:
|
||||
HTTPSDataSource(String url, uint32_t offset=0);
|
||||
~HTTPSDataSource();
|
||||
size_t read(uint8_t* buf, size_t len);
|
||||
int read();
|
||||
size_t position();
|
||||
void seek(size_t position);
|
||||
size_t size();
|
||||
void close();
|
||||
bool usable();
|
||||
};
|
11
include/esmp3.h
Normal file
11
include/esmp3.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "controller.h"
|
||||
|
||||
#define PIN_CS_SD 16
|
||||
#define PIN_CS_RFID 17
|
||||
|
||||
#define I2S_DOUT 25
|
||||
#define I2S_BCLK 27
|
||||
#define I2S_LRC 26
|
||||
|
||||
extern Controller controller;
|
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <HTTPClient.h>
|
||||
#include "config.h"
|
||||
|
||||
class HTTPClientWrapper {
|
||||
private:
|
||||
HTTPClient* _http;
|
||||
uint8_t* _buffer;
|
||||
uint16_t _buffer_size;
|
||||
uint16_t _buffer_length;
|
||||
uint16_t _buffer_position;
|
||||
uint32_t _chunk_length;
|
||||
|
||||
bool _connected = false;
|
||||
String _content_type;
|
||||
uint32_t _length;
|
||||
bool _request(String method, String url, uint32_t offset=0, uint8_t redirection_count=0);
|
||||
WiFiClient* _stream;
|
||||
bool _is_chunked;
|
||||
void _read_next_chunk_header(bool first);
|
||||
uint16_t _fill_buffer();
|
||||
|
||||
public:
|
||||
HTTPClientWrapper();
|
||||
~HTTPClientWrapper();
|
||||
bool get(String url, uint32_t offset=0, uint8_t redirection_count=0);
|
||||
bool head(String url, uint32_t offset=0, uint8_t redirection_count=0);
|
||||
String getContentType();
|
||||
String getString();
|
||||
int read();
|
||||
uint32_t read(uint8_t* dst, uint32_t len);
|
||||
void close();
|
||||
uint32_t getSize();
|
||||
String readUntil(String sep);
|
||||
String readLine();
|
||||
};
|
@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
class HTTPServer;
|
||||
|
||||
#include "player.h"
|
||||
#include "controller.h"
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
class HTTPServer {
|
||||
private:
|
||||
AsyncWebServer* _server;
|
||||
|
||||
Player* _player;
|
||||
Controller* _controller;
|
||||
void _handle_upload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final);
|
||||
uint16_t _chunk_length;
|
||||
uint8_t* _chunk;
|
||||
File _upload_file;
|
||||
uint32_t _file_size;
|
||||
uint32_t _file_size_done;
|
||||
bool _need_header;
|
||||
uint32_t _upload_position;
|
||||
void _onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len);
|
||||
void _handle_index(AsyncWebServerRequest* req);
|
||||
public:
|
||||
HTTPServer(Player* p, Controller* c);
|
||||
AsyncWebSocket* ws;
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include <Preferences.h>
|
||||
|
||||
void wifi_connect();
|
||||
|
||||
extern const uint8_t file_index_html_start[] asm("_binary_src_index_html_start");
|
||||
extern bool debug_enabled;
|
||||
extern bool trace_enabled;
|
||||
extern Preferences prefs;
|
104
include/player.h
104
include/player.h
@ -1,104 +0,0 @@
|
||||
#pragma once
|
||||
#include "config.h"
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include "spi_master.h"
|
||||
#include "playlist.h"
|
||||
#include "data_sources.h"
|
||||
|
||||
class Player;
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
#define SCI_MODE 0x00
|
||||
#define SCI_STATUS 0x01
|
||||
#define SCI_BASS 0x02
|
||||
#define SCI_CLOCKF 0x03
|
||||
#define SCI_DECODE_TIME 0x04
|
||||
#define SCI_AUDATA 0x05
|
||||
#define SCI_VOL 0x0B
|
||||
#define SCI_WRAMADDR 0x07
|
||||
#define SCI_WRAM 0x06
|
||||
#define SCI_HDAT0 0x08
|
||||
#define SCI_HDAT1 0x09
|
||||
#define SCI_AIADDR 0x0A
|
||||
#define SCI_AICTRL0 0x0C
|
||||
#define SCI_AICTRL1 0x0D
|
||||
#define SCI_AICTRL2 0x0E
|
||||
#define SCI_AICTRL3 0x0F
|
||||
|
||||
#define CMD_WRITE 0x02
|
||||
#define CMD_READ 0x03
|
||||
|
||||
#define ADDR_ENDBYTE 0x1E06
|
||||
|
||||
#define SM_LAYER12 0x0001
|
||||
#define SM_RESET 0x0004
|
||||
#define SM_CANCEL 0x0008
|
||||
#define SM_SDINEW 0x0800
|
||||
#define SM_ADPCM 0x1000
|
||||
#define SS_DO_NOT_JUMP 0x8000
|
||||
|
||||
class Player {
|
||||
private:
|
||||
enum state { uninitialized, idle, playing, stopping,
|
||||
sleeping, recording };
|
||||
void _reset();
|
||||
void _wait();
|
||||
uint16_t _read_control_register(uint8_t address, bool do_wait=true);
|
||||
void _write_control_register(uint8_t address, uint16_t value, bool do_wait=true);
|
||||
void _write_direct(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();
|
||||
bool _refill_needed();
|
||||
void _flush_and_cancel();
|
||||
int8_t _get_endbyte();
|
||||
void _flush(uint count, int8_t fill_byte);
|
||||
void _play_file(String filename, uint32_t offset);
|
||||
void _finish_playing();
|
||||
void _finish_stopping(bool turn_speaker_off);
|
||||
void _mute();
|
||||
void _unmute();
|
||||
void _sleep();
|
||||
void _wakeup();
|
||||
void _record();
|
||||
void _patch_adpcm();
|
||||
void _speaker_off();
|
||||
void _speaker_on();
|
||||
|
||||
SPISettings _spi_settings_slow = SPISettings(250000, MSBFIRST, SPI_MODE0);
|
||||
SPISettings _spi_settings_fast = SPISettings(4000000, MSBFIRST, SPI_MODE0);
|
||||
SPISettings* _spi_settings = &_spi_settings_slow;
|
||||
|
||||
DataSource* _file;
|
||||
uint32_t _file_size = 0;
|
||||
uint8_t _buffer[32];
|
||||
uint32_t _current_play_position = 0;
|
||||
Playlist* _current_playlist = NULL;
|
||||
uint _refills;
|
||||
uint8_t _volume;
|
||||
uint16_t _stop_delay;
|
||||
uint32_t _skip_to;
|
||||
SPIMaster* _spi;
|
||||
Controller* _controller;
|
||||
unsigned long _stopped_at;
|
||||
public:
|
||||
Player(SPIMaster* s);
|
||||
void init();
|
||||
void register_controller(Controller* c);
|
||||
void vol_up();
|
||||
void vol_down();
|
||||
void track_next();
|
||||
void track_prev();
|
||||
void set_track(uint8_t track);
|
||||
bool is_playing();
|
||||
bool play();
|
||||
bool play(Playlist* p);
|
||||
void stop(bool turn_speaker_off=true);
|
||||
bool loop();
|
||||
void set_volume(uint8_t vol, bool save = true);
|
||||
String position_json();
|
||||
String json();
|
||||
};
|
@ -1,59 +1,15 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <vector>
|
||||
#include <ArduinoJson.h>
|
||||
#include "http_client_wrapper.h"
|
||||
|
||||
enum PlaylistPersistence {
|
||||
PERSIST_NONE,
|
||||
PERSIST_TEMPORARY,
|
||||
PERSIST_PERMANENTLY
|
||||
};
|
||||
|
||||
struct PlaylistEntry {
|
||||
String filename;
|
||||
String title;
|
||||
String id;
|
||||
|
||||
bool operator<(PlaylistEntry p) { return title < p.title; }
|
||||
};
|
||||
#include <Arduino.h>
|
||||
|
||||
class Playlist {
|
||||
private:
|
||||
uint32_t _position = 0;
|
||||
uint32_t _current_track = 0;
|
||||
bool _started = false;
|
||||
bool _shuffled = false;
|
||||
std::vector<PlaylistEntry> _files;
|
||||
String _title = "";
|
||||
String _path;
|
||||
void _add_path(String path);
|
||||
void _examine_http_url(String url);
|
||||
void _parse_rss(HTTPClientWrapper* http);
|
||||
void _parse_m3u(HTTPClientWrapper* http);
|
||||
void _parse_pls(HTTPClientWrapper* http);
|
||||
public:
|
||||
PlaylistPersistence persistence = PERSIST_TEMPORARY;
|
||||
Playlist(String path);
|
||||
void start();
|
||||
uint16_t get_file_count();
|
||||
bool has_track_next();
|
||||
bool has_track_prev();
|
||||
bool track_next();
|
||||
bool track_prev();
|
||||
void track_restart();
|
||||
bool set_track(uint8_t track);
|
||||
void set_track_by_id(String id);
|
||||
void reset();
|
||||
String path();
|
||||
bool is_empty();
|
||||
bool get_current_file(String* dst);
|
||||
String get_current_track_id();
|
||||
uint32_t get_position();
|
||||
void set_position(uint32_t p);
|
||||
void shuffle(uint8_t random_offset=0);
|
||||
void advent_shuffle(uint8_t day);
|
||||
bool is_fresh();
|
||||
void dump();
|
||||
void json(JsonObject json);
|
||||
private:
|
||||
std::vector<String> files;
|
||||
uint8_t current_file = 0;
|
||||
uint16_t current_time = 0;
|
||||
|
||||
public:
|
||||
void add_file(String filename);
|
||||
void sort();
|
||||
};
|
||||
|
@ -1,24 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <Arduino.h>
|
||||
#include "playlist.h"
|
||||
|
||||
class PlaylistManager {
|
||||
private:
|
||||
std::map<String, String> _map;
|
||||
std::map<String, Playlist*> _playlists;
|
||||
std::vector<String> _unmapped_folders;
|
||||
void _check_for_special_chars(String s);
|
||||
void _save_mapping();
|
||||
public:
|
||||
private:
|
||||
Playlist get_playlist_for_tag_id(String id);
|
||||
String current_rfid_tag_id;
|
||||
uint32_t audio_current_time = 0;
|
||||
|
||||
public:
|
||||
PlaylistManager();
|
||||
Playlist* get_playlist_for_id(String id);
|
||||
Playlist* get_playlist_for_folder(String folder);
|
||||
void dump_ids();
|
||||
void scan_files();
|
||||
String json();
|
||||
bool add_mapping(String id, String folder);
|
||||
String create_mapping_txt();
|
||||
void persist(Playlist* p);
|
||||
};
|
||||
std::vector<String> dirs;
|
||||
std::map<String, String> map;
|
||||
Playlist get_playlist(String rfid_id);
|
||||
Playlist current_playlist;
|
||||
void set_audio_current_time(uint32_t time);
|
||||
};
|
@ -1,70 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "config.h"
|
||||
|
||||
class SPIMaster {
|
||||
public:
|
||||
static uint8_t state;
|
||||
|
||||
static void init() {
|
||||
PIN_SD_CS_SETUP();
|
||||
PIN_VS1053_XCS_SETUP();
|
||||
PIN_VS1053_XDCS_SETUP();
|
||||
PIN_RC522_CS_SETUP();
|
||||
disable();
|
||||
}
|
||||
|
||||
static void select_sd(bool enabled=true) {
|
||||
PIN_SD_CS(enabled ? LOW : HIGH);
|
||||
if (enabled) {
|
||||
state |= 1;
|
||||
} else {
|
||||
state &= ~1;
|
||||
}
|
||||
}
|
||||
|
||||
static void select_vs1053_xcs(bool enabled=true) {
|
||||
PIN_VS1053_XCS(enabled ? LOW : HIGH);
|
||||
if (enabled) {
|
||||
state |= 2;
|
||||
} else {
|
||||
state &= ~2;
|
||||
}
|
||||
}
|
||||
|
||||
static void select_vs1053_xdcs(bool enabled=true) {
|
||||
PIN_VS1053_XDCS(enabled ? LOW : HIGH);
|
||||
if (enabled) {
|
||||
state |= 4;
|
||||
} else {
|
||||
state &= ~4;
|
||||
}
|
||||
}
|
||||
|
||||
static void select_rc522(bool enabled=true) {
|
||||
PIN_RC522_CS(enabled ? LOW : HIGH);
|
||||
if (enabled) {
|
||||
state |= 8;
|
||||
} else {
|
||||
state &= ~8;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_state(uint8_t s) {
|
||||
disable();
|
||||
if (s & 1) select_sd();
|
||||
if (s & 2) select_vs1053_xcs();
|
||||
if (s & 4) select_vs1053_xdcs();
|
||||
if (s & 8) select_rc522();
|
||||
}
|
||||
|
||||
static void disable() {
|
||||
PIN_SD_CS(HIGH);
|
||||
PIN_VS1053_XCS(HIGH);
|
||||
PIN_VS1053_XDCS(HIGH);
|
||||
PIN_RC522_CS(HIGH);
|
||||
state = 0;
|
||||
}
|
||||
};
|
||||
public:
|
||||
static void enable_sd();
|
||||
static void enable_rfid();
|
||||
static void disable_all();
|
||||
static void initialize();
|
||||
};
|
||||
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "http_client_wrapper.h"
|
||||
|
||||
class Updater {
|
||||
public:
|
||||
static void run();
|
||||
static bool do_update(int cmd, String url, String expected_md5);
|
||||
static bool read_line(String* dst, HTTPClientWrapper* http, String expected_key);
|
||||
};
|
Reference in New Issue
Block a user