Untitled diff

Created Diff never expires
39 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
495 lines
26 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
474 lines
//******************************************************************************************
//******************************************************************************************
//* Esp_radio -- Webradio receiver for ESP8266, 1.8 color display and VS1053 MP3 module. *
//* Esp_radio -- Webradio receiver for ESP8266, 1.8 color display and VS1053 MP3 module. *
//* With ESP8266 running at 80 MHz, it is capable of handling up to 256 kb bitrate. *
//* With ESP8266 running at 80 MHz, it is capable of handling up to 256 kb bitrate. *
//* With ESP8266 running at 160 MHz, it is capable of handling up to 320 kb bitrate. *
//* With ESP8266 running at 160 MHz, it is capable of handling up to 320 kb bitrate. *
//******************************************************************************************
//******************************************************************************************
// ESP8266 libraries used:
// ESP8266 libraries used:
// - ESP8266WiFi
// - ESP8266WiFi - Part of ESP8266 Arduino default libraries.
// - SPI
// - SPI - Part of Arduino default libraries.
// - Adafruit_GFX
// - Adafruit_GFX - https://github.com/adafruit/Adafruit-GFX-Library
// - TFT_ILI9163C
// - TFT_ILI9163C - https://github.com/sumotoy/TFT_ILI9163C
// - ESPAsyncTCP
// - ESPAsyncTCP - https://github.com/me-no-dev/ESPAsyncTCP
// - ESPAsyncWebServer
// - ESPAsyncWebServer - https://github.com/me-no-dev/ESPAsyncWebServer
// - FS
// - FS - https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.2.0/ESP8266FS-0.2.0.zip
// - ArduinoOTA
// - ArduinoOTA Part of ESP8266 Arduino default libraries.
// - AsyncMqttClient
// - AsyncMqttClient https://github.com/marvinroger/async-mqtt-client
// - Adafruit TinyXML Fork https://github.com/adafruit/TinyXML
//
//
// A library for the VS1053 (for ESP8266) is not available (or not easy to find). Therefore
// A library for the VS1053 (for ESP8266) is not available (or not easy to find). Therefore
// a class for this module is derived from the maniacbug library and integrated in this sketch.
// a class for this module is derived from the maniacbug library and integrated in this sketch.
//
//
// See http://www.internet-radio.com for suitable stations. Add the stations of your choice
// See http://www.internet-radio.com for suitable stations. Add the stations of your choice
// to the .ini-file.
// to the .ini-file.
//
//
// Brief description of the program:
// Brief description of the program:
// First a suitable WiFi network is found and a connection is made.
// First a suitable WiFi network is found and a connection is made.
// Then a connection will be made to a shoutcast server. The server starts with some
// Then a connection will be made to a shoutcast server. The server starts with some
// info in the header in readable ascii, ending with a double CRLF, like:
// info in the header in readable ascii, ending with a double CRLF, like:
// icy-name:Classic Rock Florida - SHE Radio
// icy-name:Classic Rock Florida - SHE Radio
// icy-genre:Classic Rock 60s 70s 80s Oldies Miami South Florida
// icy-genre:Classic Rock 60s 70s 80s Oldies Miami South Florida
// icy-url:http://www.ClassicRockFLorida.com
// icy-url:http://www.ClassicRockFLorida.com
// content-type:audio/mpeg
// content-type:audio/mpeg
// icy-pub:1
// icy-pub:1
// icy-metaint:32768 - Metadata after 32768 bytes of MP3-data
// icy-metaint:32768 - Metadata after 32768 bytes of MP3-data
// icy-br:128 - in kb/sec (for Ogg this is like "icy-br=Quality 2"
// icy-br:128 - in kb/sec (for Ogg this is like "icy-br=Quality 2"
//
//
// After de double CRLF is received, the server starts sending mp3- or Ogg-data. For mp3, this
// After de double CRLF is received, the server starts sending mp3- or Ogg-data. For mp3, this
// data may contain metadata (non mp3) after every "metaint" mp3 bytes.
// data may contain metadata (non mp3) after every "metaint" mp3 bytes.
// The metadata is empty in most cases, but if any is available the content will be presented on the TFT.
// The metadata is empty in most cases, but if any is available the content will be presented on the TFT.
// Pushing the input button causes the player to select the next preset station present in the .ini file.
// Pushing the input button causes the player to select the next preset station present in the .ini file.
//
//
// The display used is a Chinese 1.8 color TFT module 128 x 160 pixels. The TFT_ILI9163C.h
// The display used is a Chinese 1.8 color TFT module 128 x 160 pixels. The TFT_ILI9163C.h
// file has been changed to reflect this particular module. TFT_ILI9163C.cpp has been
// file has been changed to reflect this particular module. TFT_ILI9163C.cpp has been
// changed to use the full screenwidth if rotated to mode "3". Now there is room for 26
// changed to use the full screenwidth if rotated to mode "3". Now there is room for 26
// characters per line and 16 lines. Software will work without installing the display.
// characters per line and 16 lines. Software will work without installing the display.
// If no TFT is used, you may use GPIO2 and GPIO15 as control buttons. See definition of "USETFT" below.
// If no TFT is used, you may use GPIO2 and GPIO15 as control buttons. See definition of "USETFT" below.
// Switches are than programmed as:
// Switches are than programmed as:
// GPIO2 : "Goto station 1"
// GPIO2 : "Goto station 1"
// GPIO0 : "Next station"
// GPIO0 : "Next station"
// GPIO15: "Previous station". Note that GPIO15 has to be LOW when starting the ESP8266.
// GPIO15: "Previous station". Note that GPIO15 has to be LOW when starting the ESP8266.
// The button for GPIO15 must therefore be connected to VCC (3.3V) instead of GND.
// The button for GPIO15 must therefore be connected to VCC (3.3V) instead of GND.


//
//
// For configuration of the WiFi network(s): see the global data section further on.
// For configuration of the WiFi network(s): see the global data section further on.
//
//
// The SPI interface for VS1053 and TFT uses hardware SPI.
// The SPI interface for VS1053 and TFT uses hardware SPI.
//
//
// Wiring:
// Wiring:
// NodeMCU GPIO Pin to program Wired to LCD Wired to VS1053 Wired to rest
// NodeMCU GPIO Pin to program Wired to LCD Wired to VS1053 Wired to rest
// ------- ------ -------------- --------------- ------------------- ---------------------
// ------- ------ -------------- --------------- ------------------- ---------------------
// D0 GPIO16 16 - pin 1 DCS -
// D0 GPIO16 16 - pin 1 DCS -
// D1 GPIO5 5 - pin 2 CS LED on nodeMCU
// D1 GPIO5 5 - pin 2 CS LED on nodeMCU
// D2 GPIO4 4 - pin 4 DREQ -
// D2 GPIO4 4 - pin 4 DREQ -
// D3 GPIO0 0 FLASH - - Control button "Next station"
// D3 GPIO0 0 FLASH - - Control button "Next station"
// D4 GPIO2 2 pin 3 (D/C) - (OR)Control button "Station 1"
// D4 GPIO2 2 pin 3 (D/C) - (OR)Control button "Station 1"
// D5 GPIO14 14 SCLK pin 5 (CLK) pin 5 SCK -
// D5 GPIO14 14 SCLK pin 5 (CLK) pin 5 SCK -
// D6 GPIO12 12 MISO - pin 7 MISO -
// D6 GPIO12 12 MISO - pin 7 MISO -
// D7 GPIO13 13 MOSI pin 4 (DIN) pin 6 MOSI -
// D7 GPIO13 13 MOSI pin 4 (DIN) pin 6 MOSI -
// D8 GPIO15 15 pin 2 (CS) - (OR)Control button "Previous station"
// D8 GPIO15 15 pin 2 (CS) - (OR)Control button "Previous station"
// D9 GPI03 3 RXD0 - - Reserved serial input
// D9 GPI03 3 RXD0 - - Reserved serial input
// D10 GPIO1 1 TXD0 - - Reserved serial output
// D10 GPIO1 1 TXD0 - - Reserved serial output
// ------- ------ -------------- --------------- ------------------- ---------------------
// ------- ------ -------------- --------------- ------------------- ---------------------
// GND - - pin 8 (GND) pin 8 GND Power supply
// GND - - pin 8 (GND) pin 8 GND Power supply
// VCC 3.3 - - pin 6 (VCC) - LDO 3.3 Volt
// VCC 3.3 - - pin 6 (VCC) - LDO 3.3 Volt
// VCC 5 V - - pin 7 (BL) pin 9 5V Power supply
// VCC 5 V - - pin 7 (BL) pin 9 5V Power supply
// RST - - pin 1 (RST) pin 3 RESET Reset circuit
// RST - - pin 1 (RST) pin 3 RESET Reset circuit
//
//
// The reset circuit is a circuit with 2 diodes to GPIO5 and GPIO16 and a resistor to ground
// The reset circuit is a circuit with 2 diodes to GPIO5 and GPIO16 and a resistor to ground
// (wired OR gate) because there was not a free GPIO output available for this function.
// (wired OR gate) because there was not a free GPIO output available for this function.
// This circuit is included in the documentation.
// This circuit is included in the documentation.
// Issues:
// Issues:
// Webserver produces error "LmacRxBlk:1" after some time. After that it will work very slow.
// Webserver produces error "LmacRxBlk:1" after some time. After that it will work very slow.
// The program will reset the ESP8266 in such a case. Now we have switched to async webserver,
// The program will reset the ESP8266 in such a case. Now we have switched to async webserver,
// the problem still exists, but the program will not crash anymore.
// the problem still exists, but the program will not crash anymore.
// Upload to ESP8266 not reliable.
// Upload to ESP8266 not reliable.
//
//
// 31-03-2016, ES: First set-up.
// 31-03-2016, ES: First set-up.
// 01-04-2016, ES: Detect missing VS1053 at start-up.
// 01-04-2016, ES: Detect missing VS1053 at start-up.
// 05-04-2016, ES: Added commands through http server on port 80.
// 05-04-2016, ES: Added commands through http server on port 80.
// 14-04-2016, ES: Added icon and switch preset on stream error.
// 14-04-2016, ES: Added icon and switch preset on stream error.
// 18-04-2016, ES: Added SPIFFS for webserver.
// 18-04-2016, ES: Added SPIFFS for webserver.
// 19-04-2016, ES: Added ringbuffer.
// 19-04-2016, ES: Added ringbuffer.
// 20-04-2016, ES: WiFi Passwords through SPIFFS files, enable OTA.
// 20-04-2016, ES: WiFi Passwords through SPIFFS files, enable OTA.
// 21-04-2016, ES: Switch to Async Webserver.
// 21-04-2016, ES: Switch to Async Webserver.
// 27-04-2016, ES: Save settings, so same volume and preset will be used after restart.
// 27-04-2016, ES: Save settings, so same volume and preset will be used after restart.
// 03-05-2016, ES: Add bass/treble settings (see also new index.html).
// 03-05-2016, ES: Add bass/treble settings (see also new index.html).
// 04-05-2016, ES: Allow stations like "skonto.ls.lv:8002/mp3".
// 04-05-2016, ES: Allow stations like "skonto.ls.lv:8002/mp3".
// 06-05-2016, ES: Allow hiddens WiFi station if this is the only .pw file.
// 06-05-2016, ES: Allow hiddens WiFi station if this is the only .pw file.
// 07-05-2016, ES: Added preset selection in webserver.
// 07-05-2016, ES: Added preset selection in webserver.
// 12-05-2016, ES: Added support for Ogg-encoder.
// 12-05-2016, ES: Added support for Ogg-encoder.
// 13-05-2016, ES: Better Ogg detection.
// 13-05-2016, ES: Better Ogg detection.
// 17-05-2016, ES: Analog input for commands, extra buttons if no TFT required.
// 17-05-2016, ES: Analog input for commands, extra buttons if no TFT required.
// 26-05-2016, ES: Fixed BUTTON3 bug (no TFT).
// 26-05-2016, ES: Fixed BUTTON3 bug (no TFT).
// 27-05-2016, ES: Fixed restore station at restart.
// 27-05-2016, ES: Fixed restore station at restart.
// 04-07-2016, ES: WiFi.disconnect clears old connection now (thanks to Juppit).
// 04-07-2016, ES: WiFi.disconnect clears old connection now (thanks to Juppit).
// 23-09-2016, ES: Added commands via MQTT and Serial input, Wifi set-up in AP mode.
// 23-09-2016, ES: Added commands via MQTT and Serial input, Wifi set-up in AP mode.
// 04-10-2016, ES: Configuration in .ini file. No more use of EEPROM and .pw files.
// 04-10-2016, ES: Configuration in .ini file. No more use of EEPROM and .pw files.
// 11-10-2016, ES: Allow stations that have no bitrate in header like icecast.err.ee/raadio2.mp3.
// 11-10-2016, ES: Allow stations that have no bitrate in header like icecast.err.ee/raadio2.mp3.
// 14-10-2016, ES: Updated for async-mqtt-client-master 0.5.0
// 14-10-2016, ES: Updated for async-mqtt-client-master 0.5.0
// 22-10-2016, ES: Correction mute/unmute.
// 22-10-2016, ES: Correction mute/unmute.
// 15-11-2016, ES: Support for .m3u playlists.
// 15-11-2016, ES: Support for .m3u playlists.
// 22-12-2016, ES: Support for localhost (play from SPIFFS).
// 22-12-2016, ES: Support for localhost (play from SPIFFS).
// 28-12-2016, ES: Implement "Resume" request.
// 28-12-2016, ES: Implement "Resume" request.
// 31-12-2016, ES: Allow ContentType "text/css".
// 31-12-2016, ES: Allow ContentType "text/css".
// 02-01-2017, ES: Webinterface in PROGMEM.
// 02-01-2017, ES: Webinterface in PROGMEM.
// 16-01-2017, ES: Correction playlists.
// 16-01-2017, ES: Correction playlists.
// 17-01-2017, ES: Bugfix config page and playlist.
// 17-01-2017, ES: Bugfix config page and playlist.
// 23-01-2017, ES: Bugfix playlist.
// 23-01-2017, ES: Bugfix playlist.
// 26-01-2017, ES: Check on wrong icy-metaint.
// 26-01-2017, ES: Check on wrong icy-metaint.
// 30-01-2017, ES: Allow chunked transfer encoding.
// 30-01-2017, ES: Allow chunked transfer encoding.
// 01-02-2017, ES: Bugfix file upload.
// 01-02-2017, ES: Bugfix file upload.
// 26-04-2017, ES: Better output webinterface on preset change.
// 26-04-2017, ES: Better output webinterface on preset change.
//
//
// Define the version number, also used for webserver as Last-Modified header:
// Define the version number, also used for webserver as Last-Modified header:
#define VERSION "Wed, 26 Apr 2017 08:45:00 GMT"
#define VERSION "Wed, 26 Apr 2017 08:45:00 GMT"
// TFT. Define USETFT if required.
// TFT. Define USETFT if required.
#define USETFT
#define USETFT
#include <ESP8266WiFi.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ESPAsyncWebServer.h>
#include <AsyncMqttClient.h>
#include <AsyncMqttClient.h>
#include <SPI.h>
#include <SPI.h>
#if defined ( USETFT )
#if defined ( USETFT )
#include <Adafruit_GFX.h>
#include <Adafruit_GFX.h>
#include <TFT_ILI9163C.h>
#include <TFT_ILI9163C.h>
#endif
#endif
#include <Ticker.h>
#include <Ticker.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <FS.h>
#include <FS.h>
#include <ArduinoOTA.h>
#include <ArduinoOTA.h>
#include <TinyXML.h>


