#include <Arduino.h>
#include <WiFi.h>
#include <SPI.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include <ArduinoJson.h>
// Configurazione hardware
#define CS_PIN 5
#define DRDY_PIN 4
// Configurazione acquisizione
#define DEFAULT_SAMPLE_RATE 30000 // Hz
// Configurazione Wi-Fi
const char* WIFI_SSID = "WebPocket-E280";
const char* WIFI_PASSWORD = "dorabino.7468!";
// Gestione configurazione
struct Config {
uint32_t sampleRate;
uint8_t gain;
bool filterEnabled;
float threshold;
bool streaming;
};
// Variabili globali
QueueHandle_t dataQueue;
QueueHandle_t eventQueue;
AsyncWebServer server(80);
AsyncWebSocket wsData("/data");
AsyncWebSocket wsEvents("/events");
Config globalConfig = {DEFAULT_SAMPLE_RATE, 1, false, 1000000, true};
float emaAlpha = 0.1; // Coefficiente EMA
// Gestione eventi WebSocket
void onEventsWebSocket(AsyncWebSocket *server, AsyncWebSocketClient *client,
AwsEventType type, void *arg, uint8_t *data, size_t len) {
if (type == WS_EVT_CONNECT) {
Serial.printf("Client eventi %u connesso\n", client->id());
} else if (type == WS_EVT_DISCONNECT) {
Serial.printf("Client eventi %u disconnesso\n", client->id());
} else if (type == WS_EVT_DATA) {
String message = String((char*)data).substring(0, len);
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, message);
if (!error) {
if (doc.containsKey("samplerate")) {
globalConfig.sampleRate = doc["samplerate"].as<int>();
Serial.printf("Sample rate impostato a: %d\n", globalConfig.sampleRate);
}
if (doc.containsKey("alfaema")) {
emaAlpha = doc["alfaema"].as<float>();
Serial.printf("EMA alpha impostato a: %.2f\n", emaAlpha);
}
}
}
}
/*
void IRAM_ATTR adcTask(void* pvParameters) {
SPIClass spi(VSPI);
spi.begin(18, 19, 23, CS_PIN);
pinMode(CS_PIN, OUTPUT);
pinMode(DRDY_PIN, INPUT);
uint32_t lastSample = 0;
uint32_t sampleInterval = 1000000 / globalConfig.sampleRate;
float emaFilteredValue = 0.0;
while (true) {
if (!globalConfig.streaming) {
vTaskDelay(100 / portTICK_PERIOD_MS);
continue;
}
if (digitalRead(DRDY_PIN) == LOW &&
(micros() - lastSample) >= sampleInterval) {
digitalWrite(CS_PIN, LOW);
uint8_t data[3] = {0x01, 0x02, 0x03};
digitalWrite(CS_PIN, HIGH);
int32_t value = (data[0] << 16) | (data[1] << 8) | data[2];
if (value & 0x800000) value -= 0x1000000;
emaFilteredValue = emaAlpha * value + (1 - emaAlpha) * emaFilteredValue;
xQueueSend(dataQueue, &emaFilteredValue, 0);
lastSample = micros();
}
}
}
*/
void printWiFiDetails() {
if(WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi Connection Details:");
Serial.printf("SSID: %s\n", WiFi.SSID().c_str());
Serial.printf("BSSID: %s\n", WiFi.BSSIDstr().c_str());
Serial.printf("Channel: %d\n", WiFi.channel());
Serial.printf("RSSI: %d dBm\n", WiFi.RSSI());
Serial.printf("IP: %s\n", WiFi.localIP().toString().c_str());
Serial.printf("Subnet: %s\n", WiFi.subnetMask().toString().c_str());
Serial.printf("Gateway: %s\n", WiFi.gatewayIP().toString().c_str());
Serial.printf("DNS: %s\n", WiFi.dnsIP().toString().c_str());
Serial.printf("MAC: %s\n", WiFi.macAddress().c_str());
}
}
void printFailReason(wifi_err_reason_t reason) {
switch(reason) {
case WIFI_REASON_AUTH_EXPIRE:
Serial.println("Auth expire");
break;
case WIFI_REASON_AUTH_LEAVE:
Serial.println("Auth leave");
break;
case WIFI_REASON_ASSOC_EXPIRE:
Serial.println("Association expire");
break;
case WIFI_REASON_ASSOC_TOOMANY:
Serial.println("Too many associations");
break;
case WIFI_REASON_NOT_AUTHED:
Serial.println("Not authenticated");
break;
case WIFI_REASON_NOT_ASSOCED:
Serial.println("Not associated");
break;
case WIFI_REASON_ASSOC_LEAVE:
Serial.println("Association leave");
break;
case WIFI_REASON_HANDSHAKE_TIMEOUT:
Serial.println("Handshake timeout");
break;
default:
Serial.printf("Unknown reason: %d\n", reason);
break;
}
}
void printHeapInfo() {
Serial.printf("Free Heap: %d bytes\n", ESP.getFreeHeap());
Serial.printf("Min Free Heap: %d bytes\n", ESP.getMinFreeHeap());
Serial.printf("Max Alloc Heap: %d bytes\n", ESP.getMaxAllocHeap());
}
void adcTask(void* pvParameters) {
uint32_t lastSample = 0;
uint32_t sampleInterval = 1000000 / globalConfig.sampleRate;
while (true) {
if (!globalConfig.streaming) {
vTaskDelay(100 / portTICK_PERIOD_MS);
continue;
}
if ((micros() - lastSample) >= sampleInterval) {
uint32_t timestamp = micros();
float sample = random(0, 1000); // Campioni casuali (da 0 a 1000)
// Pacchetto JSON con campione e timestamp
char message[128];
snprintf(message, sizeof(message), "{\"timestamp\": %u, \"sample\": %.2f}", timestamp, sample);
// Invia al server WebSocket
xQueueSend(dataQueue, &message, 0);
lastSample = timestamp;
}
}
}
// Task gestione dati WebSocket (Core 1)
void webSocketDataTask(void* pvParameters) {
float value;
char buffer[32];
while(true) {
if(xQueueReceive(dataQueue, &value, portMAX_DELAY) == pdTRUE) {
if(wsData.count() > 0) { // Se ci sono client connessi
snprintf(buffer, sizeof(buffer), "%.2f", value);
wsData.textAll(buffer);
}
}
}
}
void setup() {
Serial.begin(9600);
// Abilita log verbose
esp_log_level_set("wifi", ESP_LOG_VERBOSE);
// Configura WiFi
WiFi.mode(WIFI_STA);
Serial.print("Connecting to WiFi");
WiFi.begin("Wokwi-GUEST", "", 6);
// Loop connessione con timeout
uint8_t attempts = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
printWiFiDetails();
printHeapInfo();
// Aspetta un attimo per stabilizzare la connessione
delay(1000);
// Crea le code
dataQueue = xQueueCreate(1024, sizeof(float));
eventQueue = xQueueCreate(32, sizeof(char*));
// Configurazione WebSocket
wsEvents.onEvent(onEventsWebSocket);
server.addHandler(&wsEvents);
server.addHandler(&wsData);
server.begin();
// Avvia i task sui core specifici
// WebSocket sul Core 0 dove già gira il networking
xTaskCreatePinnedToCore(webSocketDataTask, "WS Data Task", 8192, NULL, 1, NULL, 0);
Serial.println("\nTask websocket creato");
delay(2000);
// ADC sul Core 1 dove ha più risorse dedicate
//xTaskCreatePinnedToCore(adcTask, "ADC Task", 16384, NULL, 5, NULL, 1);
Serial.println("\nTask ADC creato");
Serial.println("Sistema inizializzato");
}
void loop() {
delay(1); // Previene watchdog reset
}
esp:0
esp:2
esp:4
esp:5
esp:12
esp:13
esp:14
esp:15
esp:16
esp:17
esp:18
esp:19
esp:21
esp:22
esp:23
esp:25
esp:26
esp:27
esp:32
esp:33
esp:34
esp:35
esp:3V3
esp:EN
esp:VP
esp:VN
esp:GND.1
esp:D2
esp:D3
esp:CMD
esp:5V
esp:GND.2
esp:TX
esp:RX
esp:GND.3
esp:D1
esp:D0
esp:CLK