WIO
#include <rpcWiFi.h>
#include <WiFiUdp.h>
#include <TFT_eSPI.h>
#include "config.h" // Pulls in WIFI_SSID, WIFI_PASSWORD, and UDP_PORT
// UDP Configuration
WiFiUDP udp;
// TFT Screen
TFT_eSPI tft = TFT_eSPI();
// UI State Variables
int selectedTrack = 1;
const int maxTracks = 10;
void setup() {
Serial.begin(115200);
tft.begin();
tft.setRotation(3);
tft.fillScreen(TFT_BLACK);
tft.setTextSize(2);
tft.setTextColor(TFT_GREEN);
tft.drawString("Connecting to Wi-Fi...", 10, 10);
// Configure Joystick & Top Buttons as inputs (Fixed naming to WIO_5S)
pinMode(WIO_5S_UP, INPUT_PULLUP);
pinMode(WIO_5S_DOWN, INPUT_PULLUP);
pinMode(WIO_KEY_A, INPUT_PULLUP); // Right-most top button
pinMode(WIO_KEY_B, INPUT_PULLUP); // Middle top button
pinMode(WIO_KEY_C, INPUT_PULLUP); // <-- FIXED: Added missing
// Updated to use uppercase names from config.h
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
udp.begin(UDP_PORT); // Updated to match config.h
updateScreen();
}
void loop() {
// Joystick UP: Increment Track Number
if (digitalRead(WIO_5S_UP) == LOW) {
if (selectedTrack < maxTracks) {
selectedTrack++;
updateScreen();
delay(200); // Debounce
}
}
// Joystick DOWN: Decrement Track Number
if (digitalRead(WIO_5S_DOWN) == LOW) {
if (selectedTrack > 1) {
selectedTrack--;
updateScreen();
delay(200);
}
}
// Button A (Right Top Button): SEND PLAY COMMAND
if (digitalRead(WIO_KEY_A) == LOW) {
sendUDPCommand("PLAY:" + String(selectedTrack));
tft.setTextColor(TFT_RED);
tft.drawString("SENT: PLAY " + String(selectedTrack), 10, 150);
delay(400);
updateScreen();
}
// Button B (Middle Top Button): SEND STOP COMMAND
if (digitalRead(WIO_KEY_B) == LOW) {
sendUDPCommand("STOP");
tft.setTextColor(TFT_YELLOW);
tft.drawString("SENT: STOP ", 10, 150);
delay(400);
updateScreen();
}
// Button C (Left Top Button): SEND VOLUP COMMAND
if (digitalRead(WIO_KEY_C) == LOW) {
sendUDPCommand("VOLUP");
tft.setTextColor(TFT_YELLOW);
tft.drawString("SENT: VOLUP ", 10, 150);
delay(400);
updateScreen();
}
}
void updateScreen() {
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN);
tft.drawString("HALLOWEEN AUDIO MATRIX", 10, 10);
// Network Debug Info
tft.setTextSize(1);
tft.setTextColor(TFT_YELLOW);
tft.drawString("SSID: " + String(WiFi.SSID()), 10, 35);
tft.drawString("IP: " + WiFi.localIP().toString(), 10, 48);
tft.drawString("-----------------------------------", 10, 60);
tft.setTextSize(2);
tft.setTextColor(TFT_WHITE);
tft.drawString("Selected Track: " + String(selectedTrack), 10, 80);
tft.setTextSize(1);
tft.drawString("Press Top Right Button (A) to PLAY", 10, 120);
tft.drawString("Press Top Middle Button (B) to STOP", 10, 135);
tft.setTextSize(2);
}
void sendUDPCommand(String msg) {
// Pass direct IPAddress object for subnet broadcast
udp.beginPacket(IPAddress(255, 255, 255, 255), UDP_PORT);
udp.print(msg);
udp.endPacket();
Serial.println("Broadcasted: " + msg);
}
AtomS3U
#include "../config.h"
#include <Adafruit_NeoPixel.h>
#include <WiFi.h>
#include <WiFiUdp.h>
// --- Hardware Pins ---
#define LED_PIN 35
#define NUM_LEDS 1
// AtomS3U Grove port UART pins for the MP3 player
#define GROVE_RX_PIN 1
#define GROVE_TX_PIN 2
Adafruit_NeoPixel rgb(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
WiFiUDP udp;
// --- Status Color Functions ---
void setStatusRed() { rgb.setPixelColor(0, rgb.Color(255, 0, 0)); rgb.show(); } // Booted
void setStatusYellow() { rgb.setPixelColor(0, rgb.Color(255, 255, 0)); rgb.show(); } // WiFi Connected/Waiting
void setStatusBlue() { rgb.setPixelColor(0, rgb.Color(0, 0, 255)); rgb.show(); } // Raw Packet Received
void setStatusGreen() { rgb.setPixelColor(0, rgb.Color(0, 255, 0)); rgb.show(); } // Playing Song
void setStatusPurple() { rgb.setPixelColor(0, rgb.Color(128, 0, 128)); rgb.show(); } // MP3 Error / Silence
void initGroveMP3() {
delay(500);
Serial1.print("AT+VOL=10\r\n");
delay(100);
checkMP3Response();
// Set the specific repeat mode that worked yesterday
Serial1.print("AT+REPEATMODE=4\r\n");
delay(100);
checkMP3Response();
}
void setup() {
// Initialize USB Serial communication
Serial.begin(115200);
// Initialize status LED immediately so we can track boot stages
rgb.begin();
rgb.setBrightness(70);
setStatusRed(); // Solid Red = Booting up / Not connected
// 1. Turn on UART pins for MP3
Serial1.begin(115200, SERIAL_8N1, GROVE_RX_PIN, GROVE_TX_PIN);
// 2. Let the power settle, then initialize the MP3 player
delay(600);
initGroveMP3();
delay(600); // Extra spacing delay to prevent concurrent Wi-Fi / UART noise spikes
Serial.println("\n--- Initiating Wi-Fi Connection ---");
bool connected = false;
int retryAttempts = 0;
while (!connected) {
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
retryAttempts = 0;
// Try connecting up to 10 times (5 seconds total) before giving up and resetting
while (WiFi.status() != WL_CONNECTED && retryAttempts < 10) {
delay(500);
Serial.print(".");
retryAttempts++;
}
if (WiFi.status() == WL_CONNECTED) {
connected = true;
} else {
// If it failed, flash Red to signal a retry, disconnect, and loop back
Serial.println("\nConnection timed out. Resetting Wi-Fi radio and retrying...");
WiFi.disconnect(true);
delay(1000);
}
}
// Connection successful!
Serial.println("\nWi-Fi Connected Successfully!");
Serial.print("AtomS3U IP Address: ");
Serial.println(WiFi.localIP());
setStatusYellow(); // Turn Yellow = Safely connected and waiting for Wio Packets
udp.begin(UDP_PORT);
}
void loop() {
int packetSize = udp.parsePacket();
if (packetSize) {
setStatusBlue(); // Blue flash = Network packet hit
char packetBuffer[255];
int len = udp.read(packetBuffer, 255);
if (len > 0) packetBuffer[len] = 0;
String command = String(packetBuffer);
Serial.print("Received UDP: ["); Serial.print(command); Serial.println("]");
if (command == "STOP") {
Serial1.print("AT+STOP\r\n"); // Explicit CRLF
Serial.println("Sent to MP3: STOP");
checkMP3Response();
delay(300);
setStatusYellow();
}
else if (command.startsWith("VOLUP")) {
Serial1.print("AT+VOLUP\r\n"); // Explicit CRLF
Serial.println("Sent to MP3: VOLUP");
}
else if (command.startsWith("PLAY:")) {
String trackStr = command.substring(5);
int trackNumber = trackStr.toInt();
playTrack(trackNumber);
}
}
}
void playTrack(uint8_t trackNumber) {
// Matches yesterday's exact working syntax: AT+PLAY=sd0,1
String command = "AT+PLAY=sd0," + String(trackNumber) + "\r\n";
Serial1.print(command);
Serial.print("Sent to MP3: ");
Serial.print(command);
delay(200);
bool success = checkMP3Response();
if (success) {
setStatusGreen();
} else {
setStatusPurple();
}
}
// Reads UART response from the MP3 player
bool checkMP3Response() {
String response = "";
unsigned long startWait = millis();
// Wait up to 100ms for a response
while (millis() - startWait < 100) {
while (Serial1.available()) {
char c = Serial1.read();
response += c;
}
}
if (response.length() > 0) {
Serial.print("MP3 Chip Response: [");
Serial.print(response);
Serial.println("]");
// Most AT firmware returns "OK" on success. If it returns "ERROR", fail.
if (response.indexOf("ERROR") >= 0) {
return false;
}
return true; // Received a valid response (likely "OK")
}
Serial.println("MP3 Chip Response: SILENCE (No UART data returned)");
return false; // Hardware silence
}