# 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 <environment>         # 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 <Wire.h>
#include <SSD1306Ascii.h>

// 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<float>(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
