Skip to content

Latest commit

 

History

History
419 lines (323 loc) · 15.3 KB

File metadata and controls

419 lines (323 loc) · 15.3 KB

API reference

The public API is in namespace NiusCam. Most sketches add using namespace NiusCam; once, then use ordinary objects and methods:

Camera camera;
Config config;
config.useBalanced();
Result result = camera.begin(config);

Header selection

Header Public functionality
<NiusCam.h> Camera, frame ownership, board/config types, sensor controls, diagnostics, errors
<NiusCamAutofocus.h> Optional OV5640 autofocus controller, mode, and status
<NiusCamOv2640.h> Optional OV2640 automatic low-light frame-rate controls
<NiusCamStorage.h> microSD mounting, information, atomic JPEG saving, sequential files, bounded recording
<NiusCamHttp.h> HTTP index, snapshot, and MJPEG server
<NiusCamUdp.h> Chunked JPEG UDP sender and protocol types

Only include optional modules that the sketch uses.

Result and errors

Fallible configuration, lifecycle, control, storage, and network methods return Result.

Result result = camera.begin();
if (!result) {
  Serial.print("Camera error: ");
  Serial.print(result.message());
  Serial.print("; native code: 0x");
  Serial.println(result.native, HEX);
}
Member Meaning
error Portable Error enum
native Original esp_err_t where available
ok() true for success
operator bool() Allows if (result) and if (!result)
message() Short static English description

Error values are None, InvalidArgument, InvalidState, Unsupported, NoMemory, CameraNotFound, SensorMismatch, CaptureFailed, StorageFailed, NetworkFailed, Timeout, and NativeError.

Camera lifecycle

Construction and startup

Camera camera;
Result begin();
Result begin(const Config &config);
Result begin(const BoardProfile &board, const Config &config);

In actual code these are called as camera.begin(...). Startup validates the configuration, checks it against the expected sensor capabilities, initializes the camera driver, detects the physical sensor, optionally enforces identity, and activates the selected staged or capability-gated direct DMA path.

Calling begin() on an already initialized object returns InvalidState.

Capture

Frame frame = camera.capture();
if (frame) {
  // Use the frame.
}

Capture makes one bounded retry when the underlying driver initially returns no frame. An empty Frame indicates failure. The core capture method does not allocate or copy a second image buffer.

Reconfigure and recover

Method Behavior
reconfigure(config) Restarts with a new driver configuration; if startup fails, attempts to restore the previous working configuration
recover() Deinitializes and restarts the current board/configuration after a camera fault
end() Releases the camera driver and frame buffers
isReady() Reports whether the camera is currently initialized

Release every live Frame before any lifecycle transition.

Suspend and resume

Result result = camera.suspend(PowerState::DriverOff);
// Application-controlled sleep or idle period.
result = camera.resume();
PowerState Behavior
Active Camera initialized and available
DriverOff Camera driver and frame buffers deinitialized
BoardPowerDown Driver deinitialized and PWDN asserted when that GPIO is wired

BoardPowerDown returns Unsupported on boards whose profile has no PWDN pin. The application remains responsible for Wi-Fi sleep, ESP32 light/deep sleep, CPU frequency, and peripheral shutdown.

State access

Method Returns
board() Active BoardProfile, or null before a board is selected
config() Last selected Config
sensor() A SensorControls object for the active sensor
nativeSensor() Espressif sensor_t* escape hatch
capabilities() Capability record for the detected sensor
diagnostics() Current lifecycle, sensor, PSRAM, DMA, and memory information

Frame

Frame is move-only RAII ownership for camera_fb_t.

Method Description
operator bool() Whether a frame buffer is held
data() Read-only pointer to frame bytes
size() Byte count
width() / height() Captured dimensions
nativeFormat() Espressif pixformat_t
timestampUs() Driver timestamp in microseconds
native() Native camera_fb_t* access
release() Return the buffer before scope exit

Copy construction and copy assignment are disabled. Move construction and move assignment transfer ownership safely.

Pointers from data() and native() become invalid after release. Do not call esp_camera_fb_return() yourself for a frame still owned by Frame.

Config

Config contains profile, pixelFormat, frameSize, jpegQuality, frameBuffers, bufferLocation, grabMode, xclkHz, dmaMode, the legacy psramDma compatibility flag, and validateSensor.

Config config;          // Balanced
config.useEco();        // Replace every field with Eco defaults
config.useBalanced();   // Replace every field with Balanced defaults
config.useTurbo();      // Replace every field with Turbo defaults
config.useStagedDma();  // Select the portable staged path
config.useDirectDma();  // Select and tune the optional direct path

