// SPDX-License-Identifier: GPL-3.0-only // // OpenScribe firmware entry point. // // M1 (recording core): boots audio + storage, then records to a WAV file on the microSD // card, toggled by the button, with the status LED showing idle/recording/error. Each // recording gets a sidecar JSON metadata file matching the Recording schema in // api/openapi.yaml. // // Later milestones add the remaining module seams: // power - battery ADC, charge/VBUS detect -> mode switch (M3) // config - NVS settings (WiFi, upload target, codec, token) (M2/M3) // net_wifi - WiFi join/reconnect + mDNS (M2) // api_http - on-device REST server (api/openapi.yaml) (M2) // uploader - S3/WebDAV upload when powered (M3) // ble - GATT control + WiFi provisioning (M4) // ota - firmware update over HTTP (M9) #include #include "recorder.h" #include "ux.h" static const char *FIRMWARE_VERSION = "0.1.0"; void setup() { Serial.begin(115200); delay(300); Serial.printf("\nOpenScribe firmware %s booting\n", FIRMWARE_VERSION); #if defined(OPENSCRIBE_BOARD_XIAO) Serial.println("Board: XIAO ESP32-S3 (PDM mic + onboard SD)"); #else Serial.println("Board: ESP32-S3 dev (I2S mic + SD module)"); #endif if (!psramFound()) { Serial.println("WARNING: no PSRAM detected - audio buffering needs a PSRAM board"); } ux::begin(); if (!recorder::begin()) { Serial.println("ERROR: audio or SD init failed - check the mic wiring and SD card"); ux::setLed(ux::Led::Error); return; // stay in error state; loop() still services the LED } Serial.println("Ready. Short-press the button to start/stop recording."); ux::setLed(ux::Led::Idle); } void loop() { // Button: a short press toggles recording. if (ux::poll()) { if (recorder::toggle()) { if (recorder::state() == recorder::State::Recording) { Serial.printf("Recording started: %s\n", recorder::currentId().c_str()); ux::setLed(ux::Led::Recording); } else { Serial.printf("Recording stopped: %s (%lu PCM bytes)\n", recorder::currentId().c_str(), static_cast(recorder::recordedBytes())); ux::setLed(ux::Led::Idle); } } else { Serial.println("ERROR: could not open recording file on SD"); ux::setLed(ux::Led::Error); } } // While recording, drain the mic into the file. recorder::update(); }