diff --git a/platformio.ini b/platformio.ini index 25165b1..135a448 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [env:nodemcu-32s2] -platform = espressif32 +platform = espressif32@6.3.2 board = nodemcu-32s2 board_build.mcu = esp32 framework = arduino @@ -18,3 +18,9 @@ lib_deps = mrfaptastic/ESP32 HUB75 LED MATRIX PANEL DMA Display@^3.0.12 https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git adafruit/Adafruit GFX Library@^1.11.10 + fastled/FastLED@^3.7.1 + bblanchon/ArduinoJson@^7.1.0 +; build_flags = -DCORE_DEBUG_LEVEL=5 +; -DBOARD_HAS_PSRAM +; -mfix-esp32-psram-cache-issue + diff --git a/src/main.cpp b/src/main.cpp index 58d54d0..b6b21b3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,10 +4,26 @@ #include #include #include -#include +#include +#include +#include + const char* ssid = "VSMI-Guest"; const char* password = "h3ll0vsmi"; +// const char* ssid = "VIETTEL_txXZQ27z"; +// const char* password = "CCF5A3K9"; + +// Set your Static IP address +IPAddress local_IP(192, 168, 1, 243); +IPAddress gateway(192, 168, 1, 1); +IPAddress subnet(255, 255, 255, 0); + +// IPAddress local_IP(192, 168, 2, 243); +// IPAddress gateway(192, 168, 2, 1); +// IPAddress subnet(255, 255, 255, 0); +// IPAddress primaryDNS(8, 8, 8, 8); //optional +// IPAddress secondaryDNS(8, 8, 4, 4); //optional #define R1_PIN 25 #define G1_PIN 26 #define B1_PIN 27 @@ -27,28 +43,33 @@ const char* password = "h3ll0vsmi"; // Configure for your panel(s) as appropriate! #define PANEL_WIDTH 64 #define PANEL_HEIGHT 64 -#define PANELS_NUMBER 1 +#define PANELS_NUMBER 4 #define PANE_WIDTH PANEL_WIDTH * PANELS_NUMBER #define PANE_HEIGHT PANEL_HEIGHT -#define MAX_UDP_SIZE 1460 +#define MAX_UDP_SIZE 1450 +CRGB currentColor; +CRGBPalette16 palettes[] = {HeatColors_p, LavaColors_p, RainbowColors_p, RainbowStripeColors_p, CloudColors_p}; +CRGBPalette16 currentPalette = palettes[0]; +CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) { + return ColorFromPalette(currentPalette, index, brightness, blendType); +} +uint16_t time_counter = 0, cycles = 0, fps = 0; +unsigned long fps_timer; WiFiUDP udp; unsigned int localUdpPort = 5000; const int bufferSize = PANE_WIDTH*PANE_HEIGHT*2; // Adjust based on your data size char incomingPacket[bufferSize]; // Buffer for incoming packets -uint16_t pixelData[PANE_WIDTH*PANE_HEIGHT]; // Assuming 2 bytes per RGB565 pixel -// Cấu trúc Pixel -struct Pixel { - uint16_t color; -}; -#define PIXEL_ENTRY_SIZE 5 +//char *incomingPacket_psram = (char *) ps_malloc(bufferSize*sizeof(char)); + #define NUM_PIXELS PANE_WIDTH*PANE_HEIGHT + // Biến trạng thái int dataOffset = 0; bool dataComplete = false; -uint16_t arr[PANE_HEIGHT*PANE_WIDTH] PROGMEM; +uint16_t arr[PANE_HEIGHT*PANE_WIDTH]; MatrixPanel_I2S_DMA *dma_display = nullptr; //Another way of creating config structure //Custom pin mapping for all pins @@ -61,84 +82,235 @@ HUB75_I2S_CFG mxconfig( HUB75_I2S_CFG::FM6126A // driver chip ); -Pixel pixels[PANE_WIDTH * PANE_HEIGHT]; +//Pixel pixels[NUM_PIXELS]; +uint8_t tempBuffer[NUM_PIXELS * 2]; -void rgb565_to_rgb888(uint16_t color, uint8_t &r, uint8_t &g, uint8_t &b) { - r = (color >> 8) & 0xF8; - g = (color >> 3) & 0xFC; - b = (color << 3) & 0xF8; -} +//Use PSRAM +//uint8_t *tempBuffer = (uint8_t *)ps_malloc(sizeof(uint8_t *)); -uint8_t tempBuffer[PANE_WIDTH * PANE_HEIGHT * 2]; int receivedBytes = 0; // Số byte đã nhận bool newFrame = true; +uint32_t rgb565_to_rgb888(uint16_t rgb565) { + // Tách các kênh màu từ giá trị RGB565 + uint8_t r = (rgb565 >> 11) & 0x1F; // 5 bit cho đỏ + uint8_t g = (rgb565 >> 5) & 0x3F; // 6 bit cho xanh lục + uint8_t b = rgb565 & 0x1F; // 5 bit cho xanh dương -void resetPixels() { - memset(pixels, 0, sizeof(pixels)); - memset(tempBuffer, 0, sizeof(tempBuffer)); - receivedBytes = 0; - dataComplete = false; + // Chuyển đổi các kênh màu từ 5/6 bit sang 8 bit + r = (r * 255 + 15) / 31; // Chuyển đổi từ 5 bit sang 8 bit + g = (g * 255 + 31) / 63; // Chuyển đổi từ 6 bit sang 8 bit + b = (b * 255 + 15) / 31; // Chuyển đổi từ 5 bit sang 8 bit + + // Ghép các giá trị RGB888 thành một giá trị 32 bit + return (r << 16) | (g << 8) | b; } - void receivePixels(char* packet, int length) { - if (newFrame) { - newFrame = false; - //dma_display->clearScreen(); - } - +// if (newFrame) { +// newFrame = false; +// } if (receivedBytes + length > sizeof(tempBuffer)) { length = sizeof(tempBuffer) - receivedBytes; // Giới hạn độ dài } memcpy(tempBuffer + receivedBytes, packet, length); receivedBytes += length; // Kiểm tra xem toàn bộ dữ liệu có được nhận đầy đủ chưa - if (receivedBytes == PANE_WIDTH * PANE_HEIGHT * 2) { + if (receivedBytes >= NUM_PIXELS * 2) { //dma_display->clearScreen(); - dataComplete = true; + for (int y = 0; y < PANE_HEIGHT; y++) { + for (int x = 0; x < PANE_WIDTH; x++) { + if(PANE_WIDTH<=128) + { + int index = (y * PANE_WIDTH + x); + uint16_t color = (tempBuffer[index*2] << 8) | tempBuffer[index*2 + 1]; + uint32_t rgb888 = rgb565_to_rgb888(color); + uint8_t r = (rgb888 >> 16) & 0xFF; // Kênh đỏ + uint8_t g = (rgb888 >> 8) & 0xFF; // Kênh xanh lục + uint8_t b = rgb888 & 0xFF; // Kênh xanh dương + //pixels[index].color = color; + //dma_display->drawPixel(x, y, color); + if(y<=31)dma_display->drawPixelRGB888(x,y,r,g,b); + else dma_display->drawPixelRGB888(x,y,r,b,g); + } + else + { + if(x<=128){ + int index = (y * PANE_WIDTH + x); + uint16_t color = (tempBuffer[index*2] << 8) | tempBuffer[index*2 + 1]; + uint32_t rgb888 = rgb565_to_rgb888(color); + uint8_t r = (rgb888 >> 16) & 0xFF; // Kênh đỏ + uint8_t g = (rgb888 >> 8) & 0xFF; // Kênh xanh lục + uint8_t b = rgb888 & 0xFF; // Kênh xanh dương + //pixels[index].color = color; + //dma_display->drawPixel(x, y, color); + if(y<=31)dma_display->drawPixelRGB888(x,y,r,g,b); + else dma_display->drawPixelRGB888(x,y,r,b,g); + } + else + { + int y1 = y + 1; + int x1 = x-128; + int index = (y * PANE_WIDTH + x); + uint16_t color = (tempBuffer[index*2] << 8) | tempBuffer[index*2 + 1]; + uint32_t rgb888 = rgb565_to_rgb888(color); + uint8_t r = (rgb888 >> 16) & 0xFF; // Kênh đỏ + uint8_t g = (rgb888 >> 8) & 0xFF; // Kênh xanh lục + uint8_t b = rgb888 & 0xFF; // Kênh xanh dương + //pixels[index].color = color; + //dma_display->drawPixel(x, y, color); + if(y1<=31)dma_display->drawPixelRGB888(x1,y1,r,g,b); + else dma_display->drawPixelRGB888(x1,y1,r,b,g); + } + } + + } + } + // Đặt lại bộ nhớ tạm và biến nhận bytes + //memset(tempBuffer, 0, sizeof(tempBuffer)); + receivedBytes = 0; + newFrame = true; + } +} +/* + +void receivePixels(char* packet, int length) { + if (newFrame) { + newFrame = false; + // Xóa màn hình nếu cần + // dma_display->clearScreen(); + } + int BUFFER_SIZE = PANE_WIDTH*PANE_HEIGHT*2; + int remainingSpace = BUFFER_SIZE - receivedBytes; + int bytesToCopy = (length > remainingSpace) ? remainingSpace : length; + + // Sao chép dữ liệu vào buffer tạm + memcpy(tempBuffer + receivedBytes, packet, bytesToCopy); + receivedBytes += bytesToCopy; + + // Kiểm tra xem toàn bộ dữ liệu có được nhận đầy đủ chưa + if (receivedBytes >= BUFFER_SIZE) { + dataComplete = true; + // Xử lý dữ liệu khi đã nhận đầy đủ int index = 0; - for (int i = 0; i < receivedBytes; i += 2) { + for (int i = 0; i < BUFFER_SIZE; i += 2) { if (index < PANE_WIDTH * PANE_HEIGHT) { uint16_t color = (tempBuffer[i] << 8) | tempBuffer[i + 1]; pixels[index].color = color; index++; } } - - - - // Đặt lại bộ nhớ tạm và biến nhận bytes - memset(tempBuffer, 0, sizeof(tempBuffer)); + + // Xóa bộ nhớ tạm và đặt lại biến nhận bytes receivedBytes = 0; + memset(tempBuffer, 0, BUFFER_SIZE); newFrame = true; } } - - -void displayPixels() { - for (int y = 0; y < PANE_HEIGHT; y++) { - for (int x = 0; x < PANE_WIDTH; x++) { - int index = (y * PANE_WIDTH + x); - uint16_t color = pixels[index].color; - if (color != 0) { - dma_display->drawPixel(x, y, color); - } - else{ - dma_display->drawPixel(x, y, 0); - } - pixels[index].color = 0; - } - } -} -// void resetPixels() { -// for (int i = 0; i < PANE_WIDTH*PANE_HEIGHT; i++) { -// pixels[i].color = 0; // Đặt màu về 0 hoặc màu nền khác +*/ +// void displayPixels() { +// for (int y = 0; y < PANE_HEIGHT; y++) { +// for (int x = 0; x < PANE_WIDTH; x++) { +// int index = (y * PANE_WIDTH + x); +// uint16_t color = pixels[index].color; +// if (color != 0) { +// dma_display->drawPixel(x, y, color); +// } +// else{ +// dma_display->drawPixel(x, y, 0); +// } +// pixels[index].color = 0; +// } // } // } +void plasma_palette() +{ + // for (int x = 0; x < PANE_WIDTH; x++) { + // for (int y = 0; y < PANE_HEIGHT; y++) { + // int16_t v = 128; + // uint8_t wibble = sin8(time_counter); + // v += sin16(x * wibble * 3 + time_counter); + // v += cos16(y * (128 - wibble) + time_counter); + // v += sin16(y * x * cos8(-time_counter) / 8); + + // currentColor = ColorFromPalette(currentPalette, (v >> 8)); //, brightness, currentBlendType); + // if(y<=31)dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b); + // else dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.b, currentColor.g); + // } + // } + + for (int x = 0; x < PANE_WIDTH; x++) { + if(x<=128){ + for (int y = 0; y < PANE_HEIGHT; y++) { + int16_t v = 128; + uint8_t wibble = sin8(time_counter); + v += sin16(x * wibble * 3 + time_counter); + v += cos16(y * (128 - wibble) + time_counter); + v += sin16(y * x * cos8(-time_counter) / 8); + + currentColor = ColorFromPalette(currentPalette, (v >> 8)); //, brightness, currentBlendType); + if(y<=31)dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b); + else dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.b, currentColor.g); + } + } + else if (x>128 && x<=256){ + + for (int y = 0; y < PANE_HEIGHT; y++) { + int16_t v = 128; + uint8_t wibble = sin8(time_counter); + int x1 = x-128; + int y1 = y+64; + v += sin16(x1 * wibble * 3 + time_counter); + v += cos16(y1 * (128 - wibble) + time_counter); + v += sin16(y1 * x1 * cos8(-time_counter) / 8); + + currentColor = ColorFromPalette(currentPalette, (v >> 8)); //, brightness, currentBlendType); + if(y<=31)dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b); + else dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.b, currentColor.g); + } + } + else{ + for (int y = 0; y < PANE_HEIGHT; y++) { + int16_t v = 128; + uint8_t wibble = sin8(time_counter); + int x1 = x-256; + int y1 = y+64; + v += sin16(x1 * wibble * 3 + time_counter); + v += cos16(y1 * (128 - wibble) + time_counter); + v += sin16(y1 * x1 * cos8(-time_counter) / 8); + + currentColor = ColorFromPalette(currentPalette, (v >> 8)); //, brightness, currentBlendType); + if(y<=31)dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b); + else dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.b, currentColor.g); + } + } + } + + ++time_counter; + ++cycles; + ++fps; + + if (cycles >= 1024) { + time_counter = 0; + cycles = 0; + currentPalette = palettes[random(0,sizeof(palettes)/sizeof(palettes[0]))]; + } + + // print FPS rate every 5 seconds + // Note: this is NOT a matrix refresh rate, it's the number of data frames being drawn to the DMA buffer per second + if (fps_timer + 5000 < millis()){ + //Serial.printf_P(PSTR("Effect fps: %d\n"), fps/5); + fps_timer = millis(); + fps = 0; + } +} void setup() { // put your setup code here, to run once: - Serial.begin(115200); + Serial.begin(115200); + + if (!WiFi.config(local_IP, gateway, subnet)) { + Serial.println("STA Failed to configure"); + } WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { @@ -151,33 +323,29 @@ void setup() { udp.begin(localUdpPort); dma_display = new MatrixPanel_I2S_DMA(mxconfig); dma_display->begin(); // setup the LED matrix - dma_display->setBrightness8(15); //0-255 + dma_display->setBrightness8(50); //0-255 dma_display->clearScreen(); + currentPalette = RainbowColors_p; } - void loop() { - int packetSize = udp.parsePacket(); + int packetSize = udp.parsePacket(); if (packetSize) { int len = udp.read(incomingPacket, MAX_UDP_SIZE); if (len > 0) { - //Serial.print("Received packet of size "); - //Serial.println(len); - // appendData(incomingPacket, len); receivePixels(incomingPacket, len); - // Nếu dữ liệu đầy đủ, hiển thị - if (dataComplete) { - displayPixels(); - //Serial.print("complete"); - dataComplete = false; // Reset trạng thái - - // resetPixels(); - //memset(pixelData, 0, sizeof(pixelData)); - } } - } else { + + // // Use PSRAM + // int len = udp.read(incomingPacket_psram, MAX_UDP_SIZE); + // if (len > 0) { + // receivePixels(incomingPacket_psram, len); + // } + } + else { + //plasma_palette(); //Serial.println("No packet received"); } + //plasma_palette(); - // delay(200); }