Static factories Config::Eco(), Config::Balanced(), and Config::Turbo() are also available, but object methods are preferred in examples for clarity. See Configuration and profiles for exact values, formats, frame sizes, memory behavior, and tuning.

useDirectDma() is currently hardware-verified for ESP32-S3 with OV5640 QSXGA JPEG. It selects two or more Latest-mode PSRAM buffers, a safe JPEG-quality floor, and 20 MHz XCLK. camera.begin() rejects direct requests outside the verified constraints. useStagedDma() restores the default camera-GDMA to internal-SRAM path followed by the driver copy into the PSRAM frame buffer.

Board profiles

Built-in profiles describe ESP32-S3-CAM N16R8, AI-Thinker ESP32-CAM, and XIAO ESP32-S3 Sense. Automatic selection is used by camera.begin() and storage.begin().

An explicit board is available for generic board targets:

const BoardProfile &board = BoardProfiles::AiThinkerEsp32Cam();
Result result = camera.begin(board);

BoardProfile contains a name, CameraPins, StoragePins, expected SensorModel, verification metadata, and an optional CameraModuleInfo pointer. Module metadata describes the lens angle and flex-cable length plus declaredOpticalFilter, declaredIrPassWavelengthNm, and declaredNightVisionCapable. These fields record vendor claims; they do not constitute spectral verification or imply an integrated IR illuminator. See Supported hardware before creating a custom profile.

Generic built-in profiles auto-detect OV2640, OV3660, or OV5640 on the selected board wiring. Exact module methods are available when sensor mismatch rejection and optical metadata are required:

  • Esp32S3CamOv2640Standard()
  • Esp32S3CamOv5640Fixed130()
  • Esp32S3CamOv5640Autofocus50mm()
  • AiThinkerEsp32CamOv2640Wide850nm()
  • AiThinkerEsp32CamOv5640Fixed65()
  • XiaoEsp32S3SenseOv3660Standard()
  • XiaoEsp32S3SenseOv2640Wide650nm()

An exact profile validates the detected sensor ID; it cannot identify how a vendor routed that sensor on the flex. Before using the OV5640 profile, compare the module datasheet with the supported 24-pin DVP layout. MIPI CSI-2 variants are not supported by the ESP32 camera peripheral.

OV5640 autofocus

Autofocus is an optional object bound to an initialized OV5640 camera:

Autofocus autofocus;
Result result = autofocus.begin(camera, AutofocusMode::SingleShot);
if (result)
  result = autofocus.trigger();

AutofocusStatus focusInfo;
if (result)
  result = autofocus.wait(focusInfo, 5000);

It supports SingleShot and Continuous modes. status() reports initialized, focused, busy, and the sensor-native status byte. end() stops the controller; available() reports readiness. See OV5640 autofocus.

OV2640 sensor timing

Ov2640Controls applies the sensor manufacturer's 24 MHz automatic frame-rate sequences without changing the image to grayscale:

Ov2640Controls ov2640;
Result result = ov2640.begin(camera);
if (result)
  result = ov2640.automaticFrameRate60Hz();

automaticFrameRate50Hz() selects the documented 50 Hz sequence and restoreTiming() restores the values captured by begin(). See OV2640 low-light timing.

Sensor capabilities

camera.capabilities() returns:

  • Sensor model and native dimensions
  • Minimum and maximum frame-size enums
  • Allowed frame-size masks for JPEG, grayscale, RGB-family, and RAW outputs
  • Whether the verified sensor path permits PSRAM DMA
  • Whether sharpness and denoise controls are available

Use the portable helper before changing driver configuration:

const SensorCapabilities &caps = camera.capabilities();
if (supports(caps, PixelFormat::Jpeg, FrameSize::UXGA)) {
  // This sensor/format/size combination is represented as supported.
}

sensorName(model), identifySensor(id), sensorCapabilities(model), nativePixelFormat(format), and nativeFrameSize(size) support diagnostic and advanced integration code.

Sensor controls

Obtain a lightweight control object after successful camera startup:

SensorControls sensor = camera.sensor();
if (!sensor.available()) {
  Serial.println("Sensor is unavailable");
}

Image tuning

Method Portable range / values
brightness(value) -2 to 2
contrast(value) -2 to 2
saturation(value) -2 to 2
sharpness(value) -3 to 3; sensor-dependent
denoise(value) 0 to 8; sensor-dependent
specialEffect(value) None, Negative, Grayscale, RedTint, GreenTint, BlueTint, Sepia

Exposure and gain

Method Meaning
automaticExposure(enabled) Sensor exposure-control loop
dspAutomaticExposure(enabled) Secondary DSP AEC algorithm where supported
exposureValue(value) Manual/native exposure value, 0-1200
exposureLevel(value) Automatic-exposure bias, -2 to 2
automaticGain(enabled) Automatic gain-control loop
gain(value) Manual/native gain value, 0-30
gainCeiling(value) Automatic gain ceiling from X2 through X128

Disable the corresponding automatic loop before expecting a manual exposure or gain value to remain fixed.

White balance and orientation

Method Meaning
automaticWhiteBalance(enabled) Main automatic white-balance loop
whiteBalanceGain(enabled) Automatic white-balance gain application
whiteBalanceMode(value) Auto, Sunny, Cloudy, Office, or Home
horizontalMirror(enabled) Mirror left/right
verticalFlip(enabled) Flip top/bottom

Sensor pipeline and testing

Method Meaning
testPattern(enabled) Sensor color-bar/test pattern
lensCorrection(enabled) Lens-shading correction
rawGamma(enabled) Raw gamma stage
badPixelCorrection(enabled) Bad-pixel correction
whitePixelCorrection(enabled) White-pixel correction
downsize(enabled) Sensor downsize/crop stage
reset() Reset sensor registers through the bundled driver

Live output changes

frameSize(value), pixelFormat(value), and jpegQuality(value) call the sensor's live operations. For changes that materially alter memory requirements or are followed by sustained capture, prefer updating a Config and calling camera.reconfigure() so driver buffers match the intended output.

Native sensor access

sensor.native() returns Espressif's sensor_t*. It permits register, PLL, window, and sensor-specific operations not represented by NiusCam. Native calls bypass portable validation and can make the current Config description stale.

Diagnostics

Diagnostics reports:

Field Meaning
initialized Camera driver is active
psramAvailable Arduino core detected PSRAM
psramDmaRequested Current config requested DMA
psramDmaEnabled Capability-gated DMA path was actually enabled
dmaModeRequested Typed requested mode: Staged or Direct
dmaModeActive Typed active mode after initialization
sensor / sensorPid Detected sensor identity
freeHeap / freePsram Current free memory snapshots
powerState Current NiusCam camera lifecycle state

Memory values are observations at call time, not allocation guarantees.

Storage API

Include <NiusCamStorage.h> and construct Storage storage;.

Method Behavior
begin(frequencyHz) Mount storage from the automatic board profile; default 10 MHz request with bounded fallback
begin(board, frequencyHz) Mount storage from an explicit/custom board profile
end() Unmount and release the selected bus
mounted() Whether a filesystem object is active
info() Capacity, used/free bytes, mount state, and bus
saveJpeg(frame, path, atomic, callback, context) Save one JPEG, optionally using a temporary file and progress callback
saveNextJpeg(frame, directory, prefix, sequence) Create a collision-free six-digit filename
recordJpegs(camera, count, intervalMs, directory, saved) Capture a bounded sequence at a requested interval
native() Underlying Arduino fs::FS*

saveJpeg() rejects non-JPEG frames. See Storage guide for examples, progress fields, card preparation, and error handling.

HTTP API

Include <NiusCamHttp.h> and create HttpStreamServer server;.

Method Behavior
begin(camera, port) Start the server; default port 80
end() Stop the server and release its handle
running() Whether the server is active

Routes are /, /snapshot.jpg, and /stream. Camera output must be JPEG. The application configures Wi-Fi and must not capture concurrently while a stream client owns capture. See Streaming guide.

UDP API

Include <NiusCamUdp.h> and create UdpFrameSender sender;.

Method Behavior
begin(destination, destinationPort, localPort, packetIntervalUs) Open a unicast sender; destination defaults to port 5005
send(frame) CRC and packetize one JPEG frame into payloads of at most 1200 bytes
end() Close the UDP socket
frameId() Last assigned monotonic frame identifier
crc32(data, length) Protocol-compatible complete-frame CRC32

send() is synchronous and returns after the frame's packets have been queued or a bounded retry fails. It rejects non-JPEG frames. See UDP protocol.

Concurrency and ownership

NiusCam deliberately adds no mutex and no background capture task. Serialize camera lifecycle and capture in one task, or protect them with an application-level lock.

  • Do not capture in loop() while an HTTP MJPEG client is streaming.
  • Do not reconfigure, recover, suspend, or end while a Frame exists.
  • Do not access the same Storage or UdpFrameSender object concurrently without application synchronization.
  • Keep callbacks short; a storage progress callback runs inside the write.

These rules avoid hidden copies, tasks, and persistent synchronization overhead.