extern "C"
extern "C"
{
{
#include "user_interface.h"
#include "user_interface.h"
}
}


// Definitions for 3 control switches on analog input
// Definitions for 3 control switches on analog input
// You can test the analog input values by holding down the switch and select /?analog=1
// You can test the analog input values by holding down the switch and select /?analog=1
// in the web interface. See schematics in the documentation.
// in the web interface. See schematics in the documentation.
// Switches are programmed as "Goto station 1", "Next station" and "Previous station" respectively.
// Switches are programmed as "Goto station 1", "Next station" and "Previous station" respectively.
// Set these values to 2000 if not used or tie analog input to ground.
// Set these values to 2000 if not used or tie analog input to ground.
#define NUMANA 3
#define NUMANA 3
//#define asw1 252
//#define asw1 252
//#define asw2 334
//#define asw2 334
//#define asw3 499
//#define asw3 499
#define asw1 2000
#define asw1 2000
#define asw2 2000
#define asw2 2000
#define asw3 2000
#define asw3 2000
//
//
// Color definitions for the TFT screen (if used)
// Color definitions for the TFT screen (if used)
#define BLACK 0x0000
#define BLACK 0x0000
#define BLUE 0xF800
#define BLUE 0xF800
#define RED 0x001F
#define RED 0x001F
#define GREEN 0x07E0
#define GREEN 0x07E0
#define CYAN GREEN | BLUE
#define CYAN GREEN | BLUE
#define MAGENTA RED | BLUE
#define MAGENTA RED | BLUE
#define YELLOW RED | GREEN
#define YELLOW RED | GREEN
#define WHITE BLUE | RED | GREEN
#define WHITE BLUE | RED | GREEN
// Digital I/O used
// Digital I/O used
// Pins for VS1053 module
// Pins for VS1053 module
#define VS1053_CS 5
#define VS1053_CS 5
#define VS1053_DCS 16
#define VS1053_DCS 16
#define VS1053_DREQ 4
#define VS1053_DREQ 4
// Pins CS and DC for TFT module (if used, see definition of "USETFT")
// Pins CS and DC for TFT module (if used, see definition of "USETFT")
#define TFT_CS 15
#define TFT_CS 15
#define TFT_DC 2
#define TFT_DC 2
// Control button (GPIO) for controlling station
// Control button (GPIO) for controlling station
#define BUTTON1 2
#define BUTTON1 2
#define BUTTON2 0
#define BUTTON2 0
#define BUTTON3 15
#define BUTTON3 15
// Ringbuffer for smooth playing. 20000 bytes is 160 Kbits, about 1.5 seconds at 128kb bitrate.
// Ringbuffer for smooth playing. 20000 bytes is 160 Kbits, about 1.5 seconds at 128kb bitrate.
#define RINGBFSIZ 20000
#define RINGBFSIZ 20000
// Debug buffer size
// Debug buffer size
#define DEBUG_BUFFER_SIZE 100
#define DEBUG_BUFFER_SIZE 100
// Name of the ini file
// Name of the ini file
#define INIFILENAME "/radio.ini"
#define INIFILENAME "/radio.ini"
// Access point name if connection to WiFi network fails. Also the hostname for WiFi and OTA.
// Access point name if connection to WiFi network fails. Also the hostname for WiFi and OTA.
// Not that the password of an AP must be at least as long as 8 characters.
// Not that the password of an AP must be at least as long as 8 characters.
// Also used for other naming.
// Also used for other naming.
#define NAME "Esp-radio"
#define NAME "Esp-radio"
// Maximum number of MQTT reconnects before give-up
// Maximum number of MQTT reconnects before give-up
#define MAXMQTTCONNECTS 20
#define MAXMQTTCONNECTS 20
//
//
//******************************************************************************************
//******************************************************************************************
// Forward declaration of various functions *
// Forward declaration of various functions *
//******************************************************************************************
//******************************************************************************************
void displayinfo ( const char* str, uint16_t pos, uint16_t height, uint16_t color ) ;
void displayinfo ( const char* str, uint16_t pos, uint16_t height, uint16_t color ) ;
void showstreamtitle ( const char* ml, bool full = false ) ;
void showstreamtitle ( const char* ml, bool full = false ) ;
void handlebyte ( uint8_t b, bool force = false ) ;
void handlebyte ( uint8_t b, bool force = false ) ;
void handlebyte_ch ( uint8_t b, bool force = false ) ;
void handlebyte_ch ( uint8_t b, bool force = false ) ;
void handleFS ( AsyncWebServerRequest* request ) ;
void handleFS ( AsyncWebServerRequest* request ) ;
void handleFSf ( AsyncWebServerRequest* request, const String& filename ) ;
void handleFSf ( AsyncWebServerRequest* request, const String& filename ) ;
void handleCmd ( AsyncWebServerRequest* request ) ;
void handleCmd ( AsyncWebServerRequest* request ) ;
void handleFileUpload ( AsyncWebServerRequest* request, String filename,
void handleFileUpload ( AsyncWebServerRequest* request, String filename,
size_t index, uint8_t* data, size_t len, bool final ) ;
size_t index, uint8_t* data, size_t len, bool final ) ;
char* dbgprint( const char* format, ... ) ;
char* dbgprint( const char* format, ... ) ;
char* analyzeCmd ( const char* str ) ;
char* analyzeCmd ( const char* str ) ;
char* analyzeCmd ( const char* par, const char* val ) ;
char* analyzeCmd ( const char* par, const char* val ) ;
String chomp ( String str ) ;
String chomp ( String str ) ;
void publishIP() ;
void publishIP() ;


//
//
//******************************************************************************************
//******************************************************************************************
// Global data section. *
// Global data section. *
//******************************************************************************************
//******************************************************************************************
// There is a block ini-data that contains some configuration. Configuration data is *
// There is a block ini-data that contains some configuration. Configuration data is *
// saved in the SPIFFS file radio.ini by the webinterface. On restart the new data will *
// saved in the SPIFFS file radio.ini by the webinterface. On restart the new data will *
// de read from this file. *
// de read from this file. *
// Items in ini_block can be changed by commands from webserver/MQTT/Serial. *
// Items in ini_block can be changed by commands from webserver/MQTT/Serial. *
//******************************************************************************************
//******************************************************************************************
struct ini_struct
struct ini_struct
{
{
String mqttbroker ; // The name of the MQTT broker server
String mqttbroker ; // The name of the MQTT broker server
uint16_t mqttport ; // Port, default 1883
uint16_t mqttport ; // Port, default 1883
String mqttuser ; // User for MQTT authentication
String mqttuser ; // User for MQTT authentication
String mqttpasswd ; // Password for MQTT authentication
String mqttpasswd ; // Password for MQTT authentication
String mqtttopic ; // Topic to suscribe to
String mqtttopic ; // Topic to suscribe to
String mqttpubtopic ; // Topic to pubtop (IP will be published)
String mqttpubtopic ; // Topic to pubtop (IP will be published)
uint8_t reqvol ; // Requested volume
uint8_t reqvol ; // Requested volume
uint8_t rtone[4] ; // Requested bass/treble settings
uint8_t rtone[4] ; // Requested bass/treble settings
int8_t newpreset ; // Requested preset
int8_t newpreset ; // Requested preset
String ssid ; // SSID of WiFi network to connect to
String ssid ; // SSID of WiFi network to connect to
String passwd ; // Password for WiFi network
String passwd ; // Password for WiFi network
} ;
} ;


