firmware-base/docs/serial.md

135 lines
6.3 KiB
Markdown

# Serial Communication Interface
This document describes the serial communication protocol used for interacting with the firmware, primarily for testing, debugging, and basic control.
## Overview
The system listens for specific command strings sent over the primary serial port (the one used for programming and monitoring).
- **Receiver:** The `SerialMessage` component is responsible for reading data from the serial port.
- **Parser:** `SerialMessage` parses incoming data looking for the specific command format.
- **Dispatcher:** Upon receiving a valid command, `SerialMessage` passes it to the `Bridge` component.
- **Executor:** The `Bridge` looks up the target component and method based on the command's `component_id` and `payload`, then executes the corresponding registered function on the target component instance.
- **Output:** Feedback and results are primarily sent back via log messages (`Log.info`, `Log.verbose`, etc.) printed to the same serial port.
## Command Format
Commands must adhere to the following string format:
`<<component_id;call_type;flags;payload:arg1:arg2...>>`
**Components:**
* `<< >>`: Start and end delimiters for the command string.
* `;`: Primary delimiter separating the main parts of the command header.
* `:`: Secondary delimiter separating the payload (method name) from its arguments.
**Fields:**
1. **`component_id` (short):** The unique ID of the target component. These IDs are defined in the `COMPONENT_KEY` enum in `src/enums.h`. For example, `1` usually refers to the main `PHApp`.
2. **`call_type` (int):** Specifies the type of call. For calling registered component methods via the Bridge, this should generally be `2` (representing `E_CALLS::EC_METHOD`).
3. **`flags` (int):** Message flags, often used internally. For simple commands, `64` is a commonly used value seen in examples, but its specific meaning isn't critical for basic method calls.
4. **`payload` (String):** Contains the name of the method to call on the target component.
5. **`arg1`, `arg2`, ... (short):** Arguments passed to the target method. Currently, the `Bridge` implementation parses up to two `short` arguments (`arg1`, `arg2`). The called method must match the signature `short functionName(short arg1, short arg2)`. Unused arguments in the command string should still be present (e.g., `:0:0`).
## Execution Flow
```mermaid
sequenceDiagram
participant User as User / Script
participant SerialPort as Hardware Serial Port
participant SM as SerialMessage Component
participant Br as Bridge Component
participant Target as Target Component (e.g., Relay, PHApp)
User->>SerialPort: Send Command String (See Examples Section)
loop Serial Read
SM->>SerialPort: Read available data
end
SM->>SM: Parse data, identify complete command string
SM->>Br: onMessage(id=300, verb=EC_METHOD, flags=64, user="setValue:1:0", src=SM)
Br->>Br: Parse user string: method="setValue", arg1=1, arg2=0
Br->>Br: Find registered method for ID 300, name "setValue"
Note over Br: Looks up SComponentInfo in componentList
Br->>Target: Execute registered function pointer: (target->*ptr)(1, 0)
Note over Target: e.g., Relay::setValueCmd(1, 0)
Target->>Target: Perform action (e.g., update internal state)
Target-->>Br: Return result (e.g., E_OK)
Br-->>SM: Return result (E_OK)
Note over Target: Components may log info/verbose messages to SerialPort during execution.
```
## Available Commands (Examples)
This list is based on methods registered in `PHApp::onRegisterMethods` and `Relay::onRegisterMethods`. Other components might register their own methods.
**PHApp (Component ID: 1)**
* **List Components & Methods:** Lists components registered with the `Bridge`.
```
<<1;2;64;list:0:0>>
```
* **Print Component Info:** Calls `info()` on all components in `PHApp`'s list.
```
<<1;2;64;print:0:0>>
```
* **Reset Device:** Triggers `ESP.restart()`.
```
<<1;2;64;reset:0:0>>
```
* **Print Modbus Registers (Debug):** Prints the (now simplified) Modbus register table.
```
<<1;2;64;printRegisters:0:0>>
```
* **Test Relays:** Toggles Relay 0 and Relay 1 (using internal `setValue`).
```
<<1;2;64;testRelays:0:0>>
```
* **Get Battle Counter:** Returns the current value of the Modbus battle counter.
```
<<1;2;64;getCounter:0:0>>
```
* **Increment Battle Counter:** Increments the Modbus battle counter.
```
<<1;2;64;incrementCounter:0:0>>
```
* **Reset Battle Counter:** Resets the Modbus battle counter to 0.
```
<<1;2;64;resetCounter:0:0>>
```
* **Get Client Stats:** Returns Modbus client connection statistics.
```
<<1;2;64;getClientStats:0:0>>
```
* **Reset Client Stats:** Resets Modbus client connection statistics.
```
<<1;2;64;resetClientStats:0:0>>
```
**Relay (Component IDs: 300, 301, ...)**
* **Set Relay State:** Sets the relay ON (1) or OFF (0).
* Set Relay 300 ON: `<<300;2;64;setValue:1:0>>`
* Set Relay 300 OFF: `<<300;2;64;setValue:0:0>>`
* Set Relay 301 ON: `<<301;2;64;setValue:1:0>>`
* **Get Relay Info:** Prints info about the relay (pin, address, current value) to serial log.
* Info for Relay 300: `<<300;2;64;info:0:0>>`
* Info for Relay 301: `<<301;2;64;info:0:0>>`
**Note:** The specific component IDs (like 300, 301) are defined in `src/enums.h` (`COMPONENT_KEY_MB_RELAY_0`, `COMPONENT_KEY_MB_RELAY_1`).
## Sending Commands
You can send these command strings using:
1. **`npm run send`:** This uses the `scripts/send_message.py` script, which likely requires the full command string as an argument.
```bash
npm run send -- "<<1;2;64;list:0:0>>"
npm run send -- "<<300;2;64;setValue:1:0>>"
```
2. **Manual Serial Monitor:** You can paste the command string directly into a serial monitor connected to the ESP32 (ensure your monitor doesn't add extra line endings unless `SerialMessage` handles them).
3. **Other Scripts:** Scripts like `send_serial_cmd.py` are also available.
## Receiving Output
Most commands provide feedback by logging messages to the serial port using the `ArduinoLog` library. Monitor the serial output (`npm run monitor`) to see results, confirmations, and error messages.