/* Union-free wrapper around the esp32-camera API. * * `camera_config_t` in esp_camera.h uses anonymous unions for the deprecated * SCCB pin names, which bindgen renders as unsafe union fields that are * awkward to build from Rust. This wrapper takes a plain struct and fills in * the unions on the C side, so the generated bindings stay trivial to use. * * The enum-valued config fields are declared as local enums whose values equal * the esp32-camera ones (`pixformat_t`, `framesize_t`, `camera_fb_location_t`, * `camera_grab_mode_t`). That keeps the numbers defined in exactly one place - * the esp32-camera headers - while still giving Rust named constants to use * instead of bare magic numbers. */ #pragma once #include #include #include #include "esp_camera.h" #include "esp_err.h" /* Defined by esp32-camera's cam_hal.c but declared only in its private header, * which components outside esp32-camera cannot include. Redeclared here so the * wrapper can set the VSYNC polarity before esp_camera_init() and read back the * clock the driver used. */ void cam_set_vsync_invert(bool invert); bool cam_get_vsync_invert(void); void cam_set_xclk_hz(int hz); int cam_get_xclk_hz(void); #ifdef __cplusplus extern "C" { #endif typedef enum { CAM_WRAPPER_PIXFORMAT_JPEG = PIXFORMAT_JPEG, CAM_WRAPPER_PIXFORMAT_RGB565 = PIXFORMAT_RGB565, } cam_wrapper_pixel_format_t; typedef enum { CAM_WRAPPER_FRAMESIZE_QQVGA = FRAMESIZE_QQVGA, CAM_WRAPPER_FRAMESIZE_QVGA = FRAMESIZE_QVGA, CAM_WRAPPER_FRAMESIZE_CIF = FRAMESIZE_CIF, CAM_WRAPPER_FRAMESIZE_HVGA = FRAMESIZE_HVGA, CAM_WRAPPER_FRAMESIZE_VGA = FRAMESIZE_VGA, CAM_WRAPPER_FRAMESIZE_SVGA = FRAMESIZE_SVGA, CAM_WRAPPER_FRAMESIZE_XGA = FRAMESIZE_XGA, CAM_WRAPPER_FRAMESIZE_SXGA = FRAMESIZE_SXGA, CAM_WRAPPER_FRAMESIZE_UXGA = FRAMESIZE_UXGA, } cam_wrapper_framesize_t; typedef enum { CAM_WRAPPER_FB_IN_PSRAM = CAMERA_FB_IN_PSRAM, CAM_WRAPPER_FB_IN_DRAM = CAMERA_FB_IN_DRAM, } cam_wrapper_fb_location_t; typedef enum { CAM_WRAPPER_GRAB_WHEN_EMPTY = CAMERA_GRAB_WHEN_EMPTY, CAM_WRAPPER_GRAB_LATEST = CAMERA_GRAB_LATEST, } cam_wrapper_grab_mode_t; /* Pin map of the camera connector. Use -1 for signals that are not wired. */ typedef struct { int pin_pwdn; int pin_reset; int pin_xclk; int pin_sccb_sda; int pin_sccb_scl; int pin_d[8]; /* index 0 -> pin_d0 .. index 7 -> pin_d7 */ int pin_vsync; int pin_href; int pin_pclk; int xclk_freq_hz; int ledc_timer; int ledc_channel; cam_wrapper_pixel_format_t pixel_format; cam_wrapper_framesize_t frame_size; int jpeg_quality; size_t fb_count; cam_wrapper_fb_location_t fb_location; cam_wrapper_grab_mode_t grab_mode; int sccb_i2c_port; /* VSYNC polarity. 0 = active-high, 1 = active-low (esp32-camera's default, * correct for most DVP sensors). Getting this wrong does not fail: the * driver latches frames on the wrong edge and the result is a valid but * very low frame rate, so it is worth being able to flip it. */ int vsync_invert; } cam_wrapper_config_t; /* Sensor hint. esp32-camera probes the sensor over SCCB and binds a driver by * its PID/ID, so AUTO is normally all that is needed; the others exist only to * disambiguate when the probe itself is unreliable. */ typedef enum { CAM_WRAPPER_SENSOR_AUTO = 0, CAM_WRAPPER_SENSOR_OV2640 = 1, CAM_WRAPPER_SENSOR_OV3660 = 2, CAM_WRAPPER_SENSOR_OV5640 = 3, } cam_wrapper_sensor_t; /* A single captured frame. `data` points into memory owned by the driver and * stays valid only until cam_wrapper_fb_release() is called on this struct. * The struct is caller-owned so it can live on the handler's stack. */ typedef struct { uint8_t *data; size_t len; size_t width; size_t height; int format; void *handle; /* internal driver frame; do not touch */ } cam_wrapper_fb_t; esp_err_t cam_wrapper_init(const cam_wrapper_config_t *config, cam_wrapper_sensor_t sensor); /* Acquire one frame into `out`. Returns ESP_OK on success, ESP_FAIL if the * driver could not hand out a frame (e.g. timeout or buffer starvation). */ esp_err_t cam_wrapper_fb_get(cam_wrapper_fb_t *out, cam_wrapper_sensor_t sensor); void cam_wrapper_fb_release(cam_wrapper_fb_t *fb); esp_err_t cam_wrapper_reconfigure(const cam_wrapper_config_t *config); esp_err_t cam_wrapper_deinit(void); /* Name of the sensor the driver detected, or "unknown". Never NULL. */ const char *cam_wrapper_sensor_name(void); #ifdef __cplusplus } #endif