# AGENTS.md - Sirens Project ## Project Overview This is an Arduino/ESP32 embedded systems project for controlling sirens. The codebase consists of multiple Arduino sketches (.ino files) for different hardware components. ## Directory Structure ``` sirens/ ├── src/ │ ├── siren_remote_control_esp32_v2/ # Remote control unit │ │ └── siren_remote_control_esp32_v2.ino │ ├── siren_controller_esp32_simple_station_v2_multi/ # Station controller │ │ └── siren_controller_esp32_simple_station_v2_multi.ino │ └── B_G431B_ESC1_motor_controller/ # SimpleFOC motor controller │ └── B_G431B_ESC1_motor_controller.ino ├── v1/ # Version 1 designs ├── designs/ # CAD files (OpenSCAD, STL) └── AGENTS.md # This file ``` ## Build Commands ### Current State - **No command-line build system configured** - Uses Arduino IDE - Upload via Arduino IDE or PlatformIO (recommended for future) ### Future: PlatformIO Migration (TODO) ```bash # Once PlatformIO is configured: pio run # Build all projects pio run -e # Build specific environment pio run -t upload # Upload to device pio device monitor # Monitor serial output ``` ### Running a Single Test - **No unit tests exist** - Embedded projects typically test via hardware - For now, manual testing on physical hardware is required ## Libraries The project uses the following Arduino/ESP32 libraries: | Library | Purpose | |---------|---------| | WiFi | ESP32 WiFi connectivity | | Wire | I2C communication | | SSD1306Ascii / SSD1306AsciiWire | OLED display (128x64) | | ArduinoOSCWiFi | OSC protocol over WiFi | | AiEsp32RotaryEncoder | Rotary encoder input | | arduino-timer | Timer/async operations | | Preferences | ESP32 NVS storage | | SimpleFOC | Motor control (B-G431B-ESC1) | | SimpleFOCDrivers | SimpleFOC driver utilities | ## Code Style Guidelines ### General Conventions - **Language**: C++ (Arduino framework) - **File extension**: `.ino` (Arduino sketch) - **Naming**: camelCase for variables and functions - **Constants**: UPPER_SNAKE_CASE with `const` or `#define` ### Arduino Sketch Structure ```cpp // 1. Includes #include "WiFi.h" #include #include // 2. Global constants const int sirenCount = 4; const char* ssid = "sirening"; // 3. Global variables int menuSelect = 0; // 4. Function prototypes (if needed) void setupEncoderButton(AiEsp32RotaryEncoder& eb, char* val); // 5. setup() - runs once at boot void setup() { Serial.begin(115200); // initialization code... } // 6. loop() - runs continuously void loop() { // main logic... } ``` ### Functions - Keep functions focused and reasonably sized (<100 lines) - Use descriptive names: `updateFreq()`, `killAll()`, `setupOSC()` - Group related functions together - Use helper functions to reduce duplication in loop() ### Types - Use explicit types: `int`, `float`, `bool`, `unsigned long` - Prefer `const` for values that won't change - Use `float` for floating-point values (no `double` on ESP32) ### Error Handling - Return early on errors: ```cpp if(!currentSense.init()){ Serial.println("Current sense init failed."); return; } ``` - Use Serial for debugging output with descriptive messages - Validate input ranges before use: ```cpp if (input < 500.0 && input >= 0.0) { updateFreq(input); } ``` ### Interrupt Service Routines (ISR) - Mark ISRs with `IRAM_ATTR` on ESP32: ```cpp void IRAM_ATTR readFreqEncoderISR() { encoderButton1.readEncoder_ISR(); } ``` - Keep ISRs minimal - only do essential work ### Display/UI Code - Use helper functions for display updates: ```cpp void updateDisplayValue(String string) { oled.set2X(); oled.setCursor(12, 5); oled.print(string); oled.clearToEOL(); } ``` ### OSC Communication - Use lambda callbacks for OSC subscriptions: ```cpp OscWiFi.subscribe(settings_port, "/freq", [](const OscMessage& m) { float input = m.arg(0); // handle message... }); ``` ### Preferences (NVS) - Open with explicit mode: ```cpp prefs.begin("prefs", RO_MODE); // false = read/write, true = read only prefs.putUInt("ports", ports); prefs.getUInt("ports"); prefs.end(); ``` ### Serial Communication - Use `Serial.begin(115200)` for debug output - Use `HardwareSerial` for additional UARTs: ```cpp HardwareSerial freqSerial(1); freqSerial.begin(115200, SERIAL_8N1, 18, 19); ``` ### Comments - Use TODO comments for future work: ```cpp //TODO: These should be bound to a publication of the frequency directly from the siren ``` - Comment out disabled code with explanation - Keep comments brief and purposeful ### Formatting - Use 2-space indentation (Arduino default) - Opening brace on same line - Space after keywords: `if (` not `if(` ## Future Improvements 1. **Add PlatformIO**: Create `platformio.ini` for command-line builds 2. **Add unit tests**: Use PlatformIO unit testing for non-hardware logic 3. **Consolidate common code**: Extract shared utilities into a common library 4. **Add CI/CD**: GitHub Actions for build verification 5. **Document hardware**: Add wiring diagrams and pinouts ## Hardware Targets - **ESP32** (WiFi + BLE) - **B-G431B-ESC1** motor controller (SimpleFOC compatible) - **OLED Display**: SSD1306 128x64 I2C - **Rotary Encoder**: AiEsp32RotaryEncoder ## Development Notes - Serial monitor uses 115200 baud - WiFi AP: `sirening` / `alarm_11735` - OSC ports: 54000 (settings), 54001 (state) - Motor control uses FOC (Field-Oriented Control) via SimpleFOC