// firmware/src/main_capture.cpp // // Frame-dump firmware. Replaces main.cpp when building env:timercam-capture. // Streams raw 96x96 grayscale frames at 5 fps over serial (921600 baud) for // offline algorithm iteration. // // Wire format per frame (little-endian): // magic uint32 0xDC0FC0DE // frame_ix uint32 monotonic counter // millis uint32 ms since boot // pixels byte[9216] raw grayscale 96x96, row-major // // No WiFi, no BLE, no CV. Just camera → serial. #include #include "camera.h" #include "cv.h" // for CV_PIXELS #define LED_PIN 2 #define CAM_FPS 5 #define CAM_INTERVAL_MS (1000 / CAM_FPS) // Magic chosen from bytes that commonly survive; 'FRM1' ascii. // Avoid high bytes 0xA0-AF / 0xD0-DF — observed missing from the CH9102 stream. static const uint32_t FRAME_MAGIC = 0x314D5246; // 'FRM1' little-endian on wire void setup() { Serial.begin(460800); pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, HIGH); delay(500); Serial.println("# capture-mode: 460800 baud, 96x96 gray @ 5fps"); Serial.flush(); if (!camera_init()) { Serial.println("# FATAL: camera init failed"); while (true) { digitalWrite(LED_PIN, !digitalRead(LED_PIN)); delay(200); } } digitalWrite(LED_PIN, LOW); } void loop() { static uint8_t frame[CV_PIXELS]; static uint32_t frame_ix = 0; uint32_t t0 = millis(); if (camera_capture_96(frame)) { uint32_t ms = millis(); Serial.write((uint8_t*)&FRAME_MAGIC, 4); Serial.write((uint8_t*)&frame_ix, 4); Serial.write((uint8_t*)&ms, 4); Serial.write(frame, CV_PIXELS); frame_ix++; digitalWrite(LED_PIN, frame_ix & 1); } uint32_t elapsed = millis() - t0; if (elapsed < CAM_INTERVAL_MS) delay(CAM_INTERVAL_MS - elapsed); }