#include #define TAG "CAM" #include "esp_camera.h" #define PWDN_GPIO_NUM -1 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 15 #define SIOD_GPIO_NUM 4 #define SIOC_GPIO_NUM 5 #define Y2_GPIO_NUM 11 #define Y3_GPIO_NUM 9 #define Y4_GPIO_NUM 8 #define Y5_GPIO_NUM 10 #define Y6_GPIO_NUM 12 #define Y7_GPIO_NUM 18 #define Y8_GPIO_NUM 17 #define Y9_GPIO_NUM 16 #define VSYNC_GPIO_NUM 6 #define HREF_GPIO_NUM 7 #define PCLK_GPIO_NUM 13 #define WIFI_IF WIFI_IF_AP #define MAX_PAYLOAD_SIZE 1400 #include "esp_event.h" #include "esp_system.h" #include "esp_event.h" #include "esp_timer.h" #include "esp_wifi.h" #include "esp_log.h" #include "esp_mac.h" #include "nvs_flash.h" #include "string.h" #include "lipton/cci.h" #include "lipton/vospi.h" #include "lipton/lepton_system.h" #include "lipton/lepton_utilities.h" // Number of consecutive VoSPI resynchronization attempts before attempting to reset #define LEP_SYNC_FAIL_FAULT_LIMIT 10 // Reset fail delay before attempting a re-init (seconds) #define LEP_RESET_FAIL_RETRY_SECS 5 // // Code start // int vsync_count = 0; int sync_fail_count = 0; int reset_fail_count = 0; int64_t vsyncDetectedUsec; esp_err_t tx_with_retry(wifi_interface_t iface, const void *buffer, int len, bool en_sys_seq) { for (int i = 0; i < 160; i++) { esp_err_t err = esp_wifi_80211_tx(iface, buffer, len, en_sys_seq); if (err == ESP_OK) return ESP_OK; if (err != ESP_ERR_NO_MEM) return err; // No delay, retry immediately } return ESP_ERR_NO_MEM; } static camera_config_t camera_config = { .pin_pwdn = PWDN_GPIO_NUM, .pin_reset = RESET_GPIO_NUM, .pin_xclk = XCLK_GPIO_NUM, // .pin_sccb_sda = SIOD_GPIO_NUM, // .pin_sccb_scl = SIOC_GPIO_NUM, .pin_sccb_sda = -1, .pin_sccb_scl = -1, .sccb_i2c_port = I2C_MASTER_NUM, .pin_d7 = Y9_GPIO_NUM, .pin_d6 = Y8_GPIO_NUM, .pin_d5 = Y7_GPIO_NUM, .pin_d4 = Y6_GPIO_NUM, .pin_d3 = Y5_GPIO_NUM, .pin_d2 = Y4_GPIO_NUM, .pin_d1 = Y3_GPIO_NUM, .pin_d0 = Y2_GPIO_NUM, .pin_vsync = VSYNC_GPIO_NUM, .pin_href = HREF_GPIO_NUM, .pin_pclk = PCLK_GPIO_NUM, .xclk_freq_hz = 20000000, // EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, .pixel_format = PIXFORMAT_JPEG, // YUV422,GRAYSCALE,RGB565,JPEG .frame_size = FRAMESIZE_UXGA, // QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates.+ //.frame_size = FRAMESIZE_128X128, // QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates. .jpeg_quality = 12, // 0-63, for OV series camera sensors, lower number means higher quality .fb_count = 1, // When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode. //.fb_location = CAMERA_FB_IN_PSRAM, .fb_location = CAMERA_FB_IN_PSRAM, .grab_mode = CAMERA_GRAB_LATEST // CAMERA_GRAB_LATEST. Sets when buffers should be filled }; esp_err_t esp_wifi_80211_tx(wifi_interface_t ifx, const void *buffer, int len, bool en_sys_seq); uint16_t calculate_checksum(uint8_t *data, size_t len) { uint16_t checksum = 0; for (size_t i = 0; i < len; i++) { checksum ^= data[i]; // Simple XOR-based checksum } return checksum; } void send_data_frame(uint8_t type, uint8_t *data, size_t len) { uint8_t mac_addr[6]; if (esp_wifi_get_mac(WIFI_IF_AP, mac_addr) != ESP_OK) { ESP_LOGE(TAG, "Failed to get MAC address"); return; } uint8_t header[] = { 0x08, 0x02, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00}; memcpy(&header[10], mac_addr, 6); memcpy(&header[16], mac_addr, 6); size_t max_chunk_size = MAX_PAYLOAD_SIZE - (11 + 2); size_t total_chunks = (len + max_chunk_size - 1) / max_chunk_size; for (uint16_t seq = 0; seq < total_chunks; seq++) { size_t offset = seq * max_chunk_size; size_t chunk_size = (len - offset > max_chunk_size) ? max_chunk_size : (len - offset); uint8_t *raw_frame = malloc(11 + chunk_size + 2); uint8_t *full_packet = malloc(sizeof(header) + 11 + chunk_size + 2); if (!raw_frame || !full_packet) { ESP_LOGE(TAG, "Memory allocation failed!"); free(raw_frame); free(full_packet); return; } raw_frame[0] = type; raw_frame[1] = seq >> 8; raw_frame[2] = seq & 0xFF; raw_frame[3] = total_chunks >> 8; raw_frame[4] = total_chunks & 0xFF; raw_frame[5] = 'P'; raw_frame[6] = 'l'; raw_frame[7] = 'e'; raw_frame[8] = 'c'; raw_frame[9] = 'y'; raw_frame[10] = 'C'; memcpy(raw_frame + 11, data + offset, chunk_size); uint16_t checksum = calculate_checksum(raw_frame, 11 + chunk_size); raw_frame[11 + chunk_size] = checksum >> 8; raw_frame[12 + chunk_size] = checksum & 0xFF; memcpy(full_packet, header, sizeof(header)); memcpy(full_packet + sizeof(header), raw_frame, 11 + chunk_size + 2); esp_err_t ret = tx_with_retry(WIFI_IF, full_packet, sizeof(header) + 11 + chunk_size + 2, true); if (ret == ESP_OK) { ESP_LOGI(TAG, "Sent chunk %d/%d, size: %d bytes", seq + 1, total_chunks, chunk_size); } else { ESP_LOGE(TAG, "Failed to send chunk %d, %s", seq, esp_err_to_name(ret)); } free(raw_frame); free(full_packet); vTaskDelay(50 / portTICK_PERIOD_MS); } } esp_err_t camera_init() { // initialize the camera esp_err_t err = esp_camera_init(&camera_config); if (err != ESP_OK) { ESP_LOGE(TAG, "Camera Init Failed"); return err; } return ESP_OK; } typedef struct { bool isVisible; size_t len; size_t width; size_t height; pixformat_t format; struct timeval timestamp; } PreData; esp_err_t camera_capture() { ESP_LOGI(TAG, "Pregrab"); camera_fb_t *fb = esp_camera_fb_get(); ESP_LOGI(TAG, "Postgrab"); if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); return ESP_FAIL; } const size_t headerSize = sizeof(PreData); const size_t totalSize = fb->len + headerSize; uint8_t *dataOut = malloc(totalSize); if (!dataOut) { ESP_LOGE(TAG, "Failed to allocate memory"); esp_camera_fb_return(fb); return ESP_ERR_NO_MEM; } // Fill PreData at the start PreData *pre = (PreData *)dataOut; pre->isVisible = true; pre->len = fb->len; pre->width = fb->width; pre->height = fb->height; pre->format = fb->format; pre->timestamp = fb->timestamp; // Copy image data after PreData memcpy(dataOut + headerSize, fb->buf, fb->len); // Now chunk and send send_data_frame(0x10, dataOut, totalSize); free(dataOut); esp_camera_fb_return(fb); return ESP_OK; } void app_main(void) { nvs_flash_init(); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_create_default_wifi_sta(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); wifi_config_t ap_config = { .ap = { .ssid = "ESP32-Test", .channel = 10, .authmode = WIFI_AUTH_OPEN, .max_connection = 1, .ssid_hidden = 1, .beacon_interval = 60000}}; ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_config)); ESP_ERROR_CHECK(esp_wifi_start()); ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); esp_log_level_set("wifi", ESP_LOG_DEBUG); uint8_t mac_addr[6]; esp_read_mac(mac_addr, ESP_MAC_WIFI_SOFTAP); ESP_LOGI(TAG, "ESP32 MAC: %02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); camera_init(); vTaskDelay(pdMS_TO_TICKS(300)); // Let the camera wake up fully while (1) { gpio_config_t usb_phy_conf = { .pin_bit_mask = (1ULL << 19) | (1ULL << 20), .mode = GPIO_MODE_OUTPUT, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE, }; gpio_config(&usb_phy_conf); printf("[MAIN] Start task\n"); LEP_CONFIG.agc_set_enabled = true; LEP_CONFIG.emissivity = 100; LEP_CONFIG.gain_mode = LEP_GAIN_AUTO; // initialize spi, i2c and gpio for lepton if (!lepton_io_init()) { printf("[MAIN] Error: I/O init failed"); while (1) { vTaskDelay(pdMS_TO_TICKS(100)); } } // allocate lepton buffers if (!lepton_buffer_init()) { printf("[MAIN] Error: Memory init failed"); while (1) { vTaskDelay(pdMS_TO_TICKS(100)); } } // wait for lepton to initialize vTaskDelay(pdMS_TO_TICKS(1000));; // Attempt to initialize the VoSPI interface if (vospi_init() != ESP_OK) { printf("[MAIN] Error: Lepton VoSPI initialization failed\n"); while (1) { vTaskDelay(pdMS_TO_TICKS(100)); } } // initialize lepton if (!lepton_init()) { printf("[MAIN] Error: Lepton CCI initialization failed\n"); while (1) { vTaskDelay(pdMS_TO_TICKS(100)); } } // disable data from lepton gpio_set_level(LEP_CSN_PIN, 1); printf("LEPTON INIT DONE"); int64_t start = esp_timer_get_time(); camera_capture(); int64_t end = esp_timer_get_time(); int64_t duration = end - start; printf("%lf FPS, %lf SPF\n", 1 / (duration / 1000000.0), duration / 1000000.0); } }