docs: Update German documentation and project plan
- Updated Doxygen comments in header files (valve.h, fwu.h, modbus_server.h) to be consistent and in English. - Translated German register names in docs/modbus-registers.de.md to English. - Updated docs/concept.de.md to reflect new details on current measurement and sensors. - Updated docs/planning.de.md to reflect completed tasks in Phase 1.
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
add_subdirectory_ifdef(CONFIG_ADC_SENSOR adc_sensor)
|
||||
add_subdirectory_ifdef(CONFIG_LIB_FWU fwu)
|
||||
add_subdirectory_ifdef(CONFIG_LIB_MODBUS_SERVER modbus_server)
|
||||
add_subdirectory_ifdef(CONFIG_LIB_VALVE valve)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
menu "Irrigation system software libraries"
|
||||
|
||||
rsource "adc_sensor/Kconfig"
|
||||
rsource "fwu/Kconfig"
|
||||
rsource "modbus_server/Kconfig"
|
||||
rsource "valve/Kconfig"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
zephyr_library_sources(adc_sensor.c)
|
||||
@@ -1,16 +0,0 @@
|
||||
config ADC_SENSOR
|
||||
bool "ADC sensor library"
|
||||
default y
|
||||
help
|
||||
Enable ADC sensor library for voltage and current measurements.
|
||||
|
||||
if ADC_SENSOR
|
||||
|
||||
config ADC_SENSOR_SIMULATED
|
||||
bool "Use simulated ADC readings"
|
||||
default n
|
||||
help
|
||||
Use simulated values instead of real ADC readings.
|
||||
Voltage: 12000mV, Current: 45mA
|
||||
|
||||
endif # ADC_SENSOR
|
||||
@@ -1,382 +0,0 @@
|
||||
/**
|
||||
* @file adc_sensor.c
|
||||
* @brief Implementation of the ADC sensor library.
|
||||
*
|
||||
* This file contains the implementation for initializing and reading from ADC
|
||||
* sensors. It currently provides simulated values for voltage and current, with
|
||||
* placeholders for real hardware ADC implementation including GPIO control.
|
||||
*/
|
||||
|
||||
#include <lib/adc_sensor.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/drivers/adc.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(adc_sensor, LOG_LEVEL_INF);
|
||||
|
||||
// Simulated values
|
||||
#define SIMULATED_VOLTAGE_MV 12000
|
||||
#define SIMULATED_CURRENT_MA 45
|
||||
|
||||
// Devicetree node checks
|
||||
#define VOLTAGE_SENSOR_NODE DT_NODELABEL(supply_voltage)
|
||||
#define CURRENT_OPEN_SENSOR_NODE DT_NODELABEL(motor_current_open)
|
||||
#define CURRENT_CLOSE_SENSOR_NODE DT_NODELABEL(motor_current_close)
|
||||
#define VND7050AJ_NODE DT_NODELABEL(vnd7050aj)
|
||||
|
||||
#ifndef CONFIG_ADC_SENSOR_SIMULATED
|
||||
// ADC device reference from voltage sensor node (all sensors use same ADC)
|
||||
#if DT_NODE_EXISTS(VOLTAGE_SENSOR_NODE)
|
||||
#define ADC_NODE DT_PHANDLE(VOLTAGE_SENSOR_NODE, io_channels)
|
||||
#define ADC_REFERENCE_MV DT_PROP(VOLTAGE_SENSOR_NODE, reference_mv)
|
||||
#endif
|
||||
|
||||
#define ADC_CHANNEL 1 /* ADC1 channel 1 as defined in overlay */
|
||||
|
||||
// Sensor-specific properties
|
||||
#if DT_NODE_EXISTS(VOLTAGE_SENSOR_NODE)
|
||||
#define VOLTAGE_DIVIDER_RATIO \
|
||||
DT_PROP(VOLTAGE_SENSOR_NODE, voltage_divider_ratio)
|
||||
#define VOLTAGE_DELAY_MS DT_PROP(VOLTAGE_SENSOR_NODE, measurement_delay_ms)
|
||||
#endif
|
||||
|
||||
#if DT_NODE_EXISTS(CURRENT_OPEN_SENSOR_NODE)
|
||||
#define CURRENT_OPEN_SENSE_RESISTOR_MOHM \
|
||||
DT_PROP(CURRENT_OPEN_SENSOR_NODE, current_sense_resistor_mohm)
|
||||
#define CURRENT_OPEN_K_FACTOR DT_PROP(CURRENT_OPEN_SENSOR_NODE, k_factor)
|
||||
#define CURRENT_OPEN_DELAY_MS \
|
||||
DT_PROP(CURRENT_OPEN_SENSOR_NODE, measurement_delay_ms)
|
||||
#endif
|
||||
|
||||
#if DT_NODE_EXISTS(CURRENT_CLOSE_SENSOR_NODE)
|
||||
#define CURRENT_CLOSE_SENSE_RESISTOR_MOHM \
|
||||
DT_PROP(CURRENT_CLOSE_SENSOR_NODE, current_sense_resistor_mohm)
|
||||
#define CURRENT_CLOSE_K_FACTOR DT_PROP(CURRENT_CLOSE_SENSOR_NODE, k_factor)
|
||||
#define CURRENT_CLOSE_DELAY_MS \
|
||||
DT_PROP(CURRENT_CLOSE_SENSOR_NODE, measurement_delay_ms)
|
||||
#endif
|
||||
|
||||
static const struct device *adc_dev;
|
||||
static struct adc_channel_cfg adc_channel_cfg = {
|
||||
.gain = ADC_GAIN_1,
|
||||
.reference = ADC_REF_INTERNAL,
|
||||
.acquisition_time = ADC_ACQ_TIME_DEFAULT,
|
||||
.channel_id = ADC_CHANNEL,
|
||||
.differential = 0};
|
||||
|
||||
static struct adc_sequence adc_sequence = {
|
||||
.channels = BIT(ADC_CHANNEL),
|
||||
.buffer_size = sizeof(uint16_t),
|
||||
.resolution = 12,
|
||||
};
|
||||
|
||||
static uint16_t adc_buffer;
|
||||
#endif
|
||||
|
||||
static bool initialized = false;
|
||||
|
||||
#ifndef CONFIG_ADC_SENSOR_SIMULATED
|
||||
// GPIO specs from VND7050AJ node
|
||||
#if DT_NODE_EXISTS(VND7050AJ_NODE)
|
||||
static const struct gpio_dt_spec sen_gpio =
|
||||
GPIO_DT_SPEC_GET(VND7050AJ_NODE, sen_gpios);
|
||||
static const struct gpio_dt_spec s0_gpio =
|
||||
GPIO_DT_SPEC_GET(VND7050AJ_NODE, s0_gpios);
|
||||
static const struct gpio_dt_spec s1_gpio =
|
||||
GPIO_DT_SPEC_GET(VND7050AJ_NODE, s1_gpios);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configure GPIO pins for ADC sensor multiplexer control
|
||||
*/
|
||||
static int configure_sensor_gpios(void) {
|
||||
int ret = 0;
|
||||
|
||||
#if DT_NODE_EXISTS(VND7050AJ_NODE)
|
||||
// Configure sensor multiplexer GPIOs
|
||||
if (gpio_is_ready_dt(&sen_gpio)) {
|
||||
ret = gpio_pin_configure_dt(&sen_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to configure SEN GPIO: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (gpio_is_ready_dt(&s0_gpio)) {
|
||||
ret = gpio_pin_configure_dt(&s0_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to configure S0 GPIO: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (gpio_is_ready_dt(&s1_gpio)) {
|
||||
ret = gpio_pin_configure_dt(&s1_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to configure S1 GPIO: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set multiplexer channel for sensor selection
|
||||
* @param enable Enable/disable the sensor
|
||||
* @param channel Multiplexer channel (0-3)
|
||||
* @param delay_ms Delay after setting GPIOs
|
||||
*/
|
||||
static int set_mux_channel(bool enable, uint8_t channel, uint32_t delay_ms) {
|
||||
#if DT_NODE_EXISTS(VND7050AJ_NODE)
|
||||
if (gpio_is_ready_dt(&sen_gpio)) {
|
||||
gpio_pin_set_dt(&sen_gpio, enable ? 1 : 0);
|
||||
}
|
||||
if (gpio_is_ready_dt(&s0_gpio)) {
|
||||
gpio_pin_set_dt(&s0_gpio, (channel & 0x01) ? 1 : 0);
|
||||
}
|
||||
if (gpio_is_ready_dt(&s1_gpio)) {
|
||||
gpio_pin_set_dt(&s1_gpio, (channel & 0x02) ? 1 : 0);
|
||||
}
|
||||
|
||||
// Delay for GPIO settling
|
||||
if (delay_ms > 0) {
|
||||
k_msleep(delay_ms);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif /* !CONFIG_ADC_SENSOR_SIMULATED */
|
||||
|
||||
#ifndef CONFIG_ADC_SENSOR_SIMULATED
|
||||
/**
|
||||
* @brief Read ADC value and convert to millivolts (for voltage sensor)
|
||||
* @return ADC reading in millivolts, or 0 on error
|
||||
*/
|
||||
static uint16_t read_adc_voltage_mv(void) {
|
||||
#if DT_NODE_EXISTS(VOLTAGE_SENSOR_NODE)
|
||||
int ret = adc_read(adc_dev, &adc_sequence);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("ADC read failed: %d", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert ADC reading to millivolts
|
||||
// ADC reading is 12-bit (0-4095) representing 0 to ADC_REFERENCE_MV
|
||||
uint32_t adc_value = adc_buffer;
|
||||
uint32_t voltage_mv = (adc_value * ADC_REFERENCE_MV) / 4095;
|
||||
|
||||
// Apply voltage divider scaling
|
||||
voltage_mv *= VOLTAGE_DIVIDER_RATIO;
|
||||
|
||||
LOG_DBG("ADC raw: %u, voltage: %u mV", adc_value, (uint16_t)voltage_mv);
|
||||
|
||||
return (uint16_t)voltage_mv;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read ADC value and convert to milliamps for opening current
|
||||
* @return ADC reading in milliamps, or 0 on error
|
||||
*/
|
||||
static uint16_t read_adc_current_open_ma(void) {
|
||||
#if DT_NODE_EXISTS(CURRENT_OPEN_SENSOR_NODE)
|
||||
int ret = adc_read(adc_dev, &adc_sequence);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("ADC read failed: %d", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert ADC reading to millivolts first
|
||||
uint32_t adc_value = adc_buffer;
|
||||
uint32_t voltage_mv = (adc_value * ADC_REFERENCE_MV) / 4095;
|
||||
|
||||
// VND7050AJ current calculation: I = V_sense * K / R_sense
|
||||
// Where: V_sense in mV, K is the current sense factor, R_sense in mΩ
|
||||
// Result is in milliamps
|
||||
uint32_t current_ma = (voltage_mv * CURRENT_OPEN_K_FACTOR * 1000) /
|
||||
CURRENT_OPEN_SENSE_RESISTOR_MOHM;
|
||||
|
||||
LOG_DBG("Open current - ADC raw: %u, voltage: %u mV, current: %u mA",
|
||||
adc_value, voltage_mv, (uint16_t)current_ma);
|
||||
|
||||
return (uint16_t)current_ma;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read ADC value and convert to milliamps for closing current
|
||||
* @return ADC reading in milliamps, or 0 on error
|
||||
*/
|
||||
static uint16_t read_adc_current_close_ma(void) {
|
||||
#if DT_NODE_EXISTS(CURRENT_CLOSE_SENSOR_NODE)
|
||||
int ret = adc_read(adc_dev, &adc_sequence);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("ADC read failed: %d", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert ADC reading to millivolts first
|
||||
uint32_t adc_value = adc_buffer;
|
||||
uint32_t voltage_mv = (adc_value * ADC_REFERENCE_MV) / 4095;
|
||||
|
||||
// VND7050AJ current calculation: I = V_sense * K / R_sense
|
||||
// Where: V_sense in mV, K is the current sense factor, R_sense in mΩ
|
||||
// Result is in milliamps
|
||||
uint32_t current_ma = (voltage_mv * CURRENT_CLOSE_K_FACTOR * 1000) /
|
||||
CURRENT_CLOSE_SENSE_RESISTOR_MOHM;
|
||||
|
||||
LOG_DBG("Close current - ADC raw: %u, voltage: %u mV, current: %u mA",
|
||||
adc_value, voltage_mv, (uint16_t)current_ma);
|
||||
|
||||
return (uint16_t)current_ma;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int adc_sensor_init(void) {
|
||||
if (initialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ADC_SENSOR_SIMULATED
|
||||
LOG_INF("ADC sensor initialized (simulated mode)");
|
||||
LOG_INF("Simulated values: %dmV, %dmA", SIMULATED_VOLTAGE_MV,
|
||||
SIMULATED_CURRENT_MA);
|
||||
#else
|
||||
// Initialize GPIO pins for sensor control
|
||||
int ret = configure_sensor_gpios();
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to configure sensor GPIOs: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Initialize ADC hardware
|
||||
#if DT_NODE_EXISTS(VOLTAGE_SENSOR_NODE)
|
||||
adc_dev = DEVICE_DT_GET(ADC_NODE);
|
||||
if (!device_is_ready(adc_dev)) {
|
||||
LOG_ERR("ADC device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
adc_sequence.buffer = &adc_buffer;
|
||||
|
||||
ret = adc_channel_setup(adc_dev, &adc_channel_cfg);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to setup ADC channel: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_INF("ADC device ready: %s", adc_dev->name);
|
||||
#endif
|
||||
|
||||
LOG_INF("ADC sensor initialized (real ADC mode)");
|
||||
|
||||
#if DT_NODE_EXISTS(VOLTAGE_SENSOR_NODE)
|
||||
LOG_INF("Voltage sensor: divider ratio %d", VOLTAGE_DIVIDER_RATIO);
|
||||
#endif
|
||||
#if DT_NODE_EXISTS(CURRENT_OPEN_SENSOR_NODE)
|
||||
LOG_INF("Open current sensor: K-factor %d, sense resistor %d mΩ",
|
||||
CURRENT_OPEN_K_FACTOR, CURRENT_OPEN_SENSE_RESISTOR_MOHM);
|
||||
#endif
|
||||
#if DT_NODE_EXISTS(CURRENT_CLOSE_SENSOR_NODE)
|
||||
LOG_INF("Close current sensor: K-factor %d, sense resistor %d mΩ",
|
||||
CURRENT_CLOSE_K_FACTOR, CURRENT_CLOSE_SENSE_RESISTOR_MOHM);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t adc_sensor_get_voltage_mv(void) {
|
||||
if (!initialized) {
|
||||
LOG_WRN("ADC sensor not initialized, calling adc_sensor_init()");
|
||||
adc_sensor_init();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ADC_SENSOR_SIMULATED
|
||||
return SIMULATED_VOLTAGE_MV;
|
||||
#else
|
||||
// Set multiplexer to voltage channel (channel 3: VCC sense)
|
||||
#if DT_NODE_EXISTS(VOLTAGE_SENSOR_NODE)
|
||||
set_mux_channel(true, 3, VOLTAGE_DELAY_MS);
|
||||
|
||||
// Read real ADC value for voltage
|
||||
uint16_t voltage = read_adc_voltage_mv();
|
||||
|
||||
// Disable sensor after measurement to save power
|
||||
set_mux_channel(false, 0, 0);
|
||||
|
||||
return voltage;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t adc_sensor_get_current_ma(void) {
|
||||
// Legacy function - redirect to opening current for backward compatibility
|
||||
return adc_sensor_get_current_open_ma();
|
||||
}
|
||||
|
||||
uint16_t adc_sensor_get_current_open_ma(void) {
|
||||
if (!initialized) {
|
||||
LOG_WRN("ADC sensor not initialized, calling adc_sensor_init()");
|
||||
adc_sensor_init();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ADC_SENSOR_SIMULATED
|
||||
return SIMULATED_CURRENT_MA;
|
||||
#else
|
||||
// Set multiplexer to IN0 current sense channel (channel 0)
|
||||
#if DT_NODE_EXISTS(CURRENT_OPEN_SENSOR_NODE)
|
||||
set_mux_channel(true, 0, CURRENT_OPEN_DELAY_MS);
|
||||
|
||||
// Read real ADC value for current
|
||||
uint16_t current = read_adc_current_open_ma();
|
||||
|
||||
// Disable sensor after measurement to save power
|
||||
set_mux_channel(false, 0, 0);
|
||||
|
||||
return current;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t adc_sensor_get_current_close_ma(void) {
|
||||
if (!initialized) {
|
||||
LOG_WRN("ADC sensor not initialized, calling adc_sensor_init()");
|
||||
adc_sensor_init();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ADC_SENSOR_SIMULATED
|
||||
return SIMULATED_CURRENT_MA;
|
||||
#else
|
||||
// Set multiplexer to IN1 current sense channel (channel 1)
|
||||
#if DT_NODE_EXISTS(CURRENT_CLOSE_SENSOR_NODE)
|
||||
set_mux_channel(true, 1, CURRENT_CLOSE_DELAY_MS);
|
||||
|
||||
// Read real ADC value for current
|
||||
uint16_t current = read_adc_current_close_ma();
|
||||
|
||||
// Disable sensor after measurement to save power
|
||||
set_mux_channel(false, 0, 0);
|
||||
|
||||
return current;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -8,11 +8,11 @@
|
||||
*/
|
||||
|
||||
#include <app_version.h>
|
||||
#include <lib/adc_sensor.h>
|
||||
#include <lib/fwu.h>
|
||||
#include <lib/modbus_server.h>
|
||||
#include <lib/valve.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/misc/vnd7050aj/vnd7050aj.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
@@ -148,10 +148,10 @@ static int input_reg_rd(uint16_t addr, uint16_t *reg) {
|
||||
*reg = (valve_get_movement() << 8) | (valve_get_state() & 0xFF);
|
||||
break;
|
||||
case REG_INPUT_MOTOR_OPEN_CURRENT_MA:
|
||||
*reg = adc_sensor_get_current_open_ma();
|
||||
*reg = (uint16_t)valve_get_opening_current();
|
||||
break;
|
||||
case REG_INPUT_MOTOR_CLOSE_CURRENT_MA:
|
||||
*reg = adc_sensor_get_current_close_ma();
|
||||
*reg = (uint16_t)valve_get_closing_current();
|
||||
break;
|
||||
case REG_INPUT_UPTIME_SECONDS_LOW:
|
||||
*reg = (uint16_t)(uptime_s & 0xFFFF);
|
||||
@@ -160,7 +160,7 @@ static int input_reg_rd(uint16_t addr, uint16_t *reg) {
|
||||
*reg = (uint16_t)(uptime_s >> 16);
|
||||
break;
|
||||
case REG_INPUT_SUPPLY_VOLTAGE_MV:
|
||||
*reg = adc_sensor_get_voltage_mv();
|
||||
*reg = (uint16_t)valve_get_vnd_voltage();
|
||||
break;
|
||||
case REG_INPUT_FWU_LAST_CHUNK_CRC:
|
||||
*reg = fwu_get_last_chunk_crc();
|
||||
@@ -190,13 +190,6 @@ static struct modbus_user_callbacks mbs_cbs = {
|
||||
int modbus_server_init(void) {
|
||||
k_timer_init(&watchdog_timer, watchdog_timer_handler, NULL);
|
||||
|
||||
// Initialize ADC sensor
|
||||
int ret = adc_sensor_init();
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to initialize ADC sensor: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Load saved settings
|
||||
uint32_t saved_baudrate = 19200;
|
||||
uint8_t saved_unit_id = 1;
|
||||
|
||||
@@ -10,25 +10,24 @@
|
||||
#include <lib/valve.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/misc/vnd7050aj/vnd7050aj.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/settings/settings.h>
|
||||
|
||||
#define VND_NODE DT_ALIAS(vnd7050aj)
|
||||
#if !DT_NODE_HAS_STATUS(VND_NODE, okay)
|
||||
#error VND7050AJ node is not defined or enabled
|
||||
#endif
|
||||
const struct device *vnd7050aj_dev = DEVICE_DT_GET(VND_NODE);
|
||||
|
||||
LOG_MODULE_REGISTER(valve, LOG_LEVEL_INF);
|
||||
|
||||
static const struct valve_gpios valve_gpios = {
|
||||
.in0 = GPIO_DT_SPEC_GET(DT_NODELABEL(vnd7050aj), in0_gpios),
|
||||
.in1 = GPIO_DT_SPEC_GET(DT_NODELABEL(vnd7050aj), in1_gpios),
|
||||
.rst = GPIO_DT_SPEC_GET(DT_NODELABEL(vnd7050aj), rst_gpios),
|
||||
.sen = GPIO_DT_SPEC_GET(DT_NODELABEL(vnd7050aj), sen_gpios),
|
||||
.s0 = GPIO_DT_SPEC_GET(DT_NODELABEL(vnd7050aj), s0_gpios),
|
||||
.s1 = GPIO_DT_SPEC_GET(DT_NODELABEL(vnd7050aj), s1_gpios),
|
||||
};
|
||||
|
||||
static enum valve_state current_state = VALVE_STATE_CLOSED;
|
||||
static enum valve_state current_state = VALVE_STATE_OPEN;
|
||||
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 max_opening_time_s = 10;
|
||||
static uint16_t max_closing_time_s = 10;
|
||||
static uint32_t movement_start_time = 0;
|
||||
static struct k_work_delayable
|
||||
valve_work; // Work item for scheduling valve movement timeouts
|
||||
|
||||
@@ -41,63 +40,85 @@ static struct k_work_delayable
|
||||
* @param work Pointer to the k_work item.
|
||||
*/
|
||||
static void valve_work_handler(struct k_work *work) {
|
||||
gpio_pin_set_dt(&valve_gpios.in0, 0);
|
||||
gpio_pin_set_dt(&valve_gpios.in1, 0);
|
||||
gpio_pin_set_dt(&valve_gpios.rst, 0);
|
||||
|
||||
int current_ma = 0;
|
||||
uint32_t now;
|
||||
now = k_uptime_get_32();
|
||||
if (current_movement == VALVE_MOVEMENT_OPENING) {
|
||||
if (now - movement_start_time > max_opening_time_s * 1000) {
|
||||
LOG_WRN("Valve opening timeout reached, stopping motor.");
|
||||
current_movement = VALVE_MOVEMENT_ERROR;
|
||||
goto work_handler_finish;
|
||||
}
|
||||
vnd7050aj_read_load_current(vnd7050aj_dev, VALVE_CHANNEL_OPEN, ¤t_ma);
|
||||
if (current_ma > 10) {
|
||||
k_work_schedule(&valve_work, VALVE_ENDPOSITION_CHECK_INTERVAL);
|
||||
return;
|
||||
}
|
||||
LOG_INF("Valve finished opening");
|
||||
} else if (current_movement == VALVE_MOVEMENT_CLOSING) {
|
||||
if (now - movement_start_time > max_closing_time_s * 1000) {
|
||||
LOG_WRN("Valve closing timeout reached, stopping motor.");
|
||||
current_movement = VALVE_MOVEMENT_ERROR;
|
||||
goto work_handler_finish;
|
||||
}
|
||||
vnd7050aj_read_load_current(vnd7050aj_dev, VALVE_CHANNEL_CLOSE,
|
||||
¤t_ma);
|
||||
if (current_ma > 10) {
|
||||
k_work_schedule(&valve_work, VALVE_ENDPOSITION_CHECK_INTERVAL);
|
||||
return;
|
||||
}
|
||||
current_state = VALVE_STATE_CLOSED;
|
||||
LOG_INF("Valve finished closing");
|
||||
}
|
||||
current_movement = VALVE_MOVEMENT_IDLE;
|
||||
work_handler_finish:
|
||||
vnd7050aj_set_output_state(vnd7050aj_dev, VALVE_CHANNEL_OPEN, false);
|
||||
vnd7050aj_set_output_state(vnd7050aj_dev, VALVE_CHANNEL_CLOSE, false);
|
||||
LOG_INF("Valve work handler finished. Current state: %d, Movement: %d",
|
||||
current_state, current_movement);
|
||||
}
|
||||
|
||||
void valve_init(void) {
|
||||
int valve_init(void) {
|
||||
if (!device_is_ready(vnd7050aj_dev)) {
|
||||
LOG_ERR("VND7050AJ device is not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
k_work_init_delayable(&valve_work, valve_work_handler);
|
||||
settings_load_one("valve/max_open_time", &max_opening_time_s,
|
||||
sizeof(max_opening_time_s));
|
||||
settings_load_one("valve/max_close_time", &max_closing_time_s,
|
||||
sizeof(max_closing_time_s));
|
||||
|
||||
gpio_pin_configure_dt(&valve_gpios.in0, GPIO_OUTPUT_INACTIVE);
|
||||
gpio_pin_configure_dt(&valve_gpios.in1, GPIO_OUTPUT_INACTIVE);
|
||||
gpio_pin_configure_dt(&valve_gpios.rst,
|
||||
GPIO_OUTPUT_ACTIVE); // Keep VND7050AJ out of reset
|
||||
gpio_pin_configure_dt(&valve_gpios.sen, GPIO_OUTPUT_INACTIVE);
|
||||
gpio_pin_configure_dt(&valve_gpios.s0,
|
||||
GPIO_OUTPUT_INACTIVE); // S0 select pin - output
|
||||
gpio_pin_configure_dt(&valve_gpios.s1,
|
||||
GPIO_OUTPUT_INACTIVE); // S1 select pin - output
|
||||
|
||||
LOG_INF("Valve initialized: max_open=%us, max_close=%us", max_opening_time_s,
|
||||
max_closing_time_s);
|
||||
valve_close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void valve_open(void) {
|
||||
if (current_state == VALVE_STATE_CLOSED) {
|
||||
gpio_pin_set_dt(&valve_gpios.rst, 1);
|
||||
gpio_pin_set_dt(&valve_gpios.in0, 1);
|
||||
gpio_pin_set_dt(&valve_gpios.in1, 0);
|
||||
current_state = VALVE_STATE_OPEN;
|
||||
current_movement = VALVE_MOVEMENT_OPENING;
|
||||
k_work_schedule(&valve_work, K_MSEC(max_opening_time_s * 1000 * 0.9));
|
||||
}
|
||||
vnd7050aj_reset_fault(vnd7050aj_dev);
|
||||
vnd7050aj_set_output_state(vnd7050aj_dev, VALVE_CHANNEL_CLOSE, false);
|
||||
vnd7050aj_set_output_state(vnd7050aj_dev, VALVE_CHANNEL_OPEN, true);
|
||||
current_state = VALVE_STATE_OPEN;
|
||||
current_movement = VALVE_MOVEMENT_OPENING; /* Security: assume valve open as
|
||||
soons as it starts opening */
|
||||
movement_start_time = k_uptime_get_32();
|
||||
k_work_schedule(&valve_work, K_MSEC(100));
|
||||
}
|
||||
|
||||
void valve_close(void) {
|
||||
if (current_state == VALVE_STATE_OPEN) {
|
||||
gpio_pin_set_dt(&valve_gpios.rst, 1);
|
||||
gpio_pin_set_dt(&valve_gpios.in0, 0);
|
||||
gpio_pin_set_dt(&valve_gpios.in1, 1);
|
||||
current_movement = VALVE_MOVEMENT_CLOSING;
|
||||
k_work_schedule(&valve_work, K_MSEC(max_closing_time_s * 1000 * 0.9));
|
||||
}
|
||||
vnd7050aj_reset_fault(vnd7050aj_dev);
|
||||
vnd7050aj_set_output_state(vnd7050aj_dev, VALVE_CHANNEL_OPEN, false);
|
||||
vnd7050aj_set_output_state(vnd7050aj_dev, VALVE_CHANNEL_CLOSE, true);
|
||||
movement_start_time = k_uptime_get_32();
|
||||
current_movement = VALVE_MOVEMENT_CLOSING;
|
||||
k_work_schedule(&valve_work, VALVE_ENDPOSITION_CHECK_INTERVAL);
|
||||
}
|
||||
|
||||
void valve_stop(void) {
|
||||
k_work_cancel_delayable(&valve_work);
|
||||
vnd7050aj_set_output_state(vnd7050aj_dev, VALVE_CHANNEL_OPEN, false);
|
||||
vnd7050aj_set_output_state(vnd7050aj_dev, VALVE_CHANNEL_CLOSE, false);
|
||||
current_movement = VALVE_MOVEMENT_IDLE;
|
||||
}
|
||||
|
||||
@@ -119,3 +140,27 @@ void valve_set_max_close_time(uint16_t seconds) {
|
||||
}
|
||||
uint16_t valve_get_max_open_time(void) { return max_opening_time_s; }
|
||||
uint16_t valve_get_max_close_time(void) { return max_closing_time_s; }
|
||||
|
||||
int32_t valve_get_opening_current(void) {
|
||||
int32_t current;
|
||||
vnd7050aj_read_load_current(vnd7050aj_dev, VALVE_CHANNEL_OPEN, ¤t);
|
||||
return current;
|
||||
}
|
||||
|
||||
int32_t valve_get_closing_current(void) {
|
||||
int32_t current;
|
||||
vnd7050aj_read_load_current(vnd7050aj_dev, VALVE_CHANNEL_CLOSE, ¤t);
|
||||
return current;
|
||||
}
|
||||
|
||||
int32_t valve_get_vnd_temp(void) {
|
||||
int32_t temp_c;
|
||||
vnd7050aj_read_chip_temp(vnd7050aj_dev, &temp_c);
|
||||
return temp_c;
|
||||
}
|
||||
|
||||
int32_t valve_get_vnd_voltage(void) {
|
||||
int32_t voltage_mv;
|
||||
vnd7050aj_read_supply_voltage(vnd7050aj_dev, &voltage_mv);
|
||||
return voltage_mv;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user