Added sleep mode for VS1053, HTTP server, tar upload, JSON status, RFID card removal debouncing, ...
This commit is contained in:
154
src/http_server.cpp
Normal file
154
src/http_server.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "http_server.h"
|
||||
|
||||
HTTPServer::HTTPServer(Player* p, Controller* c) {
|
||||
_player = p;
|
||||
_controller = c;
|
||||
_http_server = new ESP8266WebServer(80);
|
||||
DEBUG("Connecting to wifi \"%s\"...\n", WIFI_SSID);
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||
ERROR("Could not connect to Wifi. Rebooting.");
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
INFO("WiFi connected.\n");
|
||||
MDNS.begin("esmp3");
|
||||
//_http_server->onFileUpload([&]() { _handle_upload(); yield();});
|
||||
_http_server->on("/upload", HTTP_POST, [&]() {
|
||||
_http_server->sendHeader("Connection", "close");
|
||||
_http_server->send(200, "text/plain", "OK");
|
||||
}, [&]() {
|
||||
_handle_upload();
|
||||
yield();
|
||||
});
|
||||
_http_server->on("/", HTTP_GET, [&](){ _handle_index(); });
|
||||
_http_server->on("/status", HTTP_GET, [&](){ _handle_status(); });
|
||||
_http_server->begin();
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
}
|
||||
|
||||
void HTTPServer::_handle_upload() {
|
||||
// https://www.gnu.org/software/tar/manual/html_node/Standard.html
|
||||
// https://www.mkssoftware.com/docs/man4/tar.4.asp
|
||||
HTTPUpload* upload = &_http_server->upload();
|
||||
DEBUG("_handle_upload Status: %d, length: %d\n", upload->status, upload->currentSize);
|
||||
|
||||
if (upload->status == UPLOAD_FILE_START) {
|
||||
_chunk = new uint8_t[512];
|
||||
_chunk_length = 0;
|
||||
_upload_position = 0;
|
||||
_file_size = 0;
|
||||
_file_size_done = 0;
|
||||
_need_header = true;
|
||||
}
|
||||
|
||||
if (upload->status == UPLOAD_FILE_END || upload->status == UPLOAD_FILE_ABORTED) {
|
||||
// Close the file
|
||||
delete _chunk;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t upload_offset = 0;
|
||||
while (upload_offset < upload->currentSize) {
|
||||
// Load a chunk
|
||||
if (_chunk_length < 512 && upload->currentSize > upload_offset) {
|
||||
uint16_t needed = 512 - _chunk_length;
|
||||
if (needed > upload->currentSize - upload_offset) needed = upload->currentSize - upload_offset;
|
||||
memcpy(_chunk + _chunk_length, upload->buf + upload_offset, needed);
|
||||
_chunk_length += needed;
|
||||
upload_offset += needed;
|
||||
_upload_position += needed;
|
||||
|
||||
if (_chunk_length == 512) {
|
||||
// Process chunk
|
||||
DEBUG("Chunk.\n");
|
||||
if (_need_header) {
|
||||
if (_chunk[257]=='u'&&_chunk[258]=='s'&&_chunk[259]=='t'&&_chunk[260]=='a'&&_chunk[261]=='r') {
|
||||
DEBUG("It is a valid header, starting at 0x%X!\n", _upload_position-512);
|
||||
char filename[200];
|
||||
strncpy(filename, (char*)_chunk, 100);
|
||||
DEBUG("filename: %s\n", filename);
|
||||
_file_size = 0;
|
||||
_file_size_done = 0;
|
||||
for (int i=0; i<11; i++) {
|
||||
//Serial.print(_header_buffer[124 + i]);
|
||||
_file_size = (_file_size<<3) + (_chunk[124 + i] - '0');
|
||||
}
|
||||
DEBUG("filesize: %d\n", _file_size);
|
||||
uint8_t type = _chunk[156] - '0';
|
||||
if (type==0) {
|
||||
DEBUG("Is a file.\n");
|
||||
} else if (type==5) {
|
||||
DEBUG("Is a directory.\n");
|
||||
} else {
|
||||
ERROR("Unknown file type %d\n", type);
|
||||
}
|
||||
_need_header = (type==5 || _file_size==0); // No chunks needed for directories.
|
||||
} else {
|
||||
bool byte_found = false;
|
||||
for (int i=0; i<512; i++) byte_found = byte_found || _chunk[i]>0;
|
||||
if (!byte_found) {
|
||||
DEBUG("Empty chunk while looking for header -> ignoring.\n");
|
||||
} else {
|
||||
ERROR("Invalid tar header: %c %c %c %c %c. Looking at header start offset 0x%X.\n", _chunk[257], _chunk[258], _chunk[259], _chunk[260], _chunk[261], _upload_position-512);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint16_t bytes_to_write = _file_size - _file_size_done;
|
||||
if (bytes_to_write > 512) bytes_to_write=512;
|
||||
// Write bytes...
|
||||
_file_size_done += bytes_to_write;
|
||||
if (_file_size_done >= _file_size) _need_header = true;
|
||||
}
|
||||
|
||||
_chunk_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPServer::_handle_index() {
|
||||
String response = String("<html><head><title>ESMP3</title><script>function play_album(e) {}</script></head><body>");
|
||||
response.concat("Albums on SD card:<table>");
|
||||
std::list<String> files = _player->ls("/", false, true, false);
|
||||
for(std::list<String>::iterator it=files.begin(); it!=files.end(); it++) {
|
||||
response.concat("<tr><td>");
|
||||
response.concat(*it);
|
||||
response.concat("</td><td><a href='#' onclick='play_album();'>Play</a></td></tr>\n");
|
||||
}
|
||||
response.concat("</table></body></html>");
|
||||
_http_server->send(200, "text/html", response);
|
||||
}
|
||||
|
||||
void HTTPServer::_handle_status() {
|
||||
String response = String("{");
|
||||
response.concat("\"state\": \"");
|
||||
response.concat(_player->is_playing() ? "playing" : "idle");
|
||||
response.concat("\", ");
|
||||
if (_player->is_playing()) {
|
||||
response.concat("\"album\": \"");
|
||||
response.concat(_player->album());
|
||||
response.concat("\", \"track\": ");
|
||||
response.concat(_player->track());
|
||||
response.concat(", \"position\": ");
|
||||
response.concat(_player->position());
|
||||
response.concat(", ");
|
||||
}
|
||||
response.concat("\"volume\": ");
|
||||
response.concat(_player->volume());
|
||||
response.concat(", \"volume_max\": ");
|
||||
response.concat(VOLUME_MAX);
|
||||
response.concat(", \"volume_min\": ");
|
||||
response.concat(VOLUME_MIN);
|
||||
response.concat(", \"rfid_uid\": ");
|
||||
response.concat(_controller->rfid_uid());
|
||||
response.concat("}");
|
||||
_http_server->send(200, "application/json", response);
|
||||
}
|
||||
|
||||
void HTTPServer::loop() {
|
||||
_http_server->handleClient();
|
||||
MDNS.update();
|
||||
}
|
||||
Reference in New Issue
Block a user