enum datamode_t { INIT = 1, HEADER = 2, DATA = 4,
enum datamode_t { INIT = 1, HEADER = 2, DATA = 4,
METADATA = 8, PLAYLISTINIT = 16,
METADATA = 8, PLAYLISTINIT = 16,
PLAYLISTHEADER = 32, PLAYLISTDATA = 64,
PLAYLISTHEADER = 32, PLAYLISTDATA = 64,
STOPREQD = 128, STOPPED = 256
STOPREQD = 128, STOPPED = 256
} ; // State for datastream
} ; // State for datastream


// Global variables
// Global variables
int DEBUG = 1 ;
int DEBUG = 1 ;
ini_struct ini_block ; // Holds configurable data
ini_struct ini_block ; // Holds configurable data
WiFiClient mp3client ; // An instance of the mp3 client
WiFiClient mp3client ; // An instance of the mp3 client
AsyncWebServer cmdserver ( 80 ) ; // Instance of embedded webserver on port 80
AsyncWebServer cmdserver ( 80 ) ; // Instance of embedded webserver on port 80
AsyncMqttClient mqttclient ; // Client for MQTT subscriber
AsyncMqttClient mqttclient ; // Client for MQTT subscriber
IPAddress mqtt_server_IP ; // IP address of MQTT broker
IPAddress mqtt_server_IP ; // IP address of MQTT broker
char cmd[130] ; // Command from MQTT or Serial
char cmd[130] ; // Command from MQTT or Serial
#if defined ( USETFT )
#if defined ( USETFT )
TFT_ILI9163C tft = TFT_ILI9163C ( TFT_CS, TFT_DC ) ;
TFT_ILI9163C tft = TFT_ILI9163C ( TFT_CS, TFT_DC ) ;
#endif
#endif
Ticker tckr ; // For timing 100 msec
Ticker tckr ; // For timing 100 msec
uint32_t totalcount = 0 ; // Counter mp3 data
uint32_t totalcount = 0 ; // Counter mp3 data
datamode_t datamode ; // State of datastream
datamode_t datamode ; // State of datastream
int metacount ; // Number of bytes in metadata
int metacount ; // Number of bytes in metadata
int datacount ; // Counter databytes before metadata
int datacount ; // Counter databytes before metadata
String metaline ; // Readable line in metadata
String metaline ; // Readable line in metadata
String icystreamtitle ; // Streamtitle from metadata
String icystreamtitle ; // Streamtitle from metadata
String icyname ; // Icecast station name
String icyname ; // Icecast station name
int bitrate ; // Bitrate in kb/sec
int bitrate ; // Bitrate in kb/sec
int metaint = 0 ; // Number of databytes between metadata
int metaint = 0 ; // Number of databytes between metadata
int8_t currentpreset = -1 ; // Preset station playing
int8_t currentpreset = -1 ; // Preset station playing
String host ; // The URL to connect to or file to play
String host ; // The URL to connect to or file to play
String playlist ; // The URL of the specified playlist
String playlist ; // The URL of the specified playlist
bool hostreq = false ; // Request for new host
bool hostreq = false ; // Request for new host
bool reqtone = false ; // New tone setting requested
bool reqtone = false ; // New tone setting requested
bool muteflag = false ; // Mute output
bool muteflag = false ; // Mute output
uint8_t* ringbuf ; // Ringbuffer for VS1053
uint8_t* ringbuf ; // Ringbuffer for VS1053
uint16_t rbwindex = 0 ; // Fill pointer in ringbuffer
uint16_t rbwindex = 0 ; // Fill pointer in ringbuffer
uint16_t rbrindex = RINGBFSIZ - 1 ; // Emptypointer in ringbuffer
uint16_t rbrindex = RINGBFSIZ - 1 ; // Emptypointer in ringbuffer
uint16_t rcount = 0 ; // Number of bytes in ringbuffer
uint16_t rcount = 0 ; // Number of bytes in ringbuffer
uint16_t analogsw[NUMANA] = { asw1, asw2, asw3 } ; // 3 levels of analog input
uint16_t analogsw[NUMANA] = { asw1, asw2, asw3 } ; // 3 levels of analog input
uint16_t analogrest ; // Rest value of analog input
uint16_t analogrest ; // Rest value of analog input
bool resetreq = false ; // Request to reset the ESP8266
bool resetreq = false ; // Request to reset the ESP8266
bool NetworkFound ; // True if WiFi network connected
bool NetworkFound ; // True if WiFi network connected
String networks ; // Found networks
String networks ; // Found networks
String anetworks ; // Aceptable networks (present in .ini file)
String anetworks ; // Aceptable networks (present in .ini file)
String presetlist ; // List for webserver
String presetlist ; // List for webserver
uint8_t num_an ; // Number of acceptable networks in .ini file
uint8_t num_an ; // Number of acceptable networks in .ini file
String testfilename = "" ; // File to test (SPIFFS speed)
String testfilename = "" ; // File to test (SPIFFS speed)
uint16_t mqttcount = 0 ; // Counter MAXMQTTCONNECTS
uint16_t mqttcount = 0 ; // Counter MAXMQTTCONNECTS
int8_t playlist_num = 0 ; // Nonzero for selection from playlist
int8_t playlist_num = 0 ; // Nonzero for selection from playlist
File mp3file ; // File containing mp3 on SPIFFS
File mp3file ; // File containing mp3 on SPIFFS
bool localfile = false ; // Play from local mp3-file or not
bool localfile = false ; // Play from local mp3-file or not
bool chunked = false ; // Station provides chunked transfer
bool chunked = false ; // Station provides chunked transfer
int chunkcount = 0 ; // Counter for chunked transfer
int chunkcount = 0 ; // Counter for chunked transfer
// XML IHeartRadio Globals.
const char* ihrhost = "playerservices.streamtheworld.com"; // XML data source.
const char* apiVersion = "1.5"; // API Version of IHeartRadio.
const char* mountPoint = "CIMXFMAAC"; // Testing MountPoint (Station Callsign).
const char* lang = "en"; // Language.
const int xmlPort = 80; // XML Port.
uint8_t xmlbuffer[150]; // For XML decoding.
String xmlOpen; // Opening XML tag.
String xmlTag; // Current XML tag.
String xmlData; // Data inside tag.
String xmlDataLast; // Prevents duplicated tag data.
String stationServer(""); // Radio stream server.
String stationPort(""); // Radio stream port.
String stationMount(""); // Radio stream Callsign.

