From e061428744470c8324c8eff8d642b93ffd0e9c78 Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 21 Nov 2021 21:35:45 -0800 Subject: [PATCH] ESP32CAM | Sending images via UDP? --- .../ESP32CAM_UDP_CLIENT.ino | 145 ++++++++++++++++++ .../ESP32_UDP_SERVER_LovyanGFX.ino | 144 +++++++++++++++++ 2 files changed, 289 insertions(+) create mode 100644 ESP32CAM_Projects/ESP32_CAM_UDP/ESP32CAM_UDP_CLIENT/ESP32CAM_UDP_CLIENT.ino create mode 100644 ESP32CAM_Projects/ESP32_CAM_UDP/ESP32_UDP_SERVER_LovyanGFX/ESP32_UDP_SERVER_LovyanGFX.ino diff --git a/ESP32CAM_Projects/ESP32_CAM_UDP/ESP32CAM_UDP_CLIENT/ESP32CAM_UDP_CLIENT.ino b/ESP32CAM_Projects/ESP32_CAM_UDP/ESP32CAM_UDP_CLIENT/ESP32CAM_UDP_CLIENT.ino new file mode 100644 index 0000000..b6f23f2 --- /dev/null +++ b/ESP32CAM_Projects/ESP32_CAM_UDP/ESP32CAM_UDP_CLIENT/ESP32CAM_UDP_CLIENT.ino @@ -0,0 +1,145 @@ +///////////////////////////////////////////////////////////////// +/* + ESP32CAM | Sending images via UDP? + Video Tutorial: https://youtu.be/1kHxd5FOUEU + Created by Eric N. (ThatProject) +*/ +///////////////////////////////////////////////////////////////// + +#include "esp_camera.h" +#include +#include + +#define CHUNK_LENGTH 1460 + +#define PWDN_GPIO_NUM 32 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 0 +#define SIOD_GPIO_NUM 26 +#define SIOC_GPIO_NUM 27 +#define Y9_GPIO_NUM 35 +#define Y8_GPIO_NUM 34 +#define Y7_GPIO_NUM 39 +#define Y6_GPIO_NUM 36 +#define Y5_GPIO_NUM 21 +#define Y4_GPIO_NUM 19 +#define Y3_GPIO_NUM 18 +#define Y2_GPIO_NUM 5 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 23 +#define PCLK_GPIO_NUM 22 + +const char* ssid = "That-Project"; +const char* password = "California"; +const int udpPort = 8000; +const char* udpAddress = "192.168.4.1"; + +boolean connected = false; +WiFiUDP udp; + +void setup() { + + Serial.begin(115200); + + camera_config_t config; + config.ledc_channel = LEDC_CHANNEL_0; + config.ledc_timer = LEDC_TIMER_0; + config.pin_d0 = Y2_GPIO_NUM; + config.pin_d1 = Y3_GPIO_NUM; + config.pin_d2 = Y4_GPIO_NUM; + config.pin_d3 = Y5_GPIO_NUM; + config.pin_d4 = Y6_GPIO_NUM; + config.pin_d5 = Y7_GPIO_NUM; + config.pin_d6 = Y8_GPIO_NUM; + config.pin_d7 = Y9_GPIO_NUM; + config.pin_xclk = XCLK_GPIO_NUM; + config.pin_pclk = PCLK_GPIO_NUM; + config.pin_vsync = VSYNC_GPIO_NUM; + config.pin_href = HREF_GPIO_NUM; + config.pin_sscb_sda = SIOD_GPIO_NUM; + config.pin_sscb_scl = SIOC_GPIO_NUM; + config.pin_pwdn = PWDN_GPIO_NUM; + config.pin_reset = RESET_GPIO_NUM; + config.xclk_freq_hz = 20000000; + config.pixel_format = PIXFORMAT_JPEG; + config.frame_size = FRAMESIZE_CIF; // 400x296 + config.jpeg_quality = 10; + config.fb_count = 2; + + // camera init + esp_err_t err = esp_camera_init(&config); + if (err != ESP_OK) { + Serial.printf("Camera init failed with error 0x%x", err); + return; + } + + //Connect to the WiFi network + connectToWiFi(ssid, password); +} + +void loop() { + //only send data when connected + if (connected) { + camera_fb_t* fb = NULL; + esp_err_t res = ESP_OK; + fb = esp_camera_fb_get(); + if (!fb) { + Serial.println("Camera capture failed"); + esp_camera_fb_return(fb); + return; + } + + if (fb->format != PIXFORMAT_JPEG) { + Serial.println("PIXFORMAT_JPEG not implemented"); + esp_camera_fb_return(fb); + return; + } + sendPacketData((const char*)fb->buf, fb->len, CHUNK_LENGTH); + esp_camera_fb_return(fb); + } +} + +void connectToWiFi(const char* ssid, const char* pwd) { + Serial.println("Connecting to WiFi network: " + String(ssid)); + + WiFi.disconnect(true); + WiFi.onEvent(WiFiEvent); + WiFi.begin(ssid, pwd); + + Serial.println("Waiting for WIFI connection..."); +} + +void WiFiEvent(WiFiEvent_t event) { + switch (event) { + case SYSTEM_EVENT_STA_GOT_IP: + Serial.print("WiFi connected! IP address: "); + Serial.println(WiFi.localIP()); + udp.begin(WiFi.localIP(), udpPort); + connected = true; + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + Serial.println("WiFi lost connection"); + connected = false; + break; + } +} + +void sendPacketData(const char* buf, uint16_t len, uint16_t chunkLength) { + uint8_t buffer[chunkLength]; + size_t blen = sizeof(buffer); + size_t rest = len % blen; + + for (uint8_t i = 0; i < len / blen; ++i) { + memcpy(buffer, buf + (i * blen), blen); + udp.beginPacket(udpAddress, udpPort); + udp.write(buffer, chunkLength); + udp.endPacket(); + } + + if (rest) { + memcpy(buffer, buf + (len - rest), rest); + udp.beginPacket(udpAddress, udpPort); + udp.write(buffer, rest); + udp.endPacket(); + } +} \ No newline at end of file diff --git a/ESP32CAM_Projects/ESP32_CAM_UDP/ESP32_UDP_SERVER_LovyanGFX/ESP32_UDP_SERVER_LovyanGFX.ino b/ESP32CAM_Projects/ESP32_CAM_UDP/ESP32_UDP_SERVER_LovyanGFX/ESP32_UDP_SERVER_LovyanGFX.ino new file mode 100644 index 0000000..61e488b --- /dev/null +++ b/ESP32CAM_Projects/ESP32_CAM_UDP/ESP32_UDP_SERVER_LovyanGFX/ESP32_UDP_SERVER_LovyanGFX.ino @@ -0,0 +1,144 @@ +///////////////////////////////////////////////////////////////// +/* + ESP32CAM | Sending images via UDP? + Video Tutorial: https://youtu.be/1kHxd5FOUEU + Created by Eric N. (ThatProject) +*/ +///////////////////////////////////////////////////////////////// + +#define LGFX_USE_V1 +#include +#include "WiFi.h" +#include "AsyncUDP.h" +#include +#define CHUNK_LENGTH 1460 + +class LGFX : public lgfx::LGFX_Device { + + lgfx::Panel_ST7796 _panel_instance; + lgfx::Bus_SPI _bus_instance; + lgfx::Light_PWM _light_instance; + +public: + LGFX(void) { + { + auto cfg = _bus_instance.config(); + cfg.spi_host = VSPI_HOST; + cfg.spi_mode = 0; + cfg.freq_write = 40000000; + cfg.freq_read = 20000000; + cfg.spi_3wire = false; + cfg.use_lock = true; + cfg.dma_channel = 1; + cfg.pin_sclk = 18; + cfg.pin_mosi = 19; + cfg.pin_miso = 23; + cfg.pin_dc = 27; + _bus_instance.config(cfg); + _panel_instance.setBus(&_bus_instance); + } + { + auto cfg = _panel_instance.config(); + cfg.pin_cs = 5; + cfg.pin_rst = -1; + cfg.pin_busy = -1; + cfg.memory_width = 320; + cfg.memory_height = 480; + cfg.panel_width = 320; + cfg.panel_height = 480; + cfg.offset_x = 0; + cfg.offset_y = 0; + cfg.offset_rotation = 0; + cfg.dummy_read_pixel = 8; + cfg.dummy_read_bits = 1; + cfg.readable = true; + cfg.invert = false; + cfg.rgb_order = false; + cfg.dlen_16bit = false; + cfg.bus_shared = true; + _panel_instance.config(cfg); + } + { + auto cfg = _light_instance.config(); + cfg.pin_bl = 12; + cfg.invert = false; + cfg.freq = 44100; + cfg.pwm_channel = 7; + _light_instance.config(cfg); + _panel_instance.setLight(&_light_instance); + } + + setPanel(&_panel_instance); + } +}; + +LGFX tft; +std::vector byte_vector; + +const char* ssid = "That-Project"; +const char* password = "California"; +const int udpPort = 8000; + +AsyncUDP udp; + +uint32_t fpsLastTime = 0; +int nbFrames = 0; + +void setup() { + Serial.begin(115200); + + tft.begin(); + tft.setRotation(1); + tft.setBrightness(255); + + tft.fillScreen(TFT_BLACK); + tft.setFont(&fonts::Orbitron_Light_24); + tft.setTextColor(TFT_GREEN); + + WiFi.softAP(ssid, password); + IPAddress myIP = WiFi.softAPIP(); + tft.drawString(myIP.toString(), tft.width() / 2, tft.height() / 2); + + if (udp.listen(udpPort)) { + Serial.print("UDP Listening on IP: "); + Serial.println(WiFi.localIP()); + + udp.onPacket([](AsyncUDPPacket packet) { + Serial.printf("packet Length: %d\n", packet.length()); + + std::vector temp_vector(&packet.data()[0], &packet.data()[packet.length()]); + + if (packet.length() == CHUNK_LENGTH && + packet.data()[0] == 255 && + packet.data()[1] == 216 && + packet.data()[2] == 255) { // FF D8 FF + byte_vector.clear(); + } + + byte_vector.insert(byte_vector.end(), temp_vector.begin(), temp_vector.end()); + + if (packet.length() != CHUNK_LENGTH && + packet.data()[packet.length() - 2] == 255 && + packet.data()[packet.length() - 1] == 217) { // FF D9 + uint8_t* jpgData = byte_vector.data(); + tft.drawJpg(jpgData, byte_vector.size(), 40, 12); + + nbFrames++; + if (millis() - fpsLastTime >= 1000) { + drawingFPSText(nbFrames); + nbFrames = 0; + fpsLastTime += 1000; + } + } + }); + } +} + +void loop() { +} + +void drawingFPSText(int fps) { + tft.fillRect(0, 0, 40, 40, TFT_BLUE); + tft.setCursor(8, 4); + tft.printf("%d", fps); +} \ No newline at end of file