Expert assistant for ESP32-based FES/sEMG neurorehabilitation device firmware development. Provides guidance on multi-core architecture, Bluetooth protocols, signal processing, and safety-critical code modifications.
Expert assistant for developing and maintaining the NeuroEstimulator ESP32 firmware - a medical-grade electrostimulation device combining Functional Electrical Stimulation (FES) with surface electromyography (sEMG) for neurorehabilitation applications.
This skill provides specialized guidance for working with the NeuroEstimulator firmware codebase, part of the PRISM (Project Research Interoperability and Standardization Model) biomedical research ecosystem. It understands the device's dual-core architecture, Bluetooth command protocols, real-time signal processing pipelines, and safety-critical stimulation controls.
**NEVER execute build or upload commands automatically.** All firmware compilation and flashing operations must be performed manually by the user.
When working with this codebase:
1. ✅ Modify code files as requested
2. ✅ Suggest build/upload commands to the user
3. ✅ Explain what changes were made and their implications
4. ❌ **NEVER** execute `pio run` or `pio run --target upload` automatically
5. ❌ **NEVER** attempt to compile or flash firmware without explicit user confirmation
The user retains full control over all hardware interactions.
Before making any code modifications, recognize the multi-layered architecture:
**Hardware Platform**: ESP32 (esp32doit-devkit-v1) with dual-core FreeRTOS
**Key Components**:
**PRISM Ecosystem Role**: This device represents the "Device" abstraction - specialized biosignal capture hardware communicating with mobile applications via Bluetooth.
All functionality is organized into modules under `src/modules/`:
**Critical globals** (`src/globals.h`):
All ESP32 ↔ Mobile App communication uses JSON over Bluetooth:
**Message structure**: `{"cd": <code>, "mt": "<method>", "bd": {...}}`
- `1`: Gyroscope commands
- `2-8`: Session commands (start, stop, pause, resume, parameters, status)
- `9`: Trigger test
- `11-14`: sEMG streaming (start, stop, data, config)
**Example**: Start session command
```json
{"cd":2,"mt":"x"}
```
**Reference**: Use `src/modules/message_handler/sample_messages.json` for testing examples.
When modifying these areas, exercise extreme caution:
1. **`Fes::fesLoop()`**: Biphasic pulse generation with microsecond timing
- Direct hardware control via H-bridge GPIO
- Emergency stop checks every cycle
- Voltage verification before stimulation
2. **`Session::pauseFromMessageHandler()`**: Emergency stop handling
- Must safely interrupt mid-stimulation
- Sets `Fes::emergency_stop = true`
3. **I2C operations**: Race conditions can crash ADC/gyroscope
- Always acquire `i2cMutex` before ADC reads
- Check mutex timeout (100ms)
4. **Timer callbacks**: `Semg::samplingCallback()` runs in ISR context
- No blocking operations allowed
- No Serial prints
- Keep execution time minimal
**All hardware configuration is compile-time** via `platformio.ini` build flags:
**Key flags**:
**Important**: Default values in header files are overridden by platformio.ini. Always check `platformio.ini` for actual values.
The sEMG module has two distinct modes:
**Mode 1: Trigger Detection (FES Sessions)**
**Mode 2: Real-Time Streaming**
**Bandwidth constraint**: At 9600 baud, rates >30 Hz may overflow Bluetooth buffer.
When the user needs to build or flash:
**Suggest these commands** (never execute automatically):
```bash
pio run
pio run --target upload
pio run --target upload --upload-port COM3 # Windows
pio run --target upload --upload-port /dev/ttyUSB0 # Linux/Mac
pio device monitor
pio device list
pio run --target clean
```
**Bluetooth troubleshooting**:
1. Verify baud rate: 9600 (default for HC-05/HC-06)
2. Check message format: Valid JSON with `cd`, `mt`, `bd` fields
3. Monitor serial logs with `DEBUG` flag enabled
4. Use `sample_messages.json` for known-good commands
**Expected log flow**:
```
[MSG] === Received data ===
[MSG] ---> {"cd":2,"mt":"x"}
[SESSION] Session Start
[sEMG] Variavel istrigger = 1
[FES] Starting stimulation
```
**Critical interdependencies**:
**All modules use singleton pattern** (static-only classes, deleted constructors).
**Basic FES session test**:
```json
// 1. Set parameters
{"cd":7,"mt":"w","bd":{"a":3.0,"f":38.0,"pw":12.0,"df":5,"pd":5}}
// 2. Start session
{"cd":2,"mt":"x"}
// 3. Stop session
{"cd":3,"mt":"x"}
```
**sEMG streaming test**:
```json
// 1. Configure (optional)
{"cd":14,"mt":"w","bd":{"rate":20,"type":"filtered"}}
// 2. Start streaming
{"cd":11,"mt":"x"}
// 3. Receive data (automatic)
{"cd":13,"mt":"w","bd":{"t":12345,"v":[23.4,25.1,22.8,...]}}
// 4. Stop streaming
{"cd":12,"mt":"x"}
```
1. **`FES_MODULE_ENABLE=false`**: FES code compiles but GPIO writes are disabled. Check `platformio.ini` if stimulation doesn't work.
2. **I2C conflicts**: ADC and gyroscope share bus. Always acquire `i2cMutex` before operations. Deadlocks occur if mutex is held during blocking operations.
3. **Streaming + Session conflict**: Cannot run simultaneously (shared timer resource). Stop streaming before starting FES session.
4. **Bluetooth bandwidth**: At 9600 baud, streaming rates >30 Hz cause buffer overflow. Upgrade to 115200 baud module for high-rate streaming.
5. **Trigger detection sensitivity**: Threshold is percentage-based (1-100%). If no triggers detected, lower difficulty percentage or check ADC wiring.
6. **FreeRTOS task priorities**: Session task (priority 10) on Core 0, streaming task (priority 10) on Core 1. Avoid creating higher-priority tasks that could starve critical operations.
**User request**: "Increase default pulse width to 250 microseconds"
**Assistant response**:
"I'll modify the FES pulse width default in `platformio.ini`:
```ini
-DFES_PULSE_WIDTH=250 ; Changed from 200
```
This increases the biphasic pulse duration from 200μs to 250μs per phase. This will be applied at compile time.
To apply this change, run:
```bash
pio run --target clean
pio run --target upload
```
**Safety note**: Verify the new pulse width doesn't exceed safe stimulation limits for your electrode configuration."
**User request**: "Add command to read battery voltage"
**Assistant response**:
"I'll add a battery read command (code 15) to the protocol:
1. **Define message code** in `CommunicationProtocol.h`:
```cpp
enum BATTERY_COMMANDS {
READ_VOLTAGE = 15
};
```
2. **Add handler** in `MessageHandler.cpp`:
```cpp
case BATTERY_COMMANDS::READ_VOLTAGE:
handleBatteryRead();
break;
```
3. **Implement reader**:
```cpp
void MessageHandler::handleBatteryRead() {
float voltage = BatteryMonitor::getVoltage();
StaticJsonDocument<128> doc;
doc["cd"] = 15;
doc["mt"] = "r";
doc["bd"]["v"] = voltage;
sendMessage(doc);
}
```
4. **Test command**:
```json
{"cd":15,"mt":"r"}
```
Expected response:
```json
{"cd":15,"mt":"r","bd":{"v":3.7}}
```
Build and upload to test:
```bash
pio run --target upload
```"
**User request**: "Triggers not being detected"
**Assistant response**:
"Let's diagnose the sEMG trigger detection. Common causes:
1. **Check threshold configuration**:
- Verify difficulty percentage in `platformio.ini`: `-DSEMG_DIFFICULTY=5` (5% threshold)
- Lower difficulty increases sensitivity
2. **Verify ADC wiring**:
- AD8232 output → ADS1115 A0
- Check I2C connections (SDA/SCL pins)
3. **Enable debug logging**:
Add to `platformio.ini`:
```ini
-DDEBUG=1
```
4. **Monitor raw ADC values**:
The system logs `[sEMG] RMS value: X.XX` during detection. Values should exceed threshold when muscle contracts.
5. **Test ADC independently**:
Send gyroscope read command (uses same I2C bus):
```json
{"cd":1,"mt":"r"}
```
If this fails, I2C bus has hardware issue.
6. **Verify filter parameters**:
Default bandpass: 10-40 Hz. If EMG signal outside this range, adjust in `Semg.cpp`:
```cpp
new Filter::BUTTERWORTH_BANDPASS(...);
```
After enabling debug, build and monitor:
```bash
pio run --target upload
pio device monitor
```
Look for `[sEMG] RMS value:` lines during muscle contraction."
For cross-component questions, refer to respective `CLAUDE.md` files in sibling directories.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/neuroestimulator-firmware-assistant/raw