//******************************************************************************************
//******************************************************************************************
// End of global data section. *
// End of global data section. *
//******************************************************************************************
//******************************************************************************************


//******************************************************************************************
//******************************************************************************************
// Pages and CSS for the webinterface. *
// Pages and CSS for the webinterface. *
//******************************************************************************************
//******************************************************************************************
#include "about_html.h"
#include "about_html.h"
#include "config_html.h"
#include "config_html.h"
#include "index_html.h"
#include "index_html.h"
#include "radio_css.h"
#include "radio_css.h"
#include "favicon_ico.h"
#include "favicon_ico.h"
//
//
//******************************************************************************************
//******************************************************************************************
// VS1053 stuff. Based on maniacbug library. *
// VS1053 stuff. Based on maniacbug library. *
//******************************************************************************************
//******************************************************************************************
// VS1053 class definition. *
// VS1053 class definition. *
//******************************************************************************************
//******************************************************************************************
class VS1053
class VS1053
{
{
private:
private:
uint8_t cs_pin ; // Pin where CS line is connected
uint8_t cs_pin ; // Pin where CS line is connected
uint8_t dcs_pin ; // Pin where DCS line is connected
uint8_t dcs_pin ; // Pin where DCS line is connected
uint8_t dreq_pin ; // Pin where DREQ line is connected
uint8_t dreq_pin ; // Pin where DREQ line is connected
uint8_t curvol ; // Current volume setting 0..100%
uint8_t curvol ; // Current volume setting 0..100%
const uint8_t vs1053_chunk_size = 32 ;
const uint8_t vs1053_chunk_size = 32 ;
// SCI Register
// SCI Register
const uint8_t SCI_MODE = 0x0 ;
const uint8_t SCI_MODE = 0x0 ;
const uint8_t SCI_BASS = 0x2 ;
const uint8_t SCI_BASS = 0x2 ;
const uint8_t SCI_CLOCKF = 0x3 ;
const uint8_t SCI_CLOCKF = 0x3 ;
const uint8_t SCI_AUDATA = 0x5 ;
const uint8_t SCI_AUDATA = 0x5 ;
const uint8_t SCI_WRAM = 0x6 ;
const uint8_t SCI_WRAM = 0x6 ;
const uint8_t SCI_WRAMADDR = 0x7 ;
const uint8_t SCI_WRAMADDR = 0x7 ;
const uint8_t SCI_AIADDR = 0xA ;
const uint8_t SCI_AIADDR = 0xA ;
const uint8_t SCI_VOL = 0xB ;
const uint8_t SCI_VOL = 0xB ;
const uint8_t SCI_AICTRL0 = 0xC ;
const uint8_t SCI_AICTRL0 = 0xC ;
const uint8_t SCI_AICTRL1 = 0xD ;
const uint8_t SCI_AICTRL1 = 0xD ;
const uint8_t SCI_num_registers = 0xF ;
const uint8_t SCI_num_registers = 0xF ;
// SCI_MODE bits
// SCI_MODE bits
const uint8_t SM_SDINEW = 11 ; // Bitnumber in SCI_MODE always on
const uint8_t SM_SDINEW = 11 ; // Bitnumber in SCI_MODE always on
const uint8_t SM_RESET = 2 ; // Bitnumber in SCI_MODE soft reset
const uint8_t SM_RESET = 2 ; // Bitnumber in SCI_MODE soft reset
const uint8_t SM_CANCEL = 3 ; // Bitnumber in SCI_MODE cancel song
const uint8_t SM_CANCEL = 3 ; // Bitnumber in SCI_MODE cancel song
const uint8_t SM_TESTS = 5 ; // Bitnumber in SCI_MODE for tests
const uint8_t SM_TESTS = 5 ; // Bitnumber in SCI_MODE for tests
const uint8_t SM_LINE1 = 14 ; // Bitnumber in SCI_MODE for Line input
const uint8_t SM_LINE1 = 14 ; // Bitnumber in SCI_MODE for Line input
SPISettings VS1053_SPI ; // SPI settings for this slave
SPISettings VS1053_SPI ; // SPI settings for this slave
uint8_t endFillByte ; // Byte to send when stopping song
uint8_t endFillByte ; // Byte to send when stopping song
protected:
protected:
inline void await_data_request() const
inline void await_data_request() const
{
{
while ( !digitalRead ( dreq_pin ) )
while ( !digitalRead ( dreq_pin ) )
{
{
yield() ; // Very short delay
yield() ; // Very short delay
}
}
}
}


inline void control_mode_on() const
inline void control_mode_on() const
{
{
SPI.beginTransaction ( VS1053_SPI ) ; // Prevent other SPI users
SPI.beginTransaction ( VS1053_SPI ) ; // Prevent other SPI users
digitalWrite ( dcs_pin, HIGH ) ; // Bring slave in control mode
digitalWrite ( dcs_pin, HIGH ) ; // Bring slave in control mode
digitalWrite ( cs_pin, LOW ) ;
digitalWrite ( cs_pin, LOW ) ;
}
}


inline void control_mode_off() const
inline void control_mode_off() const
{
{
digitalWrite ( cs_pin, HIGH ) ; // End control mode
digitalWrite ( cs_pin, HIGH ) ; // End control mode
SPI.endTransaction() ; // Allow other SPI users
SPI.endTransaction() ; // Allow other SPI users
}
}


inline void data_mode_on() const
inline void data_mode_on() const
{
{
SPI.beginTransaction ( VS1053_SPI ) ; // Prevent other SPI users
SPI.beginTransaction ( VS1053_SPI ) ; // Prevent other SPI users
digitalWrite ( cs_pin, HIGH ) ; // Bring slave in data mode
digitalWrite ( cs_pin, HIGH ) ; // Bring slave in data mode
digitalWrite ( dcs_pin, LOW ) ;
digitalWrite ( dcs_pin, LOW ) ;
}
}


inline void data_mode_off() const
inline void data_mode_off() const
{
{
digitalWrite ( dcs_pin, HIGH ) ; // End data mode
digitalWrite ( dcs_pin, HIGH ) ; // End data mode
SPI.endTransaction() ; // Allow other SPI users
SPI.endTransaction() ; // Allow other SPI users
}
}


uint16_t read_register ( uint8_t _reg ) const ;
uint16_t read_register ( uint8_t _reg ) const ;
void write_register ( uint8_t _reg, uint16_t _value ) const ;
void write_register ( uint8_t _reg, uint16_t _value ) const ;
void sdi_send_buffer ( uint8_t* data, size_t len ) ;
void sdi_send_buffer ( uint8_t* data, size_t len ) ;
void sdi_send_fillers ( size_t length ) ;
void sdi_send_fillers ( size_t length ) ;
void wram_write ( uint16_t address, uint16_t data ) ;
void wram_write ( uint16_t address, uint16_t data ) ;
uint16_t wram_read ( uint16_t address ) ;
uint16_t wram_read ( uint16_t address ) ;


public:
public:
// Constructor. Only sets pin values. Doesn't touch the chip. Be sure to call begin()!
// Constructor. Only sets pin values. Doesn't touch the chip. Be sure to call begin()!
VS1053 ( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin ) ;
VS1053 ( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin ) ;
void begin() ; // Begin operation. Sets pins correctly,
void begin() ; // Begin operation. Sets pins correctly,
// and prepares SPI bus.
// and prepares SPI bus.
void startSong() ; // Prepare to start playing. Call this each
void startSong() ; // Prepare to start playing. Call this each
// time a new song starts.
// time a new song starts.
void playChunk ( uint8_t* data, size_t len ) ; // Play a chunk of data. Copies the data to
void playChunk ( uint8_t* data, size_t len ) ; // Play a chunk of data. Copies the data to
// the chip. Blocks until complete.
// the chip. Blocks until complete.
void stopSong() ; // Finish playing a song. Call this after
void stopSong() ; // Finish playing a song. Call this after
// the last playChunk call.
// the last playChunk call.
void setVolume ( uint8_t vol ) ; // Set the player volume.Level from 0-100,
void setVolume ( uint8_t vol ) ; // Set the player volume.Level from 0-100,
// higher is louder.
// higher is louder.
void setTone ( uint8_t* rtone ) ; // Set the player baas/treble, 4 nibbles for
void setTone ( uint8_t* rtone ) ; // Set the player baas/treble, 4 nibbles for
// treble gain/freq and bass gain/freq
// treble gain/freq and bass gain/freq
uint8_t getVolume() ; // Get the currenet volume setting.
uint8_t getVolume() ; // Get the currenet volume setting.
// higher is louder.
// higher is louder.
void printDetails ( const char *header ) ; // Print configuration details to serial output.
void printDetails ( const char *header ) ; // Print configuration details to serial output.
void softReset() ; // Do a soft reset
void softReset() ; // Do a soft reset
bool testComm ( const char *header ) ; // Test communication with module
bool testComm ( const char *header ) ; // Test communication with module
inline bool data_request() const
inline bool data_request() const
{
{
return ( digitalRead ( dreq_pin ) == HIGH ) ;
return ( digitalRead ( dreq_pin ) == HIGH ) ;
}
}
} ;
} ;


//******************************************************************************************
//******************************************************************************************
// VS1053 class implementation. *
// VS1053 class implementation. *
//******************************************************************************************
//******************************************************************************************


VS1053::VS1053 ( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin ) :
VS1053::VS1053 ( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin ) :
cs_pin(_cs_pin), dcs_pin(_dcs_pin), dreq_pin(_dreq_pin)
cs_pin(_cs_pin), dcs_pin(_dcs_pin), dreq_pin(_dreq_pin)
{
{
}
}


uint16_t VS1053::read_register ( uint8_t _reg ) const
uint16_t VS1053::read_register ( uint8_t _reg ) const
{
{
uint16_t result ;
uint16_t result ;


control_mode_on() ;
control_mode_on() ;
SPI.write ( 3 ) ; // Read operation
SPI.write ( 3 ) ; // Read operation
SPI.write ( _reg ) ; // Register to write (0..0xF)
SPI.write ( _reg ) ; // Register to write (0..0xF)
// Note: transfer16 does not seem to work
// Note: transfer16 does not seem to work
result = ( SPI.transfer ( 0xFF ) << 8 ) | // Read 16 bits data
result = ( SPI.transfer ( 0xFF ) << 8 ) | // Read 16 bits data
( SPI.transfer ( 0xFF ) ) ;
( SPI.transfer ( 0xFF ) ) ;
await_data_request() ; // Wait for DREQ to be HIGH again
await_data_request() ; // Wait for DREQ to be HIGH again
control_mode_off() ;
control_mode_off() ;
return result ;
return result ;
}
}


void VS1053::write_register ( uint8_t _reg, uint16_t _value ) const
void VS1053::write_register ( uint8_t _reg, uint16_t _value ) const
{
{
control_mode_on( );
control_mode_on( );
SPI.write ( 2 ) ; // Write operation
SPI.write ( 2 ) ; // Write operation
SPI.write ( _reg ) ; // Register to write (0..0xF)
SPI.write ( _reg ) ; // Register to write (0..0xF)
SPI.write16 ( _value ) ; // Send 16 bits data
SPI.write16 ( _value ) ; // Send 16 bits data
await_data_request() ;
await_data_request() ;
control_mode_off() ;
control_mode_off() ;
}
}


void VS1053::sdi_send_buffer ( uint8_t* data, size_t len )
void VS1053::sdi_send_buffer ( uint8_t* data, size_t len )
{
{
size_t chunk_length ; // Length of chunk 32 byte or shorter
size_t chunk_length ; // Length of chunk 32 byte or shorter


data_mode_on() ;
data_mode_on() ;
while ( len ) // More to do?
while ( len ) // More to do?
{
{
await_data_request() ; // Wait for space available
await_data_request() ; // Wait for space available
chunk_length = len ;
chunk_length = len ;
if ( len > vs1053_chunk_size )
if ( len > vs1053_chunk_size )
{
{
chunk_length = vs1053_chunk_size ;
chunk_length = vs1053_chunk_size ;
}
}
len -= chunk_length ;
len -= chunk_length ;
SPI.writeBytes ( data, chunk_length ) ;
SPI.writeBytes ( data, chunk_length ) ;
data += chunk_length ;
data += chunk_length ;
}
}
data_mode_off() ;
data_mode_off() ;
}
}


void VS1053::sdi_send_fillers ( size_t len )
void VS1053::sdi_send_fillers ( size_t len )
{
{
size_t chunk_length ; // Length of chunk 32 byte or shorter
size_t chunk_length ;

data_mode_on() ;
while ( len ) // More to do?
{
await_data_request() ; // Wait for space available
chunk_length = len ;
if ( len > vs1053_chunk_size )
{
chunk_length = vs1053_chunk_size ;
}
len -= chunk_length ;
while ( chunk_length-- )
{
SPI.write ( endFillByte ) ;
}
}
data_mode_off();
}

void VS1053::wram_write ( uint16_t address, uint16_t data )
{
write_register ( SCI_WRAMADDR, address ) ;
write_register ( SCI_WRAM, data ) ;
}

uint16_t VS1053::wram_read ( uint16_t address )
{
write_register ( SCI_WRAMADDR, address ) ; // Start reading from WRAM
return read_register ( SCI_WRAM ) ; // Read back result
}

bool VS1053::testComm ( const char *header )
{
// Test the communication with the VS1053 module. The result wille be returned.
// If DREQ is low, there is problably no VS1053 connected. Pull the line HIGH
// in order to prevent an endless loop waiting for this signal. The rest of the
// software will still work, but readbacks from VS1053 will fail.
int i ;