#!/usr/bin/env python3 """Compile the actual driver handoff function with deterministic queue stubs.""" from pathlib import Path import shutil import subprocess import sys root = Path(__file__).resolve().parents[1] source = (root/'components/esp32-camera/driver/cam_hal.c').read_text() start = source.index('camera_fb_t *cam_take_latest(') end = source.index('\nvoid cam_give(', start) function = source[start:end] out = root/'target/latest-frame-test' out.mkdir(parents=True, exist_ok=True) test = r''' #include #include #include #include typedef unsigned TickType_t; typedef struct { int id; } camera_fb_t; static struct { size_t frame_cnt; } object = {3}, *cam_obj = &object; static camera_fb_t frames[] = {{0},{1},{2},{3},{4},{5}}; static int calls, releases[6], mode; static camera_fb_t *cam_take(TickType_t wait) { assert(wait == (calls == 0 ? 100 : 0)); ++calls; if (mode == 1 || (mode == 2 && calls == 2)) return NULL; assert(calls < 6); return &frames[calls]; } static void cam_give(camera_fb_t *frame) { releases[frame->id]++; } '''+function+r''' static void reset(int scenario) { mode=scenario; calls=0; for(int i=0;i<6;i++) releases[i]=0; } int main(void) { uint32_t skipped=99; // A producer that stays ahead cannot make the drain loop run forever. reset(0); camera_fb_t *latest=cam_take_latest(100,&skipped); assert(calls==3 && latest->id==3 && skipped==2); assert(releases[1]==1 && releases[2]==1 && releases[3]==0); // An unavailable/invalid newer candidate must not release our valid frame. reset(2); latest=cam_take_latest(100,&skipped); assert(calls==2 && latest->id==1 && skipped==0 && releases[1]==0); // A first-frame timeout has no handle to return, and resets the skip count. reset(1); assert(cam_take_latest(100,&skipped)==NULL && skipped==0 && calls==1); // A single capture buffer performs no second, nonblocking acquisition. reset(0); object.frame_cnt=1; latest=cam_take_latest(100,NULL); assert(calls==1 && latest->id==1 && releases[1]==0); puts("4 latest-frame ownership and bounded-drain scenarios passed"); } ''' (out/'latest-frame.c').write_text(test) compiler = shutil.which('clang') or shutil.which('gcc') if not compiler: sys.exit('A host clang or gcc is required for this optional driver test') binary = out/('latest-frame.exe' if sys.platform=='win32' else 'latest-frame') subprocess.run([compiler,'-std=c11','-Wall','-Wextra','-Werror',str(out/'latest-frame.c'),'-o',str(binary)],check=True) subprocess.run([str(binary)],check=True)