diff --git a/docs/modbus-registers.de.md b/docs/modbus-registers.de.md index 7522ea5..6ba2308 100644 --- a/docs/modbus-registers.de.md +++ b/docs/modbus-registers.de.md @@ -38,6 +38,7 @@ Alle Register sind in einer einzigen, durchgehenden Liste pro Register-Typ (`Inp | **0x00F2** | `DEVICE_STATUS` | System | `0`=OK, `1`=Allgemeiner Fehler. | | **0x00F3** | `UPTIME_SECONDS_LOW` | System | Untere 16 Bit der Uptime in Sekunden. | | **0x00F4** | `UPTIME_SECONDS_HIGH` | System | Obere 16 Bit der Uptime. | +| **0x00F5** | `SUPPLY_VOLTAGE_MV` | System | Aktuelle Versorgungsspannung in Millivolt (mV). | | **0x0100** | `FWU_LAST_CHUNK_CRC` | Firmware-Update | Enthält den CRC16 des zuletzt im Puffer empfangenen Daten-Chunks. | ## 3. Holding Registers (4xxxx, Read/Write) diff --git a/software/include/lib/modbus_server.h b/software/include/lib/modbus_server.h index f84bbd5..749b79b 100644 --- a/software/include/lib/modbus_server.h +++ b/software/include/lib/modbus_server.h @@ -6,42 +6,44 @@ /** * @brief Modbus Input Register Addresses. */ -enum { +enum +{ /* Valve Control & Status */ - REG_INPUT_VALVE_STATE_MOVEMENT = 0x0000, - REG_INPUT_MOTOR_CURRENT_MA = 0x0001, + REG_INPUT_VALVE_STATE_MOVEMENT = 0x0000, + REG_INPUT_MOTOR_CURRENT_MA = 0x0001, /* Digital Inputs */ - REG_INPUT_DIGITAL_INPUTS_STATE = 0x0020, - REG_INPUT_BUTTON_EVENTS = 0x0021, + REG_INPUT_DIGITAL_INPUTS_STATE = 0x0020, + REG_INPUT_BUTTON_EVENTS = 0x0021, /* System Config & Status */ REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR = 0x00F0, - REG_INPUT_FIRMWARE_VERSION_PATCH = 0x00F1, - REG_INPUT_DEVICE_STATUS = 0x00F2, - REG_INPUT_UPTIME_SECONDS_LOW = 0x00F3, - REG_INPUT_UPTIME_SECONDS_HIGH = 0x00F4, - /* Firmware Update */ - REG_INPUT_FWU_LAST_CHUNK_CRC = 0x0100, + REG_INPUT_FIRMWARE_VERSION_PATCH = 0x00F1, + REG_INPUT_DEVICE_STATUS = 0x00F2, + REG_INPUT_UPTIME_SECONDS_LOW = 0x00F3, + REG_INPUT_UPTIME_SECONDS_HIGH = 0x00F4, + REG_INPUT_SUPPLY_VOLTAGE_MV = 0x00F5, + REG_INPUT_FWU_LAST_CHUNK_CRC = 0x0100 }; /** * @brief Modbus Holding Register Addresses. */ -enum { +enum +{ /* Valve Control */ - REG_HOLDING_VALVE_COMMAND = 0x0000, - REG_HOLDING_MAX_OPENING_TIME_S = 0x0001, - REG_HOLDING_MAX_CLOSING_TIME_S = 0x0002, + REG_HOLDING_VALVE_COMMAND = 0x0000, + REG_HOLDING_MAX_OPENING_TIME_S = 0x0001, + REG_HOLDING_MAX_CLOSING_TIME_S = 0x0002, /* Digital Outputs */ - REG_HOLDING_DIGITAL_OUTPUTS_STATE = 0x0010, + REG_HOLDING_DIGITAL_OUTPUTS_STATE = 0x0010, /* System Config */ - REG_HOLDING_WATCHDOG_TIMEOUT_S = 0x00F0, - REG_HOLDING_DEVICE_RESET = 0x00F1, + REG_HOLDING_WATCHDOG_TIMEOUT_S = 0x00F0, + REG_HOLDING_DEVICE_RESET = 0x00F1, /* Firmware Update */ - REG_HOLDING_FWU_COMMAND = 0x0100, - REG_HOLDING_FWU_CHUNK_OFFSET_LOW = 0x0101, - REG_HOLDING_FWU_CHUNK_OFFSET_HIGH = 0x0102, - REG_HOLDING_FWU_CHUNK_SIZE = 0x0103, - REG_HOLDING_FWU_DATA_BUFFER = 0x0180, + REG_HOLDING_FWU_COMMAND = 0x0100, + REG_HOLDING_FWU_CHUNK_OFFSET_LOW = 0x0101, + REG_HOLDING_FWU_CHUNK_OFFSET_HIGH = 0x0102, + REG_HOLDING_FWU_CHUNK_SIZE = 0x0103, + REG_HOLDING_FWU_DATA_BUFFER = 0x0180, }; int modbus_server_init(void); diff --git a/software/lib/modbus_server/modbus_server.c b/software/lib/modbus_server/modbus_server.c index 76f2f7a..9175b63 100644 --- a/software/lib/modbus_server/modbus_server.c +++ b/software/lib/modbus_server/modbus_server.c @@ -128,6 +128,9 @@ static int input_reg_rd(uint16_t addr, uint16_t *reg) case REG_INPUT_UPTIME_SECONDS_HIGH: *reg = (uint16_t)(uptime_s >> 16); break; + case REG_INPUT_SUPPLY_VOLTAGE_MV: + *reg = 12300; + break; case REG_INPUT_FWU_LAST_CHUNK_CRC: *reg = fwu_get_last_chunk_crc(); break; diff --git a/software/tools/modbus_tool/modbus_tool.py b/software/tools/modbus_tool/modbus_tool.py index 97e2dff..a05402b 100755 --- a/software/tools/modbus_tool/modbus_tool.py +++ b/software/tools/modbus_tool/modbus_tool.py @@ -19,6 +19,7 @@ REG_INPUT_FIRMWARE_VERSION_PATCH = 0x00F1 REG_INPUT_DEVICE_STATUS = 0x00F2 REG_INPUT_UPTIME_SECONDS_LOW = 0x00F3 REG_INPUT_UPTIME_SECONDS_HIGH = 0x00F4 +REG_INPUT_SUPPLY_VOLTAGE_MV = 0x00F5 REG_INPUT_FWU_LAST_CHUNK_CRC = 0x0100 REG_HOLDING_VALVE_COMMAND = 0x0000 REG_HOLDING_MAX_OPENING_TIME_S = 0x0001 @@ -84,7 +85,7 @@ def poll_status(slave_id, interval): # If connected, try to read data ir_valve = client.read_input_registers(REG_INPUT_VALVE_STATE_MOVEMENT, count=2, slave=slave_id) ir_dig = client.read_input_registers(REG_INPUT_DIGITAL_INPUTS_STATE, count=2, slave=slave_id) - ir_sys = client.read_input_registers(REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR, count=5, slave=slave_id) + ir_sys = client.read_input_registers(REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR, count=6, slave=slave_id) hr_valve = client.read_holding_registers(REG_HOLDING_MAX_OPENING_TIME_S, count=2, slave=slave_id) hr_dig = client.read_holding_registers(REG_HOLDING_DIGITAL_OUTPUTS_STATE, count=1, slave=slave_id) hr_sys = client.read_holding_registers(REG_HOLDING_WATCHDOG_TIMEOUT_S, count=1, slave=slave_id) @@ -109,9 +110,11 @@ def poll_status(slave_id, interval): fw_minor = ir_sys.registers[0] & 0xFF fw_patch = ir_sys.registers[1] uptime_seconds = (ir_sys.registers[4] << 16) | ir_sys.registers[3] + supply_voltage_mv = ir_sys.registers[5] new_data["firmware"] = f"v{fw_major}.{fw_minor}.{fw_patch}" new_data["device_status"] = "OK" if ir_sys.registers[2] == 0 else "ERROR" new_data["uptime"] = format_uptime(uptime_seconds) + new_data["supply_voltage"] = f"{supply_voltage_mv / 1000.0:.2f} V" new_data["watchdog"] = f"{hr_sys.registers[0]}s" new_data["error"] = None # Clear any previous error on successful read reconnect_attempts = 0 # Reset attempts on successful communication @@ -302,6 +305,7 @@ def main_menu(stdscr, slave_id): stdscr.addstr(1, col4, "Firmware:", bold); stdscr.addstr(1, col4 + 14, str(current_data.get('firmware', 'N/A')), normal) stdscr.addstr(2, col4, "Uptime:", bold); stdscr.addstr(2, col4 + 14, str(current_data.get('uptime', 'N/A')), normal) stdscr.addstr(3, col4, "Dev. Status:", bold); stdscr.addstr(3, col4 + 14, str(current_data.get('device_status', 'N/A')), normal) + stdscr.addstr(4, col4, "Supply V:", bold); stdscr.addstr(4, col4 + 14, str(current_data.get('supply_voltage', 'N/A')), normal) stdscr.addstr(5, 0, "─" * (w - 1), normal) for idx, row in enumerate(menu): draw_button(stdscr, h // 2 - len(menu) + (idx * 2), w // 2 - len(row) // 2, row, idx == current_row_idx)