diff --git a/software/apps/slave_node/prj.conf b/software/apps/slave_node/prj.conf index 6e3225e..b11234f 100644 --- a/software/apps/slave_node/prj.conf +++ b/software/apps/slave_node/prj.conf @@ -26,4 +26,6 @@ CONFIG_MODBUS_BUFFER_SIZE=256 # Enable VND7050AJ CONFIG_VND7050AJ=y -CONFIG_LOG_VALVE_LEVEL=4 \ No newline at end of file +CONFIG_LOG_VALVE_LEVEL=4 +CONFIG_VALVE_OBSTACLE_THRESHOLD_OPEN_MA=200 +CONFIG_VALVE_OBSTACLE_THRESHOLD_CLOSE_MA=200 \ No newline at end of file diff --git a/software/include/lib/modbus_registers.h b/software/include/lib/modbus_registers.h new file mode 100644 index 0000000..9b6fc8d --- /dev/null +++ b/software/include/lib/modbus_registers.h @@ -0,0 +1,35 @@ +#ifndef MODBUS_REGISTERS_H +#define MODBUS_REGISTERS_H + +// Input Registers (Read-Only) +#define REG_INPUT_VALVE_STATE_MOVEMENT 0x0000 +#define REG_INPUT_MOTOR_OPEN_CURRENT_MA 0x0001 +#define REG_INPUT_MOTOR_CLOSE_CURRENT_MA 0x0002 +#define REG_INPUT_DIGITAL_INPUTS_STATE 0x0020 +#define REG_INPUT_BUTTON_EVENTS 0x0021 +#define REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR 0x00F0 +#define REG_INPUT_FIRMWARE_VERSION_PATCH 0x00F1 +#define REG_INPUT_DEVICE_STATUS 0x00F2 +#define REG_INPUT_UPTIME_SECONDS_LOW 0x00F3 +#define REG_INPUT_UPTIME_SECONDS_HIGH 0x00F4 +#define REG_INPUT_SUPPLY_VOLTAGE_MV 0x00F5 +#define REG_INPUT_FWU_LAST_CHUNK_CRC 0x0100 + +// Holding Registers (Read-Write) +#define REG_HOLDING_VALVE_COMMAND 0x0000 +#define REG_HOLDING_MAX_OPENING_TIME_S 0x0001 +#define REG_HOLDING_MAX_CLOSING_TIME_S 0x0002 +#define REG_HOLDING_END_CURRENT_THRESHOLD_OPEN_MA 0x0003 +#define REG_HOLDING_END_CURRENT_THRESHOLD_CLOSE_MA 0x0004 +#define REG_HOLDING_OBSTACLE_THRESHOLD_OPEN_MA 0x0005 +#define REG_HOLDING_OBSTACLE_THRESHOLD_CLOSE_MA 0x0006 +#define REG_HOLDING_DIGITAL_OUTPUTS_STATE 0x0010 +#define REG_HOLDING_WATCHDOG_TIMEOUT_S 0x00F0 +#define REG_HOLDING_DEVICE_RESET 0x00F1 +#define REG_HOLDING_FWU_COMMAND 0x0100 +#define REG_HOLDING_FWU_CHUNK_OFFSET_LOW 0x0101 +#define REG_HOLDING_FWU_CHUNK_OFFSET_HIGH 0x0102 +#define REG_HOLDING_FWU_CHUNK_SIZE 0x0103 +#define REG_HOLDING_FWU_DATA_BUFFER 0x0180 + +#endif // MODBUS_REGISTERS_H \ No newline at end of file diff --git a/software/include/lib/valve.h b/software/include/lib/valve.h index 85c7bd8..0b50abd 100644 --- a/software/include/lib/valve.h +++ b/software/include/lib/valve.h @@ -17,9 +17,6 @@ #define VALVE_CHANNEL_CLOSE 1 #define VALVE_ENDPOSITION_CHECK_INTERVAL K_MSEC(100) -#define VALVE_OBSTACLE_THRESHOLD_OPEN_MA 200 -#define VALVE_OBSTACLE_THRESHOLD_CLOSE_MA 200 - /** * @brief Represents the static state of the valve (open or closed). */ @@ -164,4 +161,33 @@ int32_t valve_get_vnd_temp(void); * @return The voltage in millivolts. */ int32_t valve_get_vnd_voltage(void); -#endif // VALVE_H + +/** + * @brief Sets the current threshold for obstacle detection during opening. + * + * @param current_ma The current threshold in milliamps. + */ +void valve_set_obstacle_threshold_open(uint16_t current_ma); + +/** + * @brief Sets the current threshold for obstacle detection during closing. + * + * @param current_ma The current threshold in milliamps. + */ +void valve_set_obstacle_threshold_close(uint16_t current_ma); + +/** + * @brief Gets the current threshold for obstacle detection during opening. + * + * @return The current threshold in milliamps. + */ +uint16_t valve_get_obstacle_threshold_open(void); + +/** + * @brief Gets the current threshold for obstacle detection during closing. + * + * @return The current threshold in milliamps. + */ +uint16_t valve_get_obstacle_threshold_close(void); + +#endif // VALVE_H \ No newline at end of file diff --git a/software/lib/modbus_server/modbus_server.c b/software/lib/modbus_server/modbus_server.c index f7402e9..db57d3b 100644 --- a/software/lib/modbus_server/modbus_server.c +++ b/software/lib/modbus_server/modbus_server.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,12 @@ static int holding_reg_rd(uint16_t addr, uint16_t *reg) case REG_HOLDING_END_CURRENT_THRESHOLD_CLOSE_MA: *reg = valve_get_end_current_threshold_close(); break; + case REG_HOLDING_OBSTACLE_THRESHOLD_OPEN_MA: + *reg = valve_get_obstacle_threshold_open(); + break; + case REG_HOLDING_OBSTACLE_THRESHOLD_CLOSE_MA: + *reg = valve_get_obstacle_threshold_close(); + break; default: *reg = 0; break; @@ -126,6 +133,12 @@ static int holding_reg_wr(uint16_t addr, uint16_t reg) case REG_HOLDING_END_CURRENT_THRESHOLD_CLOSE_MA: valve_set_end_current_threshold_close(reg); break; + case REG_HOLDING_OBSTACLE_THRESHOLD_OPEN_MA: + valve_set_obstacle_threshold_open(reg); + break; + case REG_HOLDING_OBSTACLE_THRESHOLD_CLOSE_MA: + valve_set_obstacle_threshold_close(reg); + break; case REG_HOLDING_WATCHDOG_TIMEOUT_S: watchdog_timeout_s = reg; if (watchdog_timeout_s > 0) { @@ -188,12 +201,6 @@ static int input_reg_rd(uint16_t addr, uint16_t *reg) case REG_INPUT_FIRMWARE_VERSION_PATCH: *reg = APP_PATCHLEVEL; break; - case REG_HOLDING_END_CURRENT_THRESHOLD_OPEN_MA: - *reg = valve_get_end_current_threshold_open(); - break; - case REG_HOLDING_END_CURRENT_THRESHOLD_CLOSE_MA: - *reg = valve_get_end_current_threshold_close(); - break; default: *reg = 0; break; diff --git a/software/lib/shell_valve/shell_valve.c b/software/lib/shell_valve/shell_valve.c index 24d5d90..57291e8 100644 --- a/software/lib/shell_valve/shell_valve.c +++ b/software/lib/shell_valve/shell_valve.c @@ -55,6 +55,32 @@ static int cmd_valve_set_end_curr_close(const struct shell *sh, size_t argc, cha return 0; } +static int cmd_valve_set_obstacle_open(const struct shell *sh, size_t argc, char **argv) +{ + if (argc != 2) { + shell_print(sh, "Usage: valve set_obstacle_open "); + return -EINVAL; + } + + uint16_t current_ma = (uint16_t)atoi(argv[1]); + valve_set_obstacle_threshold_open(current_ma); + shell_print(sh, "Obstacle threshold (open) set to %u mA.", current_ma); + return 0; +} + +static int cmd_valve_set_obstacle_close(const struct shell *sh, size_t argc, char **argv) +{ + if (argc != 2) { + shell_print(sh, "Usage: valve set_obstacle_close "); + return -EINVAL; + } + + uint16_t current_ma = (uint16_t)atoi(argv[1]); + valve_set_obstacle_threshold_close(current_ma); + shell_print(sh, "Obstacle threshold (close) set to %u mA.", current_ma); + return 0; +} + static int cmd_valve_show(const struct shell *sh, size_t argc, char **argv) { const int label_width = 30; @@ -72,6 +98,16 @@ static int cmd_valve_show(const struct shell *sh, size_t argc, char **argv) label_width, "End Current Threshold (Close):", valve_get_end_current_threshold_close()); + shell_print(sh, + "%*s %u mA", + label_width, + "Obstacle Threshold (Open):", + valve_get_obstacle_threshold_open()); + shell_print(sh, + "%*s %u mA", + label_width, + "Obstacle Threshold (Close):", + valve_get_obstacle_threshold_close()); return 0; } @@ -86,6 +122,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_valve_settings, NULL, "Set end current threshold for closing (mA)", cmd_valve_set_end_curr_close), + SHELL_CMD(set_obstacle_open, + NULL, + "Set obstacle threshold for opening (mA)", + cmd_valve_set_obstacle_open), + SHELL_CMD(set_obstacle_close, + NULL, + "Set obstacle threshold for closing (mA)", + cmd_valve_set_obstacle_close), SHELL_CMD(show, NULL, "Show valve configuration", cmd_valve_show), SHELL_SUBCMD_SET_END); diff --git a/software/lib/valve/Kconfig b/software/lib/valve/Kconfig index 3798d64..2dce57d 100644 --- a/software/lib/valve/Kconfig +++ b/software/lib/valve/Kconfig @@ -11,4 +11,21 @@ config LOG_VALVE_LEVEL help Set the log level for the Valve Library. 0 = None, 1 = Error, 2 = Warning, 3 = Info, 4 = Debug + +config VALVE_OBSTACLE_THRESHOLD_OPEN_MA + int "Obstacle Threshold Open (mA)" + default 200 + help + Set the current threshold in milliamps for obstacle detection + during valve opening. If the motor current exceeds this value, + an obstacle is detected and the valve stops. + +config VALVE_OBSTACLE_THRESHOLD_CLOSE_MA + int "Obstacle Threshold Close (mA)" + default 200 + help + Set the current threshold in milliamps for obstacle detection + during valve closing. If the motor current exceeds this value, + an obstacle is detected and the valve stops. + endif # LIB_VALVE diff --git a/software/lib/valve/valve.c b/software/lib/valve/valve.c index 810af31..311de01 100644 --- a/software/lib/valve/valve.c +++ b/software/lib/valve/valve.c @@ -29,6 +29,8 @@ static uint16_t max_opening_time_s = 10; static uint16_t max_closing_time_s = 10; static uint16_t end_current_threshold_open_ma = 10; static uint16_t end_current_threshold_close_ma = 10; +static uint16_t obstacle_threshold_open_ma = CONFIG_VALVE_OBSTACLE_THRESHOLD_OPEN_MA; +static uint16_t obstacle_threshold_close_ma = CONFIG_VALVE_OBSTACLE_THRESHOLD_CLOSE_MA; static struct k_work_delayable valve_work; static struct k_timer movement_timer; @@ -48,7 +50,7 @@ static void valve_work_handler(struct k_work *work) if (current_movement == VALVE_MOVEMENT_OPENING) { vnd7050aj_read_load_current(vnd7050aj_dev, VALVE_CHANNEL_OPEN, ¤t_ma); LOG_DBG("Current load during opening: %d mA", current_ma); - if (current_ma > VALVE_OBSTACLE_THRESHOLD_OPEN_MA) { + if (current_ma > obstacle_threshold_open_ma) { LOG_ERR( "Obstacle detected during opening (current: %d mA), stopping motor.", current_ma); @@ -63,7 +65,7 @@ static void valve_work_handler(struct k_work *work) } else if (current_movement == VALVE_MOVEMENT_CLOSING) { vnd7050aj_read_load_current(vnd7050aj_dev, VALVE_CHANNEL_CLOSE, ¤t_ma); LOG_DBG("Current load during closing: %d mA", current_ma); - if (current_ma > VALVE_OBSTACLE_THRESHOLD_CLOSE_MA) { + if (current_ma > obstacle_threshold_close_ma) { LOG_ERR( "Obstacle detected during closing (current: %d mA), stopping motor.", current_ma); @@ -125,13 +127,21 @@ int valve_init(void) settings_load_one("valve/end_current_threshold_close", &end_current_threshold_close_ma, sizeof(end_current_threshold_close_ma)); + settings_load_one("valve/obstacle_threshold_open", + &obstacle_threshold_open_ma, + sizeof(obstacle_threshold_open_ma)); + settings_load_one("valve/obstacle_threshold_close", + &obstacle_threshold_close_ma, + sizeof(obstacle_threshold_close_ma)); LOG_INF("Valve initialized: max_open=%us, max_close=%us, end_curr_open=%umA, " - "end_curr_close=%umA", + "end_curr_close=%umA, obs_open=%umA, obs_close=%umA", max_opening_time_s, max_closing_time_s, end_current_threshold_open_ma, - end_current_threshold_close_ma); + end_current_threshold_close_ma, + obstacle_threshold_open_ma, + obstacle_threshold_close_ma); valve_close(); return 0; } @@ -255,3 +265,29 @@ int32_t valve_get_vnd_voltage(void) vnd7050aj_read_supply_voltage(vnd7050aj_dev, &voltage_mv); return voltage_mv; } + +void valve_set_obstacle_threshold_open(uint16_t current_ma) +{ + obstacle_threshold_open_ma = current_ma; + settings_save_one("valve/obstacle_threshold_open", + &obstacle_threshold_open_ma, + sizeof(obstacle_threshold_open_ma)); +} + +void valve_set_obstacle_threshold_close(uint16_t current_ma) +{ + obstacle_threshold_close_ma = current_ma; + settings_save_one("valve/obstacle_threshold_close", + &obstacle_threshold_close_ma, + sizeof(obstacle_threshold_close_ma)); +} + +uint16_t valve_get_obstacle_threshold_open(void) +{ + return obstacle_threshold_open_ma; +} + +uint16_t valve_get_obstacle_threshold_close(void) +{ + return obstacle_threshold_close_ma; +} diff --git a/software/tools/modbus_tool/modbus_tool.py b/software/tools/modbus_tool/modbus_tool.py index a46251d..8bf6ca1 100755 --- a/software/tools/modbus_tool/modbus_tool.py +++ b/software/tools/modbus_tool/modbus_tool.py @@ -10,31 +10,7 @@ from pymodbus.exceptions import ModbusException # --- Register Definitions --- # (omitted for brevity, no changes here) -REG_INPUT_VALVE_STATE_MOVEMENT = 0x0000 -REG_INPUT_MOTOR_OPEN_CURRENT_MA = 0x0001 -REG_INPUT_MOTOR_CLOSE_CURRENT_MA = 0x0002 -REG_INPUT_DIGITAL_INPUTS_STATE = 0x0020 -REG_INPUT_BUTTON_EVENTS = 0x0021 -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 -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 -REG_HOLDING_MAX_CLOSING_TIME_S = 0x0002 -REG_HOLDING_END_CURRENT_THRESHOLD_OPEN_MA = 0x0003 -REG_HOLDING_END_CURRENT_THRESHOLD_CLOSE_MA = 0x0004 -REG_HOLDING_DIGITAL_OUTPUTS_STATE = 0x0010 -REG_HOLDING_WATCHDOG_TIMEOUT_S = 0x00F0 -REG_HOLDING_DEVICE_RESET = 0x00F1 -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 + # --- Global State --- @@ -92,7 +68,7 @@ def poll_status(slave_id, interval): ir_current = client.read_input_registers(REG_INPUT_MOTOR_OPEN_CURRENT_MA, 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=6, slave=slave_id) - hr_valve = client.read_holding_registers(REG_HOLDING_MAX_OPENING_TIME_S, count=4, slave=slave_id) + hr_valve = client.read_holding_registers(REG_HOLDING_MAX_OPENING_TIME_S, count=6, 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) @@ -111,6 +87,8 @@ def poll_status(slave_id, interval): new_data["close_time"] = f"{hr_valve.registers[1]}s" new_data["end_curr_open"] = f"{hr_valve.registers[2]}mA" new_data["end_curr_close"] = f"{hr_valve.registers[3]}mA" + new_data["obstacle_open"] = f"{hr_valve.registers[4]}mA" + new_data["obstacle_close"] = f"{hr_valve.registers[5]}mA" new_data["digital_inputs"] = f"0x{ir_dig.registers[0]:04X}" new_data["button_events"] = f"0x{ir_dig.registers[1]:04X}" new_data["digital_outputs"] = f"0x{hr_dig.registers[0]:04X}" @@ -236,7 +214,7 @@ def main_menu(stdscr, slave_id): stdscr.bkgd(' ', curses.color_pair(1)) menu = ["Open Valve", "Close Valve", "Stop Valve", "Settings", "Reset Node", "Firmware Update", "Exit"] - settings_menu = ["Set Max Open Time", "Set Max Close Time", "Set End Current Open", "Set End Current Close", "Set Watchdog", "Back"] + settings_menu = ["Set Max Open Time", "Set Max Close Time", "Set End Current Open", "Set End Current Close", "Set Obstacle Open", "Set Obstacle Close", "Set Watchdog", "Back"] current_menu = menu current_row_idx = 0 message, message_time = "", 0 @@ -282,6 +260,10 @@ def main_menu(stdscr, slave_id): input_mode, input_prompt, input_target_reg = True, "Enter End Current Threshold Close (mA): ", REG_HOLDING_END_CURRENT_THRESHOLD_CLOSE_MA elif selected_option == "Set Watchdog": input_mode, input_prompt, input_target_reg = True, "Enter Watchdog Timeout (s): ", REG_HOLDING_WATCHDOG_TIMEOUT_S + elif selected_option == "Set Obstacle Open": + input_mode, input_prompt, input_target_reg = True, "Enter Obstacle Threshold Open (mA): ", REG_HOLDING_OBSTACLE_THRESHOLD_OPEN_MA + elif selected_option == "Set Obstacle Close": + input_mode, input_prompt, input_target_reg = True, "Enter Obstacle Threshold Close (mA): ", REG_HOLDING_OBSTACLE_THRESHOLD_CLOSE_MA elif selected_option == "Reset Node": try: client.write_register(REG_HOLDING_DEVICE_RESET, 1, slave=slave_id) @@ -319,6 +301,8 @@ def main_menu(stdscr, slave_id): stdscr.addstr(3, col3, "Watchdog:", bold); stdscr.addstr(3, col3 + 16, str(current_data.get('watchdog', 'N/A')), normal) stdscr.addstr(4, col3, "End Curr Open:", bold); stdscr.addstr(4, col3 + 16, str(current_data.get('end_curr_open', 'N/A')), normal) stdscr.addstr(5, col3, "End Curr Close:", bold); stdscr.addstr(5, col3 + 16, str(current_data.get('end_curr_close', 'N/A')), normal) + stdscr.addstr(6, col3, "Obstacle Open:", bold); stdscr.addstr(6, col3 + 16, str(current_data.get('obstacle_open', 'N/A')), normal) + stdscr.addstr(7, col3, "Obstacle Close:", bold); stdscr.addstr(7, col3 + 16, str(current_data.get('obstacle_close', 'N/A')), normal) 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)