两块 ESP32-S3-WROOM-1-N16R8 图传板(DVP 接口接 OV2640/OV3660/OV5640), 向队伍客户端与裁判终端推 UDP 图传。固件是跑在 ESP-IDF 上的 Rust,用官方 esp32-camera 组件采集;客户端是 Rust + Slint 桌面程序。 三个 crate 各自独立构建: . firmware,交叉编译到 Xtensa protocol/ 线路格式与帧重组,两端共用,无 ESP-IDF 依赖,有单元测试 client/ Slint 桌面客户端 视频走 UDP 而非 TCP:实测传感器产出 22 fps,TCP MJPEG 只送出 1.9 fps, 且只占用链路能力的 1%——链路是空的,帧堵在队头阻塞后面等一个实时画面 等不起的重传计时器。改为独立数据报、不重传、缺片丢整帧后达到 20.8 fps。 发现是双向的:板子每 2 秒广播 Hello,客户端广播 Subscribe,板子据此定向 推流。板子身份由 MAC 派生,重启不变,所以客户端可以把绑定存进配置。 裁判端同时收两块板子(每个发送方一个重组器),队伍端绑定其中一块并只显示 自己那一边的血量。装甲板接口已预留(ArmorSource trait + ARMOR_PORT), 当前无数据源,界面显示占位符。 vendor 了 esp32-camera 2.1.7:组件注册表的版本求解器找不到它,且需要打一处 补丁(见 components/esp32-camera/target/esp32s3/ll_cam.c)。 .gitignore 三条 target/ 都锚定在根目录,因为 protocol/ 与 client/ 各自也是 独立 crate;而 components/esp32-camera/target/ 是上游的按芯片分目录,里面是 源码,必须保留。
166 lines
4.6 KiB
C
166 lines
4.6 KiB
C
// Copyright 2010-2020 Espressif Systems (Shanghai) PTE LTD
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include "sdkconfig.h"
|
|
#include "esp_idf_version.h"
|
|
#if CONFIG_IDF_TARGET_ESP32
|
|
#if ESP_IDF_VERSION_MAJOR >= 4
|
|
#include "esp32/rom/lldesc.h"
|
|
#else
|
|
#include "rom/lldesc.h"
|
|
#endif
|
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
#include "esp32s2/rom/lldesc.h"
|
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
|
#include "esp32s3/rom/lldesc.h"
|
|
#endif
|
|
#include "esp_log.h"
|
|
#include "esp_camera.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/queue.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/semphr.h"
|
|
|
|
#if __has_include("esp_private/periph_ctrl.h")
|
|
# include "esp_private/periph_ctrl.h"
|
|
#endif
|
|
#if __has_include("esp_private/gdma.h")
|
|
# include "esp_private/gdma.h"
|
|
#endif
|
|
|
|
#if CONFIG_LCD_CAM_ISR_IRAM_SAFE
|
|
#define CAMERA_ISR_IRAM_FLAG ESP_INTR_FLAG_IRAM
|
|
#define CAMERA_ISR_IRAM_ATTR IRAM_ATTR
|
|
#else
|
|
#define CAMERA_ISR_IRAM_FLAG 0
|
|
#define CAMERA_ISR_IRAM_ATTR
|
|
#endif
|
|
|
|
#define CAMERA_DBG_PIN_ENABLE 0
|
|
#if CAMERA_DBG_PIN_ENABLE
|
|
#if CONFIG_IDF_TARGET_ESP32
|
|
#define DBG_PIN_NUM 26
|
|
#else
|
|
#define DBG_PIN_NUM 7
|
|
#endif
|
|
#include "hal/gpio_ll.h"
|
|
#define DBG_PIN_SET(v) gpio_ll_set_level(&GPIO, DBG_PIN_NUM, v)
|
|
#else
|
|
#define DBG_PIN_SET(v)
|
|
#endif
|
|
|
|
#define CAM_CHECK(a, str, ret) if (!(a)) { \
|
|
ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
|
|
return (ret); \
|
|
}
|
|
|
|
#define CAM_CHECK_GOTO(a, str, lab) if (!(a)) { \
|
|
ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
|
|
goto lab; \
|
|
}
|
|
|
|
#define LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE (4092)
|
|
|
|
typedef enum {
|
|
CAM_IN_SUC_EOF_EVENT = 0,
|
|
CAM_VSYNC_EVENT
|
|
} cam_event_t;
|
|
|
|
typedef enum {
|
|
CAM_STATE_IDLE = 0,
|
|
CAM_STATE_READ_BUF = 1,
|
|
} cam_state_t;
|
|
|
|
typedef struct {
|
|
camera_fb_t fb;
|
|
uint8_t en;
|
|
//for RGB/YUV modes
|
|
lldesc_t *dma;
|
|
size_t fb_offset;
|
|
} cam_frame_t;
|
|
|
|
typedef struct {
|
|
uint32_t dma_bytes_per_item;
|
|
uint32_t dma_buffer_size;
|
|
uint32_t dma_half_buffer_size;
|
|
uint32_t dma_half_buffer_cnt;
|
|
uint32_t dma_node_buffer_size;
|
|
uint32_t dma_node_cnt;
|
|
uint32_t frame_copy_cnt;
|
|
|
|
//for JPEG mode
|
|
lldesc_t *dma;
|
|
uint8_t *dma_buffer;
|
|
|
|
cam_frame_t *frames;
|
|
|
|
QueueHandle_t event_queue;
|
|
QueueHandle_t frame_buffer_queue;
|
|
TaskHandle_t task_handle;
|
|
intr_handle_t cam_intr_handle;
|
|
|
|
uint8_t dma_num;//ESP32-S3
|
|
intr_handle_t dma_intr_handle;//ESP32-S3
|
|
#if SOC_GDMA_SUPPORTED
|
|
gdma_channel_handle_t dma_channel_handle;//ESP32-S3
|
|
#endif
|
|
|
|
uint8_t jpeg_mode;
|
|
uint8_t vsync_pin;
|
|
uint8_t vsync_invert;
|
|
uint32_t frame_cnt;
|
|
uint32_t recv_size;
|
|
bool swap_data;
|
|
bool psram_mode;
|
|
|
|
//for RGB/YUV modes
|
|
uint16_t width;
|
|
uint16_t height;
|
|
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
|
float in_bytes_per_pixel;
|
|
float fb_bytes_per_pixel;
|
|
camera_conv_mode_t conv_mode;
|
|
#else
|
|
uint8_t in_bytes_per_pixel;
|
|
uint8_t fb_bytes_per_pixel;
|
|
#endif
|
|
uint32_t fb_size;
|
|
|
|
cam_state_t state;
|
|
} cam_obj_t;
|
|
|
|
|
|
bool ll_cam_stop(cam_obj_t *cam);
|
|
bool ll_cam_start(cam_obj_t *cam, int frame_pos);
|
|
esp_err_t ll_cam_config(cam_obj_t *cam, const camera_config_t *config);
|
|
esp_err_t ll_cam_deinit(cam_obj_t *cam);
|
|
void ll_cam_vsync_intr_enable(cam_obj_t *cam, bool en);
|
|
esp_err_t ll_cam_set_pin(cam_obj_t *cam, const camera_config_t *config);
|
|
esp_err_t ll_cam_init_isr(cam_obj_t *cam);
|
|
void ll_cam_do_vsync(cam_obj_t *cam);
|
|
uint8_t ll_cam_get_dma_align(cam_obj_t *cam);
|
|
bool ll_cam_dma_sizes(cam_obj_t *cam);
|
|
size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len);
|
|
esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid);
|
|
#if CONFIG_IDF_TARGET_ESP32S3
|
|
void ll_cam_dma_print_state(cam_obj_t *cam);
|
|
void ll_cam_dma_reset(cam_obj_t *cam);
|
|
#endif
|
|
|
|
// implemented in cam_hal
|
|
void ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType_t * HPTaskAwoken);
|