ИИ шутит. Беседовали о reverse engineering чужих прошивок.
Потому что после нескольких лет реверса начинаешь понимать, что “точка входа” — это скорее юридическое понятие, чем техническое.
ИИ шутит. Беседовали о reverse engineering чужих прошивок.
Потому что после нескольких лет реверса начинаешь понимать, что “точка входа” — это скорее юридическое понятие, чем техническое.
Мда уж. В наше время “это другое” стало наиболее вероятным продолжением любой фразы, когда пытаются поймать за хвост. И ИИ это демонстрирует.
Ага. У меня как-то назвал подстроечный резистор “крутистором” и сказал “вращение многооборотного крутистора – занятие глубокомысленное и медиативное, способствует поиску баланса и гармонии с миром и потому является мощным антидепрессантом”
Может ли искусственный интеллект придумать такую капчу, которую искусственный интеллект не сможет решить?
а что бы ее могли решить люди обязательно ?
и если да, тогда надо затратить кучу времени для создания разных вариаций, что бы человек жал на картинку по таким правилам, нажмите на красный предмет который тяжелее синего и легче зеленого, и все ии в ступоре будет))) главное вариаций побольше! что бы не обучили легко обходить
Вот код от ИИ.
// ============================================================================
// ESP32 + VS1003 MP3 Decoder с WiFi и Web-управлением
// + Воспроизведение MP3-потока с URL (интернет-радио)
// ============================================================================
// Подключение VS1003 к ESP32:
// VS1003 -> ESP32
// XRESET -> GPIO4 (сброс)
// XCS -> GPIO5 (CS для команд)
// XDCS -> GPIO18 (CS для данных)
// DREQ -> GPIO19 (готовность данных)
// MOSI -> GPIO23 (MOSI)
// MISO -> GPIO19 (MISO)
// SCK -> GPIO18 (SCK)
// ============================================================================
#include <WiFi.h>
#include <WebServer.h>
#include <SPI.h>
#include <SD.h>
#include <HTTPClient.h>
#include <WiFiClient.h>
// ==================== НАСТРОЙКИ WiFi ====================
// Режим AP (точка доступа) - ESP32 создаёт свою сеть
const char* AP_SSID = "ESP32-MP3-Player";
const char* AP_PASSWORD = "mp3player123";
// Режим STA (подключение к существующей сети)
const char* STA_SSID = "YOUR_WIFI_SSID";
const char* STA_PASSWORD = "YOUR_WIFI_PASSWORD";
// ==================== ПИНЫ VS1003 ====================
#define VS_XRESET 4
#define VS_XCS 5
#define VS_XDCS 16
#define VS_DREQ 17
#define VS_MOSI 23
#define VS_MISO 19
#define VS_SCK 18
// ==================== ПИН SD-КАРТЫ ====================
#define SD_CS 21
// ==================== РЕГИСТРЫ VS1003 ====================
#define VS_WRITE_COMMAND 0x02
#define VS_READ_COMMAND 0x03
#define VS_MODE_REG 0x00
#define VS_STATUS_REG 0x01
#define VS_BASS_REG 0x02
#define VS_CLOCKF_REG 0x03
#define VS_DECODE_TIME_REG 0x04
#define VS_AUDATA_REG 0x05
#define VS_WRAM_REG 0x06
#define VS_WRAMADDR_REG 0x07
#define VS_HDAT0_REG 0x08
#define VS_HDAT1_REG 0x09
#define VS_AIADDR_REG 0x0A
#define VS_VOL_REG 0x0B
#define VS_AICTRL0_REG 0x0C
#define VS_AICTRL1_REG 0x0D
#define VS_AICTRL2_REG 0x0E
#define VS_AICTRL3_REG 0x0F
// ==================== ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ====================
WebServer server(80);
File currentFile;
WiFiClient streamClient;
HTTPClient httpClient;
bool isPlaying = false;
bool isPaused = false;
bool isStreaming = false; // true = поток с URL, false = файл с SD
String currentTrack = "Нет трека";
String currentStreamURL = "";
int currentVolume = 50;
float currentBass = 0;
float currentTreble = 0;
unsigned long streamBytesReceived = 0;
unsigned long lastStreamBitrateUpdate = 0;
unsigned long streamBitrate = 0;
TaskHandle_t playTaskHandle = NULL;
// ==================== HTML ИНТЕРФЕЙС ====================
const char* HTML_PAGE = R"rawliteral(
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESP32 MP3 Player & Radio</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
min-height: 100vh;
color: #eee;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
}
h1 {
text-align: center;
margin-bottom: 30px;
color: #00d4ff;
text-shadow: 0 0 20px rgba(0,212,255,0.3);
}
.player-card {
background: rgba(255,255,255,0.05);
border-radius: 20px;
padding: 25px;
margin-bottom: 20px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.1);
}
.now-playing {
text-align: center;
margin-bottom: 20px;
}
.track-name {
font-size: 1.3em;
color: #00d4ff;
margin: 10px 0;
word-break: break-all;
}
.status {
color: #888;
font-size: 0.9em;
}
.stream-badge {
display: inline-block;
background: linear-gradient(135deg, #ff4757, #cc0033);
color: white;
padding: 3px 12px;
border-radius: 12px;
font-size: 0.75em;
margin-left: 8px;
vertical-align: middle;
}
.file-badge {
display: inline-block;
background: linear-gradient(135deg, #2ed573, #1e90ff);
color: white;
padding: 3px 12px;
border-radius: 12px;
font-size: 0.75em;
margin-left: 8px;
vertical-align: middle;
}
.controls {
display: flex;
justify-content: center;
gap: 15px;
margin: 20px 0;
}
.btn {
width: 60px;
height: 60px;
border-radius: 50%;
border: none;
cursor: pointer;
font-size: 24px;
transition: all 0.3s;
display: flex;
align-items: center;
justify-content: center;
}
.btn-play {
background: linear-gradient(135deg, #00d4ff, #0099cc);
color: white;
width: 70px;
height: 70px;
font-size: 28px;
}
.btn-play:hover { transform: scale(1.1); box-shadow: 0 0 30px rgba(0,212,255,0.5); }
.btn-stop {
background: linear-gradient(135deg, #ff4757, #cc0033);
color: white;
}
.btn-stop:hover { transform: scale(1.1); box-shadow: 0 0 30px rgba(255,71,87,0.5); }
.btn-pause {
background: linear-gradient(135deg, #ffa502, #ff7f00);
color: white;
}
.btn-pause:hover { transform: scale(1.1); box-shadow: 0 0 30px rgba(255,165,2,0.5); }
.btn-next, .btn-prev {
background: rgba(255,255,255,0.1);
color: #00d4ff;
border: 2px solid #00d4ff;
}
.btn-next:hover, .btn-prev:hover {
background: #00d4ff;
color: #1a1a2e;
}
.slider-container {
margin: 20px 0;
}
.slider-label {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
color: #aaa;
}
input[type="range"] {
width: 100%;
height: 8px;
border-radius: 4px;
background: rgba(255,255,255,0.1);
outline: none;
-webkit-appearance: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 24px;
height: 24px;
border-radius: 50%;
background: #00d4ff;
cursor: pointer;
box-shadow: 0 0 15px rgba(0,212,255,0.5);
}
.file-list {
max-height: 250px;
overflow-y: auto;
}
.file-item {
padding: 12px 15px;
margin: 5px 0;
background: rgba(255,255,255,0.05);
border-radius: 10px;
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
gap: 10px;
}
.file-item:hover {
background: rgba(0,212,255,0.2);
transform: translateX(5px);
}
.file-item.playing {
background: rgba(0,212,255,0.3);
border-left: 4px solid #00d4ff;
}
.file-icon { font-size: 1.2em; }
.wifi-info {
text-align: center;
color: #666;
font-size: 0.85em;
margin-top: 20px;
}
.progress-bar {
width: 100%;
height: 6px;
background: rgba(255,255,255,0.1);
border-radius: 3px;
margin: 15px 0;
overflow: hidden;
}
.progress-fill {
height: 100%;
width: 0%;
background: linear-gradient(90deg, #00d4ff, #0099cc);
border-radius: 3px;
transition: width 0.5s;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.playing-indicator {
display: inline-block;
animation: pulse 1s infinite;
}
.stream-section {
margin-top: 20px;
}
.stream-input {
width: 100%;
padding: 12px 15px;
border-radius: 10px;
border: 1px solid rgba(0,212,255,0.3);
background: rgba(255,255,255,0.05);
color: #eee;
font-size: 1em;
margin-bottom: 10px;
}
.stream-input::placeholder { color: #666; }
.stream-input:focus {
outline: none;
border-color: #00d4ff;
box-shadow: 0 0 10px rgba(0,212,255,0.2);
}
.btn-stream {
width: 100%;
padding: 12px;
border-radius: 10px;
border: none;
background: linear-gradient(135deg, #ff4757, #cc0033);
color: white;
font-size: 1em;
cursor: pointer;
transition: all 0.3s;
}
.btn-stream:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(255,71,87,0.4);
}
.preset-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 10px;
}
.preset-btn {
padding: 8px 14px;
border-radius: 20px;
border: 1px solid rgba(0,212,255,0.3);
background: rgba(255,255,255,0.05);
color: #00d4ff;
cursor: pointer;
font-size: 0.85em;
transition: all 0.3s;
}
.preset-btn:hover {
background: rgba(0,212,255,0.2);
border-color: #00d4ff;
}
.bitrate-info {
text-align: center;
color: #888;
font-size: 0.85em;
margin-top: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1>🎵 ESP32 MP3 Player & Radio</h1>
<div class="player-card">
<div class="now-playing">
<div class="status" id="status">Готов</div>
<div class="track-name" id="trackName">Нет трека</div>
<div class="bitrate-info" id="bitrateInfo"></div>
<div class="progress-bar">
<div class="progress-fill" id="progressBar"></div>
</div>
</div>
<div class="controls">
<button class="btn btn-prev" onclick="sendCmd('prev')">⏮</button>
<button class="btn btn-play" id="playBtn" onclick="togglePlay()">▶</button>
<button class="btn btn-pause" onclick="sendCmd('pause')">⏸</button>
<button class="btn btn-stop" onclick="sendCmd('stop')">⏹</button>
<button class="btn btn-next" onclick="sendCmd('next')">⏭</button>
</div>
<div class="slider-container">
<div class="slider-label">
<span>🔊 Громкость</span>
<span id="volValue">50%</span>
</div>
<input type="range" min="0" max="100" value="50" id="volumeSlider" oninput="setVolume(this.value)">
</div>
<div class="slider-container">
<div class="slider-label">
<span>🎸 Bass</span>
<span id="bassValue">0</span>
</div>
<input type="range" min="0" max="15" value="0" id="bassSlider" oninput="setBass(this.value)">
</div>
<div class="slider-container">
<div class="slider-label">
<span>🎺 Treble</span>
<span id="trebleValue">0</span>
</div>
<input type="range" min="-8" max="7" value="0" id="trebleSlider" oninput="setTreble(this.value)">
</div>
</div>
<div class="player-card">
<h3 style="margin-bottom: 15px; color: #ff4757;">📡 Интернет-радио / Поток</h3>
<input type="text" class="stream-input" id="streamUrl"
placeholder="Введите URL MP3-потока..."
value="http://stream.radioparadise.com/mp3-192">
<button class="btn-stream" onclick="playStream()">▶ Воспроизвести поток</button>
<div style="margin-top: 15px; color: #888; font-size: 0.85em;">Быстрые ссылки:</div>
<div class="preset-list">
<button class="preset-btn" onclick="setStream('http://stream.radioparadise.com/mp3-192')">Radio Paradise</button>
<button class="preset-btn" onclick="setStream('http://ice1.somafm.com/groovesalad-128-mp3')">SomaFM Groove</button>
<button class="preset-btn" onclick="setStream('http://icecast.err.ee:80/vikerraadio.mp3')">Vikerraadio</button>
<button class="preset-btn" onclick="setStream('http://stream.live.vc.bbcmedia.co.uk/bbc_radio_one')">BBC Radio 1</button>
<button class="preset-btn" onclick="setStream('http://icecast.omroep.nl/radio1-bb-mp3')">NPO Radio 1</button>
<button class="preset-btn" onclick="setStream('http://direct.fipradio.fr/live/fip-midfi.mp3')">FIP Radio</button>
</div>
</div>
<div class="player-card">
<h3 style="margin-bottom: 15px; color: #00d4ff;">📁 Плейлист (SD-карта)</h3>
<div class="file-list" id="fileList">
<div class="file-item">Загрузка...</div>
</div>
</div>
<div class="wifi-info" id="wifiInfo"></div>
</div>
<script>
let isPlaying = false;
let isStreaming = false;
let currentTrack = '';
function sendCmd(cmd) {
fetch('/cmd?action=' + cmd)
.then(r => r.json())
.then(data => updateUI(data));
}
function togglePlay() {
sendCmd(isPlaying ? 'pause' : 'play');
}
function setVolume(val) {
document.getElementById('volValue').textContent = val + '%';
fetch('/cmd?action=volume&value=' + val);
}
function setBass(val) {
document.getElementById('bassValue').textContent = val;
fetch('/cmd?action=bass&value=' + val);
}
function setTreble(val) {
document.getElementById('trebleValue').textContent = val;
fetch('/cmd?action=treble&value=' + val);
}
function playFile(filename) {
fetch('/cmd?action=playfile&file=' + encodeURIComponent(filename))
.then(r => r.json())
.then(data => updateUI(data));
}
function setStream(url) {
document.getElementById('streamUrl').value = url;
}
function playStream() {
const url = document.getElementById('streamUrl').value.trim();
if (!url) return;
fetch('/cmd?action=stream&url=' + encodeURIComponent(url))
.then(r => r.json())
.then(data => updateUI(data));
}
function updateUI(data) {
isPlaying = data.playing;
isStreaming = data.streaming;
currentTrack = data.track;
document.getElementById('trackName').innerHTML = (data.track || 'Нет трека') +
(isStreaming ? '<span class="stream-badge">STREAM</span>' :
(isPlaying ? '<span class="file-badge">FILE</span>' : ''));
document.getElementById('status').textContent = data.status;
document.getElementById('playBtn').textContent = isPlaying ? '⏸' : '▶';
document.getElementById('progressBar').style.width = data.progress + '%';
document.getElementById('bitrateInfo').textContent = data.bitrate > 0 ?
'Bitrate: ' + Math.round(data.bitrate / 1024) + ' KB/s' : '';
document.querySelectorAll('.file-item').forEach(item => {
item.classList.toggle('playing', item.dataset.file === data.track);
});
}
function loadFileList() {
fetch('/files')
.then(r => r.json())
.then(files => {
const list = document.getElementById('fileList');
list.innerHTML = files.map(f =>
`<div class="file-item ${f === currentTrack ? 'playing' : ''}"
data-file="${f}" onclick="playFile('${f}')">
<span class="file-icon">🎵</span>
<span>${f}</span>
</div>`
).join('') || '<div class="file-item">Нет MP3 файлов</div>';
});
}
function updateStatus() {
fetch('/status')
.then(r => r.json())
.then(data => updateUI(data));
}
loadFileList();
fetch('/wifi').then(r => r.text()).then(t => document.getElementById('wifiInfo').innerHTML = t);
setInterval(updateStatus, 1000);
setInterval(loadFileList, 10000);
</script>
</body>
</html>
)rawliteral";
// ==================== ФУНКЦИИ VS1003 ====================
void vs1003_writeRegister(uint8_t reg, uint16_t value) {
//while (!digitalRead(VS_DREQ));
while (!digitalRead(VS_DREQ)) {
delay(50);
}
digitalWrite(VS_XCS, LOW);
SPI.transfer(VS_WRITE_COMMAND);
SPI.transfer(reg);
SPI.transfer(value >> 8);
SPI.transfer(value & 0xFF);
digitalWrite(VS_XCS, HIGH);
//while (!digitalRead(VS_DREQ));
while (!digitalRead(VS_DREQ)) {
delay(50);
}
}
uint16_t vs1003_readRegister(uint8_t reg) {
//while (!digitalRead(VS_DREQ));
while (!digitalRead(VS_DREQ)) {
delay(50);
}
digitalWrite(VS_XCS, LOW);
SPI.transfer(VS_READ_COMMAND);
SPI.transfer(reg);
uint16_t result = SPI.transfer(0xFF) << 8;
result |= SPI.transfer(0xFF);
digitalWrite(VS_XCS, HIGH);
//while (!digitalRead(VS_DREQ));
while (!digitalRead(VS_DREQ)) {
delay(50);
}
return result;
}
void vs1003_sendData(const uint8_t* data, size_t len) {
while (len > 0) {
while (!digitalRead(VS_DREQ));
digitalWrite(VS_XDCS, LOW);
size_t chunk = min(len, (size_t)32);
SPI.writeBytes(data, chunk);
digitalWrite(VS_XDCS, HIGH);
data += chunk;
len -= chunk;
}
}
void vs1003_setVolume(int vol) {
if (vol < 0) vol = 0;
if (vol > 100) vol = 100;
int attenuation = map(vol, 0, 100, 0xFE, 0x00);
uint16_t volValue = (attenuation << 8) | attenuation;
vs1003_writeRegister(VS_VOL_REG, volValue);
currentVolume = vol;
}
void vs1003_setBass(int bass) {
uint16_t bassReg = vs1003_readRegister(VS_BASS_REG);
bassReg &= 0x00FF;
bassReg |= (bass & 0x0F) << 12;
vs1003_writeRegister(VS_BASS_REG, bassReg);
currentBass = bass;
}
void vs1003_setTreble(int treble) {
uint16_t bassReg = vs1003_readRegister(VS_BASS_REG);
bassReg &= 0xFF0F;
bassReg |= (treble & 0x0F) << 4;
vs1003_writeRegister(VS_BASS_REG, bassReg);
currentTreble = treble;
}
void vs1003_softReset() {
vs1003_writeRegister(VS_MODE_REG, 0x0804);
delay(100);
while (!digitalRead(VS_DREQ));
}
void vs1003_cancel() {
vs1003_writeRegister(VS_MODE_REG, 0x0808);
delay(100);
}
void vs1003_init() {
pinMode(VS_XRESET, OUTPUT);
pinMode(VS_XCS, OUTPUT);
pinMode(VS_XDCS, OUTPUT);
pinMode(VS_DREQ, INPUT);
digitalWrite(VS_XRESET, LOW);
digitalWrite(VS_XCS, HIGH);
digitalWrite(VS_XDCS, HIGH);
delay(10);
digitalWrite(VS_XRESET, HIGH);
delay(10);
SPI.begin(VS_SCK, VS_MISO, VS_MOSI, VS_XCS);
SPI.setFrequency(1000000);
vs1003_writeRegister(VS_MODE_REG, 0x0804);
delay(100);
//while (!digitalRead(VS_DREQ));
while (!digitalRead(VS_DREQ)) {
delay(50);
}
vs1003_writeRegister(VS_CLOCKF_REG, 0x8800);
delay(10);
vs1003_setVolume(50);
vs1003_writeRegister(VS_BASS_REG, 0x0000);
SPI.setFrequency(4000000);
}
// ==================== ОСТАНОВКА ВОСПРОИЗВЕДЕНИЯ ====================
void stopPlayback() {
isPlaying = false;
isPaused = false;
isStreaming = false;
if (currentFile) {
currentFile.close();
}
if (streamClient.connected()) {
streamClient.stop();
}
if (httpClient.connected()) {
httpClient.end();
}
vs1003_softReset();
currentTrack = "Нет трека";
currentStreamURL = "";
streamBytesReceived = 0;
streamBitrate = 0;
if (playTaskHandle != NULL) {
vTaskDelete(playTaskHandle);
playTaskHandle = NULL;
}
}
// ==================== ВОСПРОИЗВЕДЕНИЕ ФАЙЛА С SD ====================
void playFileTask(void* parameter) {
const size_t BUFFER_SIZE = 512;
uint8_t buffer[BUFFER_SIZE];
while (isPlaying && currentFile.available()) {
if (isPaused) {
vTaskDelay(100 / portTICK_PERIOD_MS);
continue;
}
size_t bytesRead = currentFile.read(buffer, BUFFER_SIZE);
if (bytesRead > 0) {
vs1003_sendData(buffer, bytesRead);
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
if (currentFile) {
currentFile.close();
}
isPlaying = false;
isPaused = false;
playTaskHandle = NULL;
vTaskDelete(NULL);
}
void playMP3File(const char* filename) {
stopPlayback();
currentFile = SD.open(filename);
if (!currentFile) {
Serial.println("Ошибка открытия файла: " + String(filename));
return;
}
currentTrack = String(filename);
isPlaying = true;
isPaused = false;
isStreaming = false;
Serial.println("Воспроизведение файла: " + String(filename));
xTaskCreatePinnedToCore(
playFileTask,
"PlayFileTask",
4096,
NULL,
1,
&playTaskHandle,
1
);
}
// ==================== ВОСПРОИЗВЕДЕНИЕ ПОТОКА С URL ====================
void playStreamTask(void* parameter) {
const size_t BUFFER_SIZE = 2048;
uint8_t buffer[BUFFER_SIZE];
unsigned long lastDataTime = millis();
unsigned long reconnectDelay = 2000;
int reconnectAttempts = 0;
const int MAX_RECONNECTS = 5;
while (isPlaying && isStreaming) {
if (isPaused) {
vTaskDelay(100 / portTICK_PERIOD_MS);
continue;
}
// Подключение к потоку
if (!streamClient.connected()) {
httpClient.end();
httpClient.setTimeout(10000);
httpClient.setReuse(true);
if (!httpClient.begin(streamClient, currentStreamURL)) {
Serial.println("Не удалось начать HTTP-запрос");
vTaskDelay(reconnectDelay / portTICK_PERIOD_MS);
reconnectAttempts++;
if (reconnectAttempts >= MAX_RECONNECTS) {
Serial.println("Превышено количество попыток переподключения");
break;
}
continue;
}
httpClient.addHeader("Icy-MetaData", "0");
httpClient.addHeader("User-Agent", "ESP32-MP3-Player/1.0");
int httpCode = httpClient.GET();
if (httpCode != HTTP_CODE_OK && httpCode != 200) {
Serial.println("HTTP ошибка: " + String(httpCode));
httpClient.end();
vTaskDelay(reconnectDelay / portTICK_PERIOD_MS);
reconnectAttempts++;
if (reconnectAttempts >= MAX_RECONNECTS) {
break;
}
continue;
}
Serial.println("Подключено к потоку, HTTP: " + String(httpCode));
reconnectAttempts = 0;
lastDataTime = millis();
}
// Чтение данных из потока
int available = streamClient.available();
if (available > 0) {
int toRead = min(available, (int)BUFFER_SIZE);
int bytesRead = streamClient.read(buffer, toRead);
if (bytesRead > 0) {
vs1003_sendData(buffer, bytesRead);
streamBytesReceived += bytesRead;
lastDataTime = millis();
// Расчёт битрейта
unsigned long now = millis();
if (now - lastStreamBitrateUpdate >= 1000) {
streamBitrate = streamBytesReceived;
streamBytesReceived = 0;
lastStreamBitrateUpdate = now;
}
}
} else {
// Проверка таймаута
if (millis() - lastDataTime > 30000) {
Serial.println("Таймаут потока, переподключение...");
streamClient.stop();
httpClient.end();
vTaskDelay(1000 / portTICK_PERIOD_MS);
reconnectAttempts++;
if (reconnectAttempts >= MAX_RECONNECTS) {
break;
}
}
vTaskDelay(5 / portTICK_PERIOD_MS);
}
}
streamClient.stop();
httpClient.end();
isPlaying = false;
isStreaming = false;
playTaskHandle = NULL;
Serial.println("Поток завершён");
vTaskDelete(NULL);
}
void playMP3Stream(const char* url) {
stopPlayback();
currentStreamURL = String(url);
isPlaying = true;
isPaused = false;
isStreaming = true;
currentTrack = String(url);
streamBytesReceived = 0;
streamBitrate = 0;
lastStreamBitrateUpdate = millis();
Serial.println("Воспроизведение потока: " + String(url));
xTaskCreatePinnedToCore(
playStreamTask,
"PlayStreamTask",
8192,
NULL,
1,
&playTaskHandle,
1
);
}
// ==================== WEB-ОБРАБОТЧИКИ ====================
void handleRoot() {
server.send(200, "text/html", HTML_PAGE);
}
void sendStatus() {
String json = "{";
json += "\"playing\":" + String(isPlaying && !isPaused ? "true" : "false") + ",";
json += "\"paused\":" + String(isPaused ? "true" : "false") + ",";
json += "\"streaming\":" + String(isStreaming ? "true" : "false") + ",";
json += "\"track\":\"" + currentTrack + "\",";
//json += "\"status\":\"" + String(isPlaying ? (isPaused ? "Пауза" : "Воспроизведение ▶") : "Готов") + "\",";
//json += "\"status\":\"" + String(isPlaying ? (isPaused ? "Пауза" : "Воспроизведение") : "Готов") + "\",";
json += "\"volume\":" + String(currentVolume) + ",";
json += "\"bitrate\":" + String(streamBitrate) + ",";
//json += "\"progress\":" + String(isPlaying && !isStreaming && currentFile ?
// (int)(currentFile.position() * 100 / currentFile.size()) : 0);
json += "}";
server.send(200, "application/json", json);
}
void handleStatus() {
sendStatus();
}
void handleCommand() {
String action = server.arg("action");
String value = server.arg("value");
String file = server.arg("file");
String url = server.arg("url");
if (action == "play") {
if (!isPlaying && currentTrack != "Нет трека" && !isStreaming) {
playMP3File(currentTrack.c_str());
}
}
else if (action == "pause") {
isPaused = !isPaused;
}
else if (action == "stop") {
stopPlayback();
}
else if (action == "playfile") {
playMP3File(file.c_str());
}
else if (action == "stream") {
if (url.length() > 0) {
playMP3Stream(url.c_str());
}
}
else if (action == "volume") {
vs1003_setVolume(value.toInt());
}
else if (action == "bass") {
vs1003_setBass(value.toInt());
}
else if (action == "treble") {
vs1003_setTreble(value.toInt());
}
else if (action == "next" || action == "prev") {
// TODO: реализовать навигацию по плейлисту
}
sendStatus();
}
//void handleStatus() {
// sendStatus();
//}
void handleFiles() {
String json = "[";
File root = SD.open("/");
bool first = true;
while (true) {
File entry = root.openNextFile();
if (!entry) break;
String name = entry.name();
if (name.endsWith(".mp3") || name.endsWith(".MP3")) {
if (!first) json += ",";
json += "\"" + name + "\"";
first = false;
}
entry.close();
}
root.close();
json += "]";
server.send(200, "application/json", json);
}
void handleWiFi() {
String info = "IP: " + WiFi.localIP().toString();
if (WiFi.getMode() & WIFI_AP) {
info += " | AP: " + WiFi.softAPIP().toString();
}
info += " | MAC: " + WiFi.macAddress();
server.send(200, "text/plain", info);
}
// ==================== SETUP ====================
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n=== ESP32 MP3 Player & Radio ===");
vs1003_init();
Serial.println("VS1003 инициализирован");
if (!SD.begin(SD_CS)) {
Serial.println("Ошибка инициализации SD-карты!");
} else {
Serial.println("SD-карта инициализирована");
}
WiFi.mode(WIFI_AP_STA);
WiFi.softAP(AP_SSID, AP_PASSWORD);
Serial.println("AP запущен: " + String(AP_SSID));
Serial.println("AP IP: " + WiFi.softAPIP().toString());
if (strlen(STA_SSID) > 0) {
WiFi.begin(STA_SSID, STA_PASSWORD);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nПодключено к WiFi: " + WiFi.localIP().toString());
}
}
server.on("/", HTTP_GET, handleRoot);
server.on("/cmd", HTTP_GET, handleCommand);
server.on("/status", HTTP_GET, handleStatus);
server.on("/files", HTTP_GET, handleFiles);
server.on("/wifi", HTTP_GET, handleWiFi);
server.begin();
Serial.println("Web-сервер запущен на порту 80");
Serial.println("Откройте браузер: http://" + WiFi.softAPIP().toString());
}
// ==================== LOOP ====================
void loop() {
server.handleClient();
delay(1);
}
Кто найдет ошибку?
Диагностика? Логи компилятора?
Попробуй компильнуть и залить в esp32. Логи чистые, но не работает.
Sketch uses 1032348 bytes (78%) of program storage space. Maximum is 1310720 bytes.
Global variables use 48800 bytes (14%) of dynamic memory, leaving 278880 bytes for local variables. Maximum is 327680 bytes.
Ответ дам потом. 2 дня искал.
как-то не конкретно
Похоже на типичный вопрос новичка на форуме ![]()
А вот это не косяк? 18й пин два раза и 19й два раза
Ваш комментарий не уместен. Вы реально спец или просто потролить?
Это коментарии. Реально - все правильно. Смотрите define.
Почему не уместен? как можно искать ошибку, не зная, что именно “не работает”?
Ты имел всю диагностику работы (не_работы)) модуля, мог проводить любые тесты и все равно разбирался два дня. А нам предлагаешь умозрительно найти ошибку, только глядя в код?
Ты же не думаешь, что ради твоей шарады мы станем собирать макет на реальном железе?
Даю подсказку.
Ошибка в одной строчке среди этого кода.
<div class="player-card">
<h3 style="margin-bottom: 15px; color: #ff4757;">📡 Интернет-радио / Поток</h3>
<input type="text" class="stream-input" id="streamUrl"
placeholder="Введите URL MP3-потока..."
value="http://stream.radioparadise.com/mp3-192">
<button class="btn-stream" onclick="playStream()">▶ Воспроизвести поток</button>
<div style="margin-top: 15px; color: #888; font-size: 0.85em;">Быстрые ссылки:</div>
<div class="preset-list">
<button class="preset-btn" onclick="setStream('http://stream.radioparadise.com/mp3-192')">Radio Paradise</button>
<button class="preset-btn" onclick="setStream('http://ice1.somafm.com/groovesalad-128-mp3')">SomaFM Groove</button>
<button class="preset-btn" onclick="setStream('http://icecast.err.ee:80/vikerraadio.mp3')">Vikerraadio</button>
<button class="preset-btn" onclick="setStream('http://stream.live.vc.bbcmedia.co.uk/bbc_radio_one')">BBC Radio 1</button>
<button class="preset-btn" onclick="setStream('http://icecast.omroep.nl/radio1-bb-mp3')">NPO Radio 1</button>
<button class="preset-btn" onclick="setStream('http://direct.fipradio.fr/live/fip-midfi.mp3')">FIP Radio</button>
</div>
</div>
В HTML ? Я пас
Это форум веб-дизайнеров или что? ![]()
Это не ошибка HTML. Это ошибка компилятора.
а если ошибку можно найти даже не в коде html, еще может и не одну, что тогда ?)))
Не надо гадать. Ошибка в одной строчке. Вывод web я приложил. Что характерно, что код компилится нормально, то почему появляются строчки #line xxx и т.д.