Last active
May 13, 2020 21:25
-
-
Save schreibfaul1/cd1aed62054ae1c616df468d59784385 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// AI-Thinker A1S Audioboard V2.2 | |
// for default SPI GPIOs remove C58...C61 or use JTag GPIOs | |
// Display with Touchpad 320x240px, 3.3V relevant, controller: ILI9431 | |
#include "Arduino.h" | |
#include "WiFi.h" | |
#include "SPI.h" | |
#include "SD.h" | |
#include "FS.h" | |
#include "Wire.h" | |
#include "Preferences.h" | |
#include "tft.h" // https://github.com/schreibfaul1/ESP32-TFT-Library-ILI9341-HX8347D | |
#include "AC101.h" // https://github.com/Yveaux/AC101 | |
#include "Audio.h" // https://github.com/schreibfaul1/ESP32-audioI2S | |
// GPIOs for SD Card | |
#define SD_CS 13 | |
// GPIOs for SPI | |
#define SPI_MOSI 15 //23 | |
#define SPI_MISO 2 //19 | |
#define SPI_SCK 14 //18 | |
// GPIOs for TFT/TP | |
#define TFT_CS 22 | |
#define TFT_DC 12 | |
#define TP_CS 19 //21 | |
#define TP_IRQ 4 //5 | |
// I2S GPIOs, the names refer on AC101 | |
#define I2S_DSIN 25 | |
#define I2S_BCLK 27 | |
#define I2S_LRC 26 | |
#define I2S_MCLK 0 | |
#define I2S_DOUT 35 | |
// I2C GPIOs | |
#define IIC_CLK 32 | |
#define IIC_DATA 33 | |
// Amplifier enable | |
#define GPIO_PA_EN 21 | |
// GPIOs for KEYS | |
#define KEY1 36 | |
#define KEY2 13 // SD_CS | |
#define KEY3 19 | |
#define KEY4 23 | |
#define KEY5 18 | |
#define KEY6 5 | |
//String ssid = "xxxxxxxxx"; | |
//String password = "xxxxxxxxx"; | |
static AC101 ac; | |
Preferences pref; | |
TFT tft(0); | |
TP tp(TP_CS, TP_IRQ); | |
Audio audio; | |
String stations[] ={ | |
"0n-80s.radionetz.de:8000/0n-70s.mp3", | |
"mediaserv30.live-streams.nl:8000/stream", | |
"www.surfmusic.de/m3u/100-5-das-hitradio,4529.m3u", | |
"stream.1a-webradio.de/deutsch/mp3-128/vtuner-1a", | |
"mp3.ffh.de/radioffh/hqlivestream.aac", // 128k aac | |
"www.antenne.de/webradio/antenne.m3u", | |
"listen.rusongs.ru/ru-mp3-128", | |
"edge.audio.3qsdn.com/senderkw-mp3", | |
"macslons-irish-pub-radio.com/media.asx", | |
"https://rbbmediapmdp-a.akamaihd.net/content/a8/0d/a80dd31a-f96f-496d-aaf4-ed43891dee5e/6ed01c6b-050f-4202-b95e-81c2bdccd592_6b575035-41f2-4e11-84f5-bd5cffded6f8.mp3", | |
}; | |
//some global variables | |
uint8_t max_volume = 21; | |
uint8_t max_stations = 0; //will be set later | |
uint8_t cur_station = 0; //current station(nr), will be set later | |
uint8_t cur_volume = 0; //will be set from stored preferences | |
int8_t cur_btn =-1; //current button (, -1 means idle) | |
enum action{VOLUME_UP=0, VOLUME_DOWN=1, STATION_UP=2, STATION_DOWN=3}; | |
enum staus {RELEASED=0, PRESSED=1}; | |
struct _btns{ | |
uint16_t x; //PosX | |
uint16_t y; //PosY | |
uint16_t w; //Width | |
uint16_t h; //Hight | |
uint8_t a; //Action | |
uint8_t s; //Status | |
}; | |
typedef _btns btns; | |
btns btn[4]; | |
//************************************************************************************************** | |
// G U I * | |
//************************************************************************************************** | |
void draw_button(btns b){ | |
uint16_t color=TFT_BLACK; | |
uint8_t r=4, o=r*3; | |
if(b.s==RELEASED) color=TFT_GOLD; | |
if(b.s==PRESSED) color=TFT_DEEPSKYBLUE; | |
tft.drawRoundRect(b.x, b.y, b.w, b.h, r, color); | |
switch(b.a){ | |
case VOLUME_UP: | |
tft.fillTriangle(b.x+b.w/2, b.y+o, b.x+o, b.y+b.h-o, b.x+b.w-o, b.y+b.h-o, color); break; | |
case VOLUME_DOWN: | |
tft.fillTriangle(b.x+o, b.y+o, b.x+b.w/2, b.y+b.h-o, b.x+b.w-o, b.y+o, color); break; | |
case STATION_UP: | |
tft.fillTriangle(b.x+o, b.y+o, b.x+o, b.y+b.h-o, b.x+b.w-o, b.y+b.h/2, color); break; | |
case STATION_DOWN: | |
tft.fillTriangle(b.x+b.w-o, b.y+o, b.x+o, b.y+b.h/2, b.x+b.w-o, b.y+b.h-o, color); break; | |
} | |
} | |
void write_stationNr(uint8_t nr){ | |
tft.fillRect(60, 195, 50, 40, TFT_BLACK); | |
String snr = String(nr); | |
if(snr.length()<2) snr = "0"+snr; | |
tft.setCursor(68, 195); | |
tft.setFont(Garamond34x42); | |
tft.setTextColor(TFT_YELLOW); | |
tft.print(snr); | |
} | |
void write_volume(uint8_t vol){ | |
tft.fillRect(210, 195, 50, 40, TFT_BLACK); | |
String svol = String(vol); | |
if(svol.length()<2) svol = "0"+svol; | |
tft.setCursor(218, 195); | |
tft.setFont(Garamond34x42); | |
tft.setTextColor(TFT_YELLOW); | |
tft.print(svol); | |
} | |
void write_stationName(String sName){ | |
tft.fillRect(0, 0, 320, 60, TFT_BLACK); | |
tft.setFont(Times_New_Roman34x27); | |
tft.setTextColor(TFT_CORNSILK); | |
tft.setCursor(20, 10); | |
tft.print(sName); | |
} | |
void write_streamTitle(String sTitle){ | |
tft.fillRect(0, 60, 320, 130, TFT_BLACK); | |
tft.setFont(Times_New_Roman34x27); | |
tft.setTextColor(TFT_LIGHTBLUE); | |
tft.setCursor(20, 70); | |
tft.print(sTitle); | |
} | |
//************************************************************************************************** | |
// S E T U P * | |
//************************************************************************************************** | |
void setup() | |
{ | |
Serial.begin(115200); | |
btn[0].x= 20; btn[0].y=195; btn[0].w=40; btn[0].h=40; btn[0].a=STATION_DOWN; btn[0].s=RELEASED; | |
btn[1].x=110; btn[1].y=195; btn[1].w=40; btn[1].h=40; btn[1].a=STATION_UP; btn[1].s=RELEASED; | |
btn[2].x=170; btn[2].y=195; btn[2].w=40; btn[2].h=40; btn[2].a=VOLUME_UP; btn[2].s=RELEASED; | |
btn[3].x=260; btn[3].y=195; btn[3].w=40; btn[3].h=40; btn[3].a=VOLUME_DOWN; btn[3].s=RELEASED; | |
max_stations= sizeof(stations)/sizeof(stations[0]); log_i("max stations %i", max_stations); | |
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI); | |
Serial.printf("Connect to AC101 codec... "); | |
while (not ac.begin(IIC_DATA, IIC_CLK)) | |
{ | |
Serial.printf("Failed!\n"); | |
delay(1000); | |
} | |
Serial.printf("OK\n"); | |
pref.begin("WebRadio", false); // instance of preferences for defaults (station, volume ...) | |
if(pref.getShort("volume", 1000) == 1000){ // if that: pref was never been initialized | |
pref.putShort("volume", 10); | |
pref.putShort("station", 0); | |
} | |
else{ // get the stored values | |
cur_station = pref.getShort("station"); | |
cur_volume = pref.getShort("volume"); | |
} | |
WiFi.mode(WIFI_STA); | |
while (WiFi.status() != WL_CONNECTED){ | |
WiFi.begin(ssid.c_str(), password.c_str()); | |
delay(1500); | |
} | |
log_i("Connect to %s", WiFi.SSID().c_str()); | |
tft.begin(TFT_CS, TFT_DC, SPI_MOSI, SPI_MISO, SPI_SCK); | |
tft.setRotation(1); | |
tp.setRotation(3); | |
tft.setFont(Times_New_Roman21x17); | |
tft.fillScreen(TFT_BLACK); | |
audio.connecttohost(stations[cur_station]); | |
for(uint8_t i=0; i<(sizeof(btn)/sizeof(*btn)); i++) draw_button(btn[i]); | |
ac.SetVolumeSpeaker(cur_volume * 1.5); // 0...31 | |
ac.SetVolumeHeadphone(cur_volume *3); // 0...63 | |
write_volume(cur_volume); | |
write_stationNr(cur_station); | |
// Enable amplifier | |
pinMode(GPIO_PA_EN, OUTPUT); | |
digitalWrite(GPIO_PA_EN, HIGH); | |
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DSIN); | |
audio.setVolume(cur_volume); // 0...21 | |
for(uint8_t i=0; i<(sizeof(btn)/sizeof(*btn)); i++) draw_button(btn[i]); | |
write_volume(cur_volume); | |
write_stationNr(cur_station); | |
} | |
//----------------------------------------------------------------------- | |
void loop() | |
{ | |
audio.loop(); | |
tp.loop(); | |
} | |
//************************************************************************************************** | |
// E V E N T S * | |
//************************************************************************************************** | |
void audio_info(const char *info){ | |
Serial.print("audio_info: "); Serial.println(info); | |
} | |
void audio_showstation(const char *info){ | |
write_stationName(String(info)); | |
} | |
void audio_showstreamtitle(const char *info){ | |
String sinfo=String(info); | |
sinfo.replace("|", "\n"); | |
write_streamTitle(sinfo); | |
} | |
void tp_pressed(uint16_t x, uint16_t y){ | |
for(uint8_t i=0; i<(sizeof(btn)/sizeof(*btn)); i++){ | |
if(x>btn[i].x && (x<btn[i].x+btn[i].w)){ | |
if(y>btn[i].y && (y<btn[i].y+btn[i].h)){ | |
cur_btn=i; | |
btn[cur_btn].s=PRESSED; | |
draw_button(btn[cur_btn]); | |
} | |
} | |
} | |
} | |
void tp_released(){ | |
if(cur_btn !=-1){ | |
btn[cur_btn].s=RELEASED; | |
draw_button(btn[cur_btn]); | |
switch(btn[cur_btn].a){ | |
case VOLUME_UP: if(cur_volume<max_volume){ | |
cur_volume++; | |
write_volume(cur_volume); | |
audio.setVolume(cur_volume); | |
ac.SetVolumeSpeaker(cur_volume * 1.5); // 0...31 | |
ac.SetVolumeHeadphone(cur_volume *3); // 0...63 | |
pref.putShort("volume", cur_volume);} // store the current volume in nvs | |
break; | |
case VOLUME_DOWN: if(cur_volume>0){ | |
cur_volume-- ; | |
write_volume(cur_volume); | |
audio.setVolume(cur_volume); | |
ac.SetVolumeSpeaker(cur_volume * 1.5); // 0...31 | |
ac.SetVolumeHeadphone(cur_volume *3); // 0...63 | |
pref.putShort("volume", cur_volume);} // store the current volume in nvs | |
break; | |
case STATION_UP: if(cur_station<max_stations-1){ | |
cur_station++; | |
write_stationNr(cur_station); | |
tft.fillRect(0, 0, 320, 195, TFT_BLACK); | |
audio.connecttohost(stations[cur_station]); | |
pref.putShort("station", cur_station);} // store the current station in nvs | |
break; | |
case STATION_DOWN:if(cur_station>0){ | |
cur_station--; | |
write_stationNr(cur_station); | |
tft.fillRect(0, 0, 320, 195, TFT_BLACK); | |
audio.connecttohost(stations[cur_station]); | |
pref.putShort("station", cur_station);} // store the current station in nvs | |
break; | |
} | |
} | |
cur_btn=-1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment