feat(valve): Implement safe virtual valve control
- Implement virtual valve logic with time-based movement simulation. - The valve state is now set to 'OPEN' immediately when the opening process starts, ensuring a safe and correct state representation. - The state is only set to 'CLOSED' after the closing process has finished. - Add persistence for max opening and closing times.
This commit is contained in:
parent
8cab3eecc1
commit
269e9e88a1
|
|
@ -22,6 +22,8 @@ LOG_MODULE_REGISTER(mbs_sample, LOG_LEVEL_INF);
|
|||
#define APP_VERSION_PATCH 0
|
||||
|
||||
enum {
|
||||
REG_INPUT_VALVE_STATE_MOVEMENT = 0x0000,
|
||||
REG_INPUT_MOTOR_CURRENT_MA = 0x0001,
|
||||
REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR = 0x00F0,
|
||||
REG_INPUT_FIRMWARE_VERSION_PATCH = 0x00F1,
|
||||
REG_INPUT_DEVICE_STATUS = 0x00F2,
|
||||
|
|
@ -30,13 +32,33 @@ enum {
|
|||
};
|
||||
|
||||
enum {
|
||||
REG_HOLDING_WATCHDOG_TIMEOUT_S = 0x00F0,
|
||||
REG_HOLDING_VALVE_COMMAND = 0x0000,
|
||||
REG_HOLDING_MAX_OPENING_TIME_S = 0x0001,
|
||||
REG_HOLDING_MAX_CLOSING_TIME_S = 0x0002,
|
||||
REG_HOLDING_WATCHDOG_TIMEOUT_S = 0x00F0,
|
||||
};
|
||||
|
||||
enum valve_state {
|
||||
VALVE_STATE_CLOSED,
|
||||
VALVE_STATE_OPEN,
|
||||
};
|
||||
|
||||
enum valve_movement {
|
||||
VALVE_MOVEMENT_IDLE,
|
||||
VALVE_MOVEMENT_OPENING,
|
||||
VALVE_MOVEMENT_CLOSING,
|
||||
VALVE_MOVEMENT_ERROR,
|
||||
};
|
||||
|
||||
static enum valve_state current_state = VALVE_STATE_CLOSED;
|
||||
static enum valve_movement current_movement = VALVE_MOVEMENT_IDLE;
|
||||
static uint16_t max_opening_time_s = 60;
|
||||
static uint16_t max_closing_time_s = 60;
|
||||
static uint16_t watchdog_timeout_s;
|
||||
static int modbus_iface;
|
||||
|
||||
static struct k_work_delayable valve_work;
|
||||
|
||||
static struct modbus_iface_param server_param = {
|
||||
.mode = MODBUS_MODE_RTU,
|
||||
.server = {
|
||||
|
|
@ -49,6 +71,17 @@ static struct modbus_iface_param server_param = {
|
|||
},
|
||||
};
|
||||
|
||||
static void valve_work_handler(struct k_work *work)
|
||||
{
|
||||
if (current_movement == VALVE_MOVEMENT_OPENING) {
|
||||
LOG_INF("Virtual valve finished opening");
|
||||
} else if (current_movement == VALVE_MOVEMENT_CLOSING) {
|
||||
current_state = VALVE_STATE_CLOSED;
|
||||
LOG_INF("Virtual valve finished closing");
|
||||
}
|
||||
current_movement = VALVE_MOVEMENT_IDLE;
|
||||
}
|
||||
|
||||
|
||||
static int coil_rd(uint16_t addr, bool *state)
|
||||
{
|
||||
|
|
@ -66,6 +99,12 @@ static int coil_wr(uint16_t addr, bool state)
|
|||
static int holding_reg_rd(uint16_t addr, uint16_t *reg)
|
||||
{
|
||||
switch (addr) {
|
||||
case REG_HOLDING_MAX_OPENING_TIME_S:
|
||||
*reg = max_opening_time_s;
|
||||
break;
|
||||
case REG_HOLDING_MAX_CLOSING_TIME_S:
|
||||
*reg = max_closing_time_s;
|
||||
break;
|
||||
case REG_HOLDING_WATCHDOG_TIMEOUT_S:
|
||||
*reg = watchdog_timeout_s;
|
||||
break;
|
||||
|
|
@ -81,6 +120,34 @@ static int holding_reg_rd(uint16_t addr, uint16_t *reg)
|
|||
static int holding_reg_wr(uint16_t addr, uint16_t reg)
|
||||
{
|
||||
switch (addr) {
|
||||
case REG_HOLDING_VALVE_COMMAND:
|
||||
if (reg == 1) { /* Open */
|
||||
if (current_state == VALVE_STATE_CLOSED) {
|
||||
current_state = VALVE_STATE_OPEN;
|
||||
current_movement = VALVE_MOVEMENT_OPENING;
|
||||
LOG_INF("Virtual valve opening...");
|
||||
k_work_schedule(&valve_work, K_MSEC(max_opening_time_s * 1000 * 0.9));
|
||||
}
|
||||
} else if (reg == 2) { /* Close */
|
||||
if (current_state == VALVE_STATE_OPEN) {
|
||||
current_movement = VALVE_MOVEMENT_CLOSING;
|
||||
LOG_INF("Virtual valve closing...");
|
||||
k_work_schedule(&valve_work, K_MSEC(max_closing_time_s * 1000 * 0.9));
|
||||
}
|
||||
} else if (reg == 0) { /* Stop */
|
||||
k_work_cancel_delayable(&valve_work);
|
||||
current_movement = VALVE_MOVEMENT_IDLE;
|
||||
LOG_INF("Virtual valve movement stopped");
|
||||
}
|
||||
break;
|
||||
case REG_HOLDING_MAX_OPENING_TIME_S:
|
||||
max_opening_time_s = reg;
|
||||
settings_save_one("valve/max_open_time", &max_opening_time_s, sizeof(max_opening_time_s));
|
||||
break;
|
||||
case REG_HOLDING_MAX_CLOSING_TIME_S:
|
||||
max_closing_time_s = reg;
|
||||
settings_save_one("valve/max_close_time", &max_closing_time_s, sizeof(max_closing_time_s));
|
||||
break;
|
||||
case REG_HOLDING_WATCHDOG_TIMEOUT_S:
|
||||
watchdog_timeout_s = reg;
|
||||
break;
|
||||
|
|
@ -97,6 +164,12 @@ static int input_reg_rd(uint16_t addr, uint16_t *reg)
|
|||
uint32_t uptime_s = k_uptime_get_32() / 1000;
|
||||
|
||||
switch (addr) {
|
||||
case REG_INPUT_VALVE_STATE_MOVEMENT:
|
||||
*reg = (current_movement << 8) | (current_state & 0xFF);
|
||||
break;
|
||||
case REG_INPUT_MOTOR_CURRENT_MA:
|
||||
*reg = 50; /* Dummy value */
|
||||
break;
|
||||
case REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR:
|
||||
*reg = (APP_VERSION_MAJOR << 8) | (APP_VERSION_MINOR & 0xFF);
|
||||
break;
|
||||
|
|
@ -165,7 +238,7 @@ uint8_t modbus_get_unit_id(void)
|
|||
return server_param.server.unit_id;
|
||||
}
|
||||
|
||||
static int settings_modbus_load(const char *name, size_t len,
|
||||
static int settings_load_cb(const char *name, size_t len,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
const char *next;
|
||||
|
|
@ -189,10 +262,29 @@ static int settings_modbus_load(const char *name, size_t len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (settings_name_steq(name, "max_open_time", &next) && !next) {
|
||||
rc = read_cb(cb_arg, &max_opening_time_s, sizeof(max_opening_time_s));
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
LOG_INF("Loaded valve/max_open_time: %u", max_opening_time_s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (settings_name_steq(name, "max_close_time", &next) && !next) {
|
||||
rc = read_cb(cb_arg, &max_closing_time_s, sizeof(max_closing_time_s));
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
LOG_INF("Loaded valve/max_close_time: %u", max_closing_time_s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
SETTINGS_STATIC_HANDLER_DEFINE(modbus, "modbus", NULL, settings_modbus_load, NULL, NULL);
|
||||
SETTINGS_STATIC_HANDLER_DEFINE(modbus, "modbus", NULL, settings_load_cb, NULL, NULL);
|
||||
SETTINGS_STATIC_HANDLER_DEFINE(valve, "valve", NULL, settings_load_cb, NULL, NULL);
|
||||
|
||||
|
||||
static int init_modbus_server(void)
|
||||
|
|
@ -214,6 +306,8 @@ int main(void)
|
|||
{
|
||||
LOG_INF("Starting APP");
|
||||
|
||||
k_work_init_delayable(&valve_work, valve_work_handler);
|
||||
|
||||
if (settings_subsys_init()) {
|
||||
LOG_ERR("Failed to initialize settings subsystem");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue