# 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: `<>` **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.