#include "driver/i2s_pdm.h"
#include "Arduino.h"
#include <WiFi.h>
#include <EEPROM.h>
/* ========== 默认参数 ========== */
const char *ssid_dft = "123";
const char *pass_dft = "12345678";
const int port_dft = 8888;
const char *eeprom_ip_dft= "192.168.107.97";
const char *local_ip_dft = "192.168.107.88";
const char *gateway_dft = "192.168.107.1";
const char *netmask_dft = "255.255.255.0";
/* ========== 运行期变量 ========== */
char ssid[32] = {0};
char password[64] = {0};
int server_port = port_dft;
char eeprom_ip[16]= {0};
char eeprom_local_ip[16] = {0};
char eeprom_gw[16] = {0};
char eeprom_mask[16] = {0};
bool use_static_flag = false;
WiFiClient client;
#define PDM_CLK_GPIO 4
#define PDM_DIN_GPIO 5
i2s_chan_handle_t rx_chan = nullptr;
/* -------- 函数声明 -------- */
void configure_i2s();
bool parse_ip_cmd(const char *line);
void load_cfg_from_eeprom();
void save_cfg_to_eeprom();
/* -------------------------- */
void setup() {
Serial.begin(115200);
EEPROM.begin(256); // 128 也够用,留余量
load_cfg_from_eeprom(); // 一次性读出全部配置
configure_i2s();
WiFi.begin(ssid, password);
/* ---- 关键:静态 IP ---- */
if (use_static_flag) {
IPAddress lip, gw, sn;
lip.fromString(eeprom_local_ip);
gw .fromString(eeprom_gw);
sn .fromString(eeprom_mask);
WiFi.config(lip, gw, sn);
}
/* ----------------------- */
while (WiFi.status() != WL_CONNECTED) delay(500);
Serial.println("WiFi已连接");
Serial.print("ESP32本地IP: ");
Serial.println(WiFi.localIP());
Serial.print("目标服务器: ");
Serial.print(eeprom_ip);
Serial.print(':');
Serial.println(server_port);
WiFi.setTxPower(WIFI_POWER_8_5dBm);
gpio_set_drive_capability((gpio_num_t)PDM_CLK_GPIO, GPIO_DRIVE_CAP_1);
gpio_set_drive_capability((gpio_num_t)PDM_DIN_GPIO, GPIO_DRIVE_CAP_1);
gpio_set_pull_mode((gpio_num_t)PDM_DIN_GPIO, GPIO_PULLUP_ONLY);
}
void loop() {
/* 1. 串口命令接收(非阻塞) */
static uint8_t cmd_buf[128], cmdIdx = 0;
while (Serial.available()) {
char c = Serial.read();
if (c == '\n' || c == '\r') {
if (cmdIdx) {
cmd_buf[cmdIdx] = 0;
if (parse_ip_cmd((char *)cmd_buf)) {
save_cfg_to_eeprom();
Serial.println("Save & Restart...");
delay(100);
ESP.restart();
}
cmdIdx = 0;
}
} else if (cmdIdx < sizeof(cmd_buf) - 1) {
cmd_buf[cmdIdx++] = c;
}
}
/* 2. TCP 重连 */
if (!client.connected()) {
if (client.connect(eeprom_ip, server_port)) {
Serial.println("TCP流已建立");
} else {
delay(1000);
}
return;
}
/* 3. 非阻塞读 I2S 并实时转发 */
static int16_t buf[512];
size_t bytes_read = 0;
if (i2s_channel_read(rx_chan, buf, sizeof(buf), &bytes_read, portMAX_DELAY) == ESP_OK) {
client.write((uint8_t*)buf, bytes_read);
}
}
/* ==================== I2S 驱动 ==================== */
void configure_i2s() {
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
chan_cfg.dma_desc_num = 16;
chan_cfg.dma_frame_num = 1024;
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, nullptr, &rx_chan));
i2s_pdm_rx_config_t pdm_cfg = {
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(16000),
.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.gpio_cfg = { .clk = (gpio_num_t)PDM_CLK_GPIO, .din = (gpio_num_t)PDM_DIN_GPIO,
.invert_flags = { .clk_inv = false } },
};
ESP_ERROR_CHECK(i2s_channel_init_pdm_rx_mode(rx_chan, &pdm_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
}
/* ==================== 串口命令 & EEPROM ==================== */
//ssid=Test pass=12345678 ip=192.168.107.97 port=8888 lip=192.168.1.99 gw=192.168.1.1 mask=255.255.255.0 dhcp=0
bool parse_ip_cmd(const char *line) {
bool changed = false;
char tmp[128];
strcpy(tmp, line);
char *tok = strtok(tmp, " ");
while (tok) {
if (strncmp(tok, "ip=", 3) == 0) {
unsigned int seg[4];
if (sscanf(tok + 3, "%3u.%3u.%3u.%3u", &seg[0], &seg[1], &seg[2], &seg[3]) == 4) {
bool ok = true;
for (int i = 0; i < 4; ++i) if (seg[i] > 255) ok = false;
if (ok && strlen(tok + 3) < 16) {
strcpy(eeprom_ip, tok + 3);
changed = true;
}
}
} else if (strncmp(tok, "ssid=", 5) == 0 && strlen(tok + 5) < 32) {
strcpy(ssid, tok + 5); changed = true;
} else if (strncmp(tok, "pass=", 5) == 0 && strlen(tok + 5) < 64) {
strcpy(password, tok + 5); changed = true;
} else if (strncmp(tok, "port=", 5) == 0) {
int p = atoi(tok + 5);
if (p > 0 && p <= 65535) { server_port = p; changed = true; }
}
/* ---- 新增本地 IP 相关命令 ---- */
else if (strncmp(tok, "lip=", 4) == 0) {
if (strlen(tok + 4) < 16) { strcpy(eeprom_local_ip, tok + 4); changed = true; }
} else if (strncmp(tok, "gw=", 3) == 0) {
if (strlen(tok + 3) < 16) { strcpy(eeprom_gw, tok + 3); changed = true; }
} else if (strncmp(tok, "mask=", 5) == 0) {
if (strlen(tok + 5) < 16) { strcpy(eeprom_mask, tok + 5); changed = true; }
} else if (strncmp(tok, "dhcp=", 5) == 0) {
int d = atoi(tok + 5);
use_static_flag = (d == 0);
changed = true;
}
/* ------------------------------ */
tok = strtok(nullptr, " ");
}
return changed;
}
/* ---------- EEPROM 读写 ---------- */
void load_cfg_from_eeprom() {
struct __attribute__((packed)) cfg {
char ip[16];
char ssid[32];
char pass[64];
int port;
bool use_static;
char local_ip[16];
char gateway[16];
char netmask[16];
uint8_t crc;
} c;
EEPROM.get(0, c);
uint8_t *p = (uint8_t*)&c;
uint8_t sum = 0;
for (int i = 0; i < sizeof(c) - 1; ++i) sum += p[i];
if (sum == c.crc && c.port > 0 && c.port <= 65535) {
strcpy(eeprom_ip, c.ip);
strcpy(ssid, c.ssid);
strcpy(password, c.pass);
server_port = c.port;
use_static_flag = c.use_static;
strcpy(eeprom_local_ip, c.local_ip);
strcpy(eeprom_gw, c.gateway);
strcpy(eeprom_mask, c.netmask);
Serial.println("从EEPROM载入配置成功");
} else {
/* 使用默认值并立即保存一份 */
strcpy(eeprom_ip, eeprom_ip_dft);
strcpy(ssid, ssid_dft);
strcpy(password, pass_dft);
server_port = port_dft;
use_static_flag = false;
strcpy(eeprom_local_ip, local_ip_dft);
strcpy(eeprom_gw, gateway_dft);
strcpy(eeprom_mask, netmask_dft);
save_cfg_to_eeprom();
}
}
void save_cfg_to_eeprom() {
struct __attribute__((packed)) cfg {
char ip[16];
char ssid[32];
char pass[64];
int port;
bool use_static;
char local_ip[16];
char gateway[16];
char netmask[16];
uint8_t crc;
} c;
strcpy(c.ip, eeprom_ip);
strcpy(c.ssid, ssid);
strcpy(c.pass, password);
c.port = server_port;
c.use_static = use_static_flag;
strcpy(c.local_ip, eeprom_local_ip);
strcpy(c.gateway, eeprom_gw);
strcpy(c.netmask, eeprom_mask);
uint8_t *p = (uint8_t*)&c;
uint8_t sum = 0;
for (int i = 0; i < sizeof(c) - 1; ++i) sum += p[i];
c.crc = sum;
EEPROM.put(0, c);
EEPROM.commit();
Serial.println("配置已写入EEPROM");
}
ssid=Test pass=12345678 ip=192.168.107.97 port=8888 lip=192.168.1.99 gw=192.168.1.1 mask=255.255.255.0 dhcp=0,使用的是串口0,电脑直接输入即可