style: Apply clang-format to C/C++ source files

Applied consistent code formatting using clang-format to all C/C++ source
and header files in the 'software/' directory.
This commit is contained in:
Eduard Iten 2025-07-10 23:33:50 +02:00
parent 8f89713866
commit bd8a7a766c
10 changed files with 580 additions and 428 deletions

View File

@ -1,5 +1,142 @@
# .clang-format # Zephyr Project .clang-format configuration
BasedOnStyle: Google # Based on Linux kernel style with Zephyr-specific adaptations
#IndentWidth: 4
#ColumnLimit: 100 # Use LLVM as the base style and customize from there
#AllowShortFunctionsOnASingleLine: None BasedOnStyle: LLVM
# Language settings
Language: Cpp
# Indentation settings
IndentWidth: 8
TabWidth: 8
UseTab: ForIndentation
# Line length
ColumnLimit: 100
# Brace settings
BreakBeforeBraces: Linux
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
# Always add braces for control statements (Zephyr requirement)
RemoveBracesLLVM: false
# Control statement settings
SpaceBeforeParens: ControlStatements
SpacesInParentheses: false
# Function settings
AllowShortFunctionsOnASingleLine: None
AllowShortBlocksOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
# Pointer and reference alignment
PointerAlignment: Right
ReferenceAlignment: Right
# Spacing settings
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInSquareBrackets: false
# Alignment settings
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: false
AlignTrailingComments: false
# Breaking settings
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
# Penalties (used for line breaking decisions)
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
# Comment settings
ReflowComments: true
CommentPragmas: '^ IWYU pragma:'
# Sorting settings
SortIncludes: true
SortUsingDeclarations: true
# Preprocessor settings
IndentPPDirectives: None
MacroBlockBegin: ''
MacroBlockEnd: ''
# Misc settings
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros: ['LISTIFY', 'FOR_EACH', 'FOR_EACH_FIXED_ARG', 'FOR_EACH_IDX', 'FOR_EACH_IDX_FIXED_ARG', 'FOR_EACH_NONEMPTY_TERM', 'Z_FOR_EACH', 'Z_FOR_EACH_FIXED_ARG', 'Z_FOR_EACH_IDX', 'Z_FOR_EACH_IDX_FIXED_ARG']
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^<zephyr/.*\.h>'
Priority: 1
- Regex: '^<.*\.h>'
Priority: 2
- Regex: '^<.*'
Priority: 3
- Regex: '.*'
Priority: 4
IndentCaseLabels: false
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true

View File

@ -6,7 +6,8 @@
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
int main(void) { int main(void)
printk("Hello from Gateway!\n"); {
return 0; printk("Hello from Gateway!\n");
return 0;
} }

View File

@ -1,27 +1,28 @@
#include <lib/fwu.h>
#include <lib/modbus_server.h>
#include <lib/valve.h>
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/settings/settings.h> #include <zephyr/settings/settings.h>
#include <lib/fwu.h>
#include <lib/modbus_server.h>
#include <lib/valve.h>
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF); LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
int main(void) { int main(void)
LOG_INF("Starting Irrigation System Slave Node"); {
LOG_INF("Starting Irrigation System Slave Node");
if (settings_subsys_init() || settings_load()) { if (settings_subsys_init() || settings_load()) {
LOG_ERR("Settings initialization or loading failed"); LOG_ERR("Settings initialization or loading failed");
} }
valve_init(); valve_init();
fwu_init(); fwu_init();
if (modbus_server_init()) { if (modbus_server_init()) {
LOG_ERR("Modbus RTU server initialization failed"); LOG_ERR("Modbus RTU server initialization failed");
return 0; return 0;
} }
LOG_INF("Irrigation System Slave Node started successfully"); LOG_INF("Irrigation System Slave Node started successfully");
return 0; return 0;
} }

View File

@ -44,4 +44,4 @@ void fwu_handler(uint16_t addr, uint16_t reg);
*/ */
uint16_t fwu_get_last_chunk_crc(void); uint16_t fwu_get_last_chunk_crc(void);
#endif // FWU_H #endif // FWU_H

View File

@ -16,59 +16,59 @@
* @see docs/modbus-registers.de.md * @see docs/modbus-registers.de.md
*/ */
enum { enum {
/** /**
* @brief Combined status register for the valve. * @brief Combined status register for the valve.
* High-Byte: Movement (0=Idle, 1=Opening, 2=Closing, 3=Error). * High-Byte: Movement (0=Idle, 1=Opening, 2=Closing, 3=Error).
* Low-Byte: State (0=Closed, 1=Open). * Low-Byte: State (0=Closed, 1=Open).
*/ */
REG_INPUT_VALVE_STATE_MOVEMENT = 0x0000, REG_INPUT_VALVE_STATE_MOVEMENT = 0x0000,
/** /**
* @brief Motor current during opening in milliamperes (mA). * @brief Motor current during opening in milliamperes (mA).
*/ */
REG_INPUT_MOTOR_OPEN_CURRENT_MA = 0x0001, REG_INPUT_MOTOR_OPEN_CURRENT_MA = 0x0001,
/** /**
* @brief Motor current during closing in milliamperes (mA). * @brief Motor current during closing in milliamperes (mA).
*/ */
REG_INPUT_MOTOR_CLOSE_CURRENT_MA = 0x0002, REG_INPUT_MOTOR_CLOSE_CURRENT_MA = 0x0002,
/** /**
* @brief Bitmask of digital inputs. Bit 0: Input 1, Bit 1: Input 2. * @brief Bitmask of digital inputs. Bit 0: Input 1, Bit 1: Input 2.
* 1=Active. * 1=Active.
*/ */
REG_INPUT_DIGITAL_INPUTS_STATE = 0x0020, REG_INPUT_DIGITAL_INPUTS_STATE = 0x0020,
/** /**
* @brief Event flags for buttons (Clear-on-Read). Bit 0: Button 1 pressed. * @brief Event flags for buttons (Clear-on-Read). Bit 0: Button 1 pressed.
* Bit 1: Button 2 pressed. * Bit 1: Button 2 pressed.
*/ */
REG_INPUT_BUTTON_EVENTS = 0x0021, REG_INPUT_BUTTON_EVENTS = 0x0021,
/** /**
* @brief Firmware version, e.g., 0x0102 for v1.2. * @brief Firmware version, e.g., 0x0102 for v1.2.
*/ */
REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR = 0x00F0, REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR = 0x00F0,
/** /**
* @brief Firmware version patch level, e.g., 3 for v1.2.3. * @brief Firmware version patch level, e.g., 3 for v1.2.3.
*/ */
REG_INPUT_FIRMWARE_VERSION_PATCH = 0x00F1, REG_INPUT_FIRMWARE_VERSION_PATCH = 0x00F1,
/** /**
* @brief Device status (0=OK, 1=General Error). * @brief Device status (0=OK, 1=General Error).
*/ */
REG_INPUT_DEVICE_STATUS = 0x00F2, REG_INPUT_DEVICE_STATUS = 0x00F2,
/** /**
* @brief Lower 16 bits of uptime in seconds. * @brief Lower 16 bits of uptime in seconds.
*/ */
REG_INPUT_UPTIME_SECONDS_LOW = 0x00F3, REG_INPUT_UPTIME_SECONDS_LOW = 0x00F3,
/** /**
* @brief Upper 16 bits of uptime in seconds. * @brief Upper 16 bits of uptime in seconds.
*/ */
REG_INPUT_UPTIME_SECONDS_HIGH = 0x00F4, REG_INPUT_UPTIME_SECONDS_HIGH = 0x00F4,
/** /**
* @brief Current supply voltage in millivolts (mV). * @brief Current supply voltage in millivolts (mV).
*/ */
REG_INPUT_SUPPLY_VOLTAGE_MV = 0x00F5, REG_INPUT_SUPPLY_VOLTAGE_MV = 0x00F5,
/** /**
* @brief CRC16 of the last received data chunk in the buffer for firmware * @brief CRC16 of the last received data chunk in the buffer for firmware
* update. * update.
*/ */
REG_INPUT_FWU_LAST_CHUNK_CRC = 0x0100 REG_INPUT_FWU_LAST_CHUNK_CRC = 0x0100
}; };
/** /**
@ -76,55 +76,55 @@ enum {
* @see docs/modbus-registers.de.md * @see docs/modbus-registers.de.md
*/ */
enum { enum {
/** /**
* @brief Valve control command (1=Open, 2=Close, 0=Stop movement). * @brief Valve control command (1=Open, 2=Close, 0=Stop movement).
*/ */
REG_HOLDING_VALVE_COMMAND = 0x0000, REG_HOLDING_VALVE_COMMAND = 0x0000,
/** /**
* @brief Safety timeout in seconds for the opening process. * @brief Safety timeout in seconds for the opening process.
*/ */
REG_HOLDING_MAX_OPENING_TIME_S = 0x0001, REG_HOLDING_MAX_OPENING_TIME_S = 0x0001,
/** /**
* @brief Safety timeout in seconds for the closing process. * @brief Safety timeout in seconds for the closing process.
*/ */
REG_HOLDING_MAX_CLOSING_TIME_S = 0x0002, REG_HOLDING_MAX_CLOSING_TIME_S = 0x0002,
/** /**
* @brief Bitmask for reading and writing digital outputs. Bit 0: Output 1, * @brief Bitmask for reading and writing digital outputs. Bit 0: Output 1,
* Bit 1: Output 2. 1=ON, 0=OFF. * Bit 1: Output 2. 1=ON, 0=OFF.
*/ */
REG_HOLDING_DIGITAL_OUTPUTS_STATE = 0x0010, REG_HOLDING_DIGITAL_OUTPUTS_STATE = 0x0010,
/** /**
* @brief Fail-safe watchdog timeout in seconds. 0=Disabled. * @brief Fail-safe watchdog timeout in seconds. 0=Disabled.
*/ */
REG_HOLDING_WATCHDOG_TIMEOUT_S = 0x00F0, REG_HOLDING_WATCHDOG_TIMEOUT_S = 0x00F0,
/** /**
* @brief Writing 1 restarts the device. * @brief Writing 1 restarts the device.
*/ */
REG_HOLDING_DEVICE_RESET = 0x00F1, REG_HOLDING_DEVICE_RESET = 0x00F1,
/** /**
* @brief Command for firmware update. * @brief Command for firmware update.
* 1: Verify Chunk - Slave writes the last chunk to flash. * 1: Verify Chunk - Slave writes the last chunk to flash.
* 2: Finalize Update - Complete installation and restart. * 2: Finalize Update - Complete installation and restart.
*/ */
REG_HOLDING_FWU_COMMAND = 0x0100, REG_HOLDING_FWU_COMMAND = 0x0100,
/** /**
* @brief Lower 16 bits of the 32-bit offset for the next firmware update * @brief Lower 16 bits of the 32-bit offset for the next firmware update
* chunk. * chunk.
*/ */
REG_HOLDING_FWU_CHUNK_OFFSET_LOW = 0x0101, REG_HOLDING_FWU_CHUNK_OFFSET_LOW = 0x0101,
/** /**
* @brief Upper 16 bits of the 32-bit offset for the next firmware update * @brief Upper 16 bits of the 32-bit offset for the next firmware update
* chunk. * chunk.
*/ */
REG_HOLDING_FWU_CHUNK_OFFSET_HIGH = 0x0102, REG_HOLDING_FWU_CHUNK_OFFSET_HIGH = 0x0102,
/** /**
* @brief Size of the next firmware update chunk in bytes (max. 256). * @brief Size of the next firmware update chunk in bytes (max. 256).
*/ */
REG_HOLDING_FWU_CHUNK_SIZE = 0x0103, REG_HOLDING_FWU_CHUNK_SIZE = 0x0103,
/** /**
* @brief Start address of the 256-byte buffer for firmware update data. * @brief Start address of the 256-byte buffer for firmware update data.
*/ */
REG_HOLDING_FWU_DATA_BUFFER = 0x0180, REG_HOLDING_FWU_DATA_BUFFER = 0x0180,
}; };
/** /**
@ -165,4 +165,4 @@ uint32_t modbus_get_baudrate(void);
*/ */
uint8_t modbus_get_unit_id(void); uint8_t modbus_get_unit_id(void);
#endif // MODBUS_SERVER_H #endif // MODBUS_SERVER_H

View File

@ -1,8 +1,8 @@
#ifndef VALVE_H #ifndef VALVE_H
#define VALVE_H #define VALVE_H
#include <stdint.h>
#include <zephyr/drivers/gpio.h> #include <zephyr/drivers/gpio.h>
#include <stdint.h>
/** /**
* @file valve.h * @file valve.h
@ -21,18 +21,18 @@
* @brief Represents the static state of the valve (open or closed). * @brief Represents the static state of the valve (open or closed).
*/ */
enum valve_state { enum valve_state {
VALVE_STATE_CLOSED, /**< The valve is fully closed. */ VALVE_STATE_CLOSED, /**< The valve is fully closed. */
VALVE_STATE_OPEN, /**< The valve is fully open. */ VALVE_STATE_OPEN, /**< The valve is fully open. */
}; };
/** /**
* @brief Represents the dynamic movement status of the valve. * @brief Represents the dynamic movement status of the valve.
*/ */
enum valve_movement { enum valve_movement {
VALVE_MOVEMENT_IDLE, /**< The valve is not moving. */ VALVE_MOVEMENT_IDLE, /**< The valve is not moving. */
VALVE_MOVEMENT_OPENING, /**< The valve is currently opening. */ VALVE_MOVEMENT_OPENING, /**< The valve is currently opening. */
VALVE_MOVEMENT_CLOSING, /**< The valve is currently closing. */ VALVE_MOVEMENT_CLOSING, /**< The valve is currently closing. */
VALVE_MOVEMENT_ERROR /**< An error occurred during movement. */ VALVE_MOVEMENT_ERROR /**< An error occurred during movement. */
}; };
/** /**
@ -140,4 +140,4 @@ int32_t valve_get_vnd_temp(void);
* @return The voltage in millivolts. * @return The voltage in millivolts.
*/ */
int32_t valve_get_vnd_voltage(void); int32_t valve_get_vnd_voltage(void);
#endif // VALVE_H #endif // VALVE_H

View File

@ -8,51 +8,57 @@
* the update process. The actual writing to flash is simulated. * the update process. The actual writing to flash is simulated.
*/ */
#include <lib/fwu.h>
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/sys/crc.h> #include <zephyr/sys/crc.h>
#include <lib/fwu.h>
LOG_MODULE_REGISTER(fwu, LOG_LEVEL_INF); LOG_MODULE_REGISTER(fwu, LOG_LEVEL_INF);
#define FWU_BUFFER_SIZE 256 #define FWU_BUFFER_SIZE 256
static uint8_t fwu_buffer[FWU_BUFFER_SIZE]; // Buffer to store incoming static uint8_t fwu_buffer[FWU_BUFFER_SIZE]; // Buffer to store incoming
// firmware data chunks // firmware data chunks
static uint32_t fwu_chunk_offset = static uint32_t fwu_chunk_offset = 0; // Offset for the current firmware chunk in the overall image
0; // Offset for the current firmware chunk in the overall image static uint16_t fwu_chunk_size = 0; // Size of the current firmware chunk
static uint16_t fwu_chunk_size = 0; // Size of the current firmware chunk static uint16_t fwu_last_chunk_crc = 0; // CRC16 of the last received firmware chunk
static uint16_t fwu_last_chunk_crc =
0; // CRC16 of the last received firmware chunk
void fwu_init(void) {} void fwu_init(void)
{
void fwu_handler(uint16_t addr, uint16_t reg) {
// This is a simplified handler. In a real scenario, you would have a proper
// mapping between register addresses and actions.
if (addr == 0x0100) { // FWU_COMMAND
if (reg == 1) {
LOG_INF("FWU: Chunk at offset %u (size %u) verified.", fwu_chunk_offset,
fwu_chunk_size);
} else if (reg == 2) {
LOG_INF("FWU: Finalize command received. Rebooting (simulated).");
}
} else if (addr == 0x0101) { // FWU_CHUNK_OFFSET_LOW
fwu_chunk_offset = (fwu_chunk_offset & 0xFFFF0000) | reg;
} else if (addr == 0x0102) { // FWU_CHUNK_OFFSET_HIGH
fwu_chunk_offset = (fwu_chunk_offset & 0x0000FFFF) | ((uint32_t)reg << 16);
} else if (addr == 0x0103) { // FWU_CHUNK_SIZE
fwu_chunk_size = (reg > FWU_BUFFER_SIZE) ? FWU_BUFFER_SIZE : reg;
} else if (addr >= 0x0180 && addr < (0x0180 + (FWU_BUFFER_SIZE / 2))) {
uint16_t index = (addr - 0x0180) * 2;
if (index < sizeof(fwu_buffer)) {
sys_put_be16(reg, &fwu_buffer[index]);
if (index + 2 >= fwu_chunk_size) {
fwu_last_chunk_crc = crc16_ccitt(0xffff, fwu_buffer, fwu_chunk_size);
LOG_INF("FWU: Chunk received, CRC is 0x%04X", fwu_last_chunk_crc);
}
}
}
} }
uint16_t fwu_get_last_chunk_crc(void) { return fwu_last_chunk_crc; } void fwu_handler(uint16_t addr, uint16_t reg)
{
// This is a simplified handler. In a real scenario, you would have a proper
// mapping between register addresses and actions.
if (addr == 0x0100) { // FWU_COMMAND
if (reg == 1) {
LOG_INF("FWU: Chunk at offset %u (size %u) verified.",
fwu_chunk_offset,
fwu_chunk_size);
} else if (reg == 2) {
LOG_INF("FWU: Finalize command received. Rebooting (simulated).");
}
} else if (addr == 0x0101) { // FWU_CHUNK_OFFSET_LOW
fwu_chunk_offset = (fwu_chunk_offset & 0xFFFF0000) | reg;
} else if (addr == 0x0102) { // FWU_CHUNK_OFFSET_HIGH
fwu_chunk_offset = (fwu_chunk_offset & 0x0000FFFF) | ((uint32_t)reg << 16);
} else if (addr == 0x0103) { // FWU_CHUNK_SIZE
fwu_chunk_size = (reg > FWU_BUFFER_SIZE) ? FWU_BUFFER_SIZE : reg;
} else if (addr >= 0x0180 && addr < (0x0180 + (FWU_BUFFER_SIZE / 2))) {
uint16_t index = (addr - 0x0180) * 2;
if (index < sizeof(fwu_buffer)) {
sys_put_be16(reg, &fwu_buffer[index]);
if (index + 2 >= fwu_chunk_size) {
fwu_last_chunk_crc =
crc16_ccitt(0xffff, fwu_buffer, fwu_chunk_size);
LOG_INF("FWU: Chunk received, CRC is 0x%04X", fwu_last_chunk_crc);
}
}
}
}
uint16_t fwu_get_last_chunk_crc(void)
{
return fwu_last_chunk_crc;
}

View File

@ -7,10 +7,6 @@
* libraries like valve control, ADC sensors, and firmware updates. * libraries like valve control, ADC sensors, and firmware updates.
*/ */
#include <app_version.h>
#include <lib/fwu.h>
#include <lib/modbus_server.h>
#include <lib/valve.h>
#include <zephyr/device.h> #include <zephyr/device.h>
#include <zephyr/drivers/misc/vnd7050aj/vnd7050aj.h> #include <zephyr/drivers/misc/vnd7050aj/vnd7050aj.h>
#include <zephyr/drivers/uart.h> #include <zephyr/drivers/uart.h>
@ -20,6 +16,10 @@
#include <zephyr/settings/settings.h> #include <zephyr/settings/settings.h>
#include <zephyr/sys/reboot.h> #include <zephyr/sys/reboot.h>
#include <zephyr/usb/usb_device.h> #include <zephyr/usb/usb_device.h>
#include <app_version.h>
#include <lib/fwu.h>
#include <lib/modbus_server.h>
#include <lib/valve.h>
LOG_MODULE_REGISTER(modbus_server, LOG_LEVEL_INF); LOG_MODULE_REGISTER(modbus_server, LOG_LEVEL_INF);
@ -42,9 +42,10 @@ static struct k_timer watchdog_timer;
* *
* @param timer_id Pointer to the timer instance. * @param timer_id Pointer to the timer instance.
*/ */
static void watchdog_timer_handler(struct k_timer *timer_id) { static void watchdog_timer_handler(struct k_timer *timer_id)
LOG_WRN("Modbus watchdog expired! Closing valve as a fail-safe."); {
valve_close(); LOG_WRN("Modbus watchdog expired! Closing valve as a fail-safe.");
valve_close();
} }
/** /**
@ -53,10 +54,11 @@ static void watchdog_timer_handler(struct k_timer *timer_id) {
* This function should be called upon receiving any valid Modbus request * This function should be called upon receiving any valid Modbus request
* to prevent the watchdog from expiring. * to prevent the watchdog from expiring.
*/ */
static inline void reset_watchdog(void) { static inline void reset_watchdog(void)
if (watchdog_timeout_s > 0) { {
k_timer_start(&watchdog_timer, K_SECONDS(watchdog_timeout_s), K_NO_WAIT); if (watchdog_timeout_s > 0) {
} k_timer_start(&watchdog_timer, K_SECONDS(watchdog_timeout_s), K_NO_WAIT);
}
} }
/** /**
@ -66,23 +68,24 @@ static inline void reset_watchdog(void) {
* @param reg Pointer to store the read value. * @param reg Pointer to store the read value.
* @return 0 on success. * @return 0 on success.
*/ */
static int holding_reg_rd(uint16_t addr, uint16_t *reg) { static int holding_reg_rd(uint16_t addr, uint16_t *reg)
reset_watchdog(); {
switch (addr) { reset_watchdog();
case REG_HOLDING_MAX_OPENING_TIME_S: switch (addr) {
*reg = valve_get_max_open_time(); case REG_HOLDING_MAX_OPENING_TIME_S:
break; *reg = valve_get_max_open_time();
case REG_HOLDING_MAX_CLOSING_TIME_S: break;
*reg = valve_get_max_close_time(); case REG_HOLDING_MAX_CLOSING_TIME_S:
break; *reg = valve_get_max_close_time();
case REG_HOLDING_WATCHDOG_TIMEOUT_S: break;
*reg = watchdog_timeout_s; case REG_HOLDING_WATCHDOG_TIMEOUT_S:
break; *reg = watchdog_timeout_s;
default: break;
*reg = 0; default:
break; *reg = 0;
} break;
return 0; }
return 0;
} }
/** /**
@ -92,45 +95,46 @@ static int holding_reg_rd(uint16_t addr, uint16_t *reg) {
* @param reg Value to write. * @param reg Value to write.
* @return 0 on success. * @return 0 on success.
*/ */
static int holding_reg_wr(uint16_t addr, uint16_t reg) { static int holding_reg_wr(uint16_t addr, uint16_t reg)
reset_watchdog(); {
switch (addr) { reset_watchdog();
case REG_HOLDING_VALVE_COMMAND: switch (addr) {
if (reg == 1) { case REG_HOLDING_VALVE_COMMAND:
valve_open(); if (reg == 1) {
} else if (reg == 2) { valve_open();
valve_close(); } else if (reg == 2) {
} else if (reg == 0) { valve_close();
valve_stop(); } else if (reg == 0) {
} valve_stop();
break; }
case REG_HOLDING_MAX_OPENING_TIME_S: break;
valve_set_max_open_time(reg); case REG_HOLDING_MAX_OPENING_TIME_S:
break; valve_set_max_open_time(reg);
case REG_HOLDING_MAX_CLOSING_TIME_S: break;
valve_set_max_close_time(reg); case REG_HOLDING_MAX_CLOSING_TIME_S:
break; valve_set_max_close_time(reg);
case REG_HOLDING_WATCHDOG_TIMEOUT_S: break;
watchdog_timeout_s = reg; case REG_HOLDING_WATCHDOG_TIMEOUT_S:
if (watchdog_timeout_s > 0) { watchdog_timeout_s = reg;
LOG_INF("Watchdog enabled with %u s timeout.", watchdog_timeout_s); if (watchdog_timeout_s > 0) {
reset_watchdog(); LOG_INF("Watchdog enabled with %u s timeout.", watchdog_timeout_s);
} else { reset_watchdog();
LOG_INF("Watchdog disabled."); } else {
k_timer_stop(&watchdog_timer); LOG_INF("Watchdog disabled.");
} k_timer_stop(&watchdog_timer);
break; }
case REG_HOLDING_DEVICE_RESET: break;
if (reg == 1) { case REG_HOLDING_DEVICE_RESET:
LOG_WRN("Modbus reset command received. Rebooting..."); if (reg == 1) {
sys_reboot(SYS_REBOOT_WARM); LOG_WRN("Modbus reset command received. Rebooting...");
} sys_reboot(SYS_REBOOT_WARM);
break; }
default: break;
fwu_handler(addr, reg); default:
break; fwu_handler(addr, reg);
} break;
return 0; }
return 0;
} }
/** /**
@ -140,42 +144,43 @@ static int holding_reg_wr(uint16_t addr, uint16_t reg) {
* @param reg Pointer to store the read value. * @param reg Pointer to store the read value.
* @return 0 on success. * @return 0 on success.
*/ */
static int input_reg_rd(uint16_t addr, uint16_t *reg) { static int input_reg_rd(uint16_t addr, uint16_t *reg)
reset_watchdog(); {
uint32_t uptime_s = k_uptime_get_32() / 1000; reset_watchdog();
switch (addr) { uint32_t uptime_s = k_uptime_get_32() / 1000;
case REG_INPUT_VALVE_STATE_MOVEMENT: switch (addr) {
*reg = (valve_get_movement() << 8) | (valve_get_state() & 0xFF); case REG_INPUT_VALVE_STATE_MOVEMENT:
break; *reg = (valve_get_movement() << 8) | (valve_get_state() & 0xFF);
case REG_INPUT_MOTOR_OPEN_CURRENT_MA: break;
*reg = (uint16_t)valve_get_opening_current(); case REG_INPUT_MOTOR_OPEN_CURRENT_MA:
break; *reg = (uint16_t)valve_get_opening_current();
case REG_INPUT_MOTOR_CLOSE_CURRENT_MA: break;
*reg = (uint16_t)valve_get_closing_current(); case REG_INPUT_MOTOR_CLOSE_CURRENT_MA:
break; *reg = (uint16_t)valve_get_closing_current();
case REG_INPUT_UPTIME_SECONDS_LOW: break;
*reg = (uint16_t)(uptime_s & 0xFFFF); case REG_INPUT_UPTIME_SECONDS_LOW:
break; *reg = (uint16_t)(uptime_s & 0xFFFF);
case REG_INPUT_UPTIME_SECONDS_HIGH: break;
*reg = (uint16_t)(uptime_s >> 16); case REG_INPUT_UPTIME_SECONDS_HIGH:
break; *reg = (uint16_t)(uptime_s >> 16);
case REG_INPUT_SUPPLY_VOLTAGE_MV: break;
*reg = (uint16_t)valve_get_vnd_voltage(); case REG_INPUT_SUPPLY_VOLTAGE_MV:
break; *reg = (uint16_t)valve_get_vnd_voltage();
case REG_INPUT_FWU_LAST_CHUNK_CRC: break;
*reg = fwu_get_last_chunk_crc(); case REG_INPUT_FWU_LAST_CHUNK_CRC:
break; *reg = fwu_get_last_chunk_crc();
case REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR: break;
*reg = (APP_VERSION_MAJOR << 8) | APP_VERSION_MINOR; case REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR:
break; *reg = (APP_VERSION_MAJOR << 8) | APP_VERSION_MINOR;
case REG_INPUT_FIRMWARE_VERSION_PATCH: break;
*reg = APP_PATCHLEVEL; case REG_INPUT_FIRMWARE_VERSION_PATCH:
break; *reg = APP_PATCHLEVEL;
default: break;
*reg = 0; default:
break; *reg = 0;
} break;
return 0; }
return 0;
} }
static struct modbus_user_callbacks mbs_cbs = { static struct modbus_user_callbacks mbs_cbs = {
@ -187,74 +192,80 @@ static struct modbus_user_callbacks mbs_cbs = {
#define MODBUS_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_modbus_serial) #define MODBUS_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_modbus_serial)
int modbus_server_init(void) { int modbus_server_init(void)
k_timer_init(&watchdog_timer, watchdog_timer_handler, NULL); {
k_timer_init(&watchdog_timer, watchdog_timer_handler, NULL);
// Load saved settings // Load saved settings
uint32_t saved_baudrate = 19200; uint32_t saved_baudrate = 19200;
uint8_t saved_unit_id = 1; uint8_t saved_unit_id = 1;
settings_load_one("modbus/baudrate", &saved_baudrate, sizeof(saved_baudrate)); settings_load_one("modbus/baudrate", &saved_baudrate, sizeof(saved_baudrate));
settings_load_one("modbus/unit_id", &saved_unit_id, sizeof(saved_unit_id)); settings_load_one("modbus/unit_id", &saved_unit_id, sizeof(saved_unit_id));
// Apply loaded settings // Apply loaded settings
server_param.serial.baud = saved_baudrate; server_param.serial.baud = saved_baudrate;
server_param.server.unit_id = saved_unit_id; server_param.server.unit_id = saved_unit_id;
const char iface_name[] = {DEVICE_DT_NAME(MODBUS_NODE)}; const char iface_name[] = {DEVICE_DT_NAME(MODBUS_NODE)};
#if DT_NODE_HAS_COMPAT(DT_PARENT(MODBUS_NODE), zephyr_cdc_acm_uart) #if DT_NODE_HAS_COMPAT(DT_PARENT(MODBUS_NODE), zephyr_cdc_acm_uart)
const struct device *const dev = DEVICE_DT_GET(DT_PARENT(MODBUS_NODE)); const struct device *const dev = DEVICE_DT_GET(DT_PARENT(MODBUS_NODE));
uint32_t dtr = 0; uint32_t dtr = 0;
if (!device_is_ready(dev) || usb_enable(NULL)) { if (!device_is_ready(dev) || usb_enable(NULL)) {
return 0; return 0;
} }
while (!dtr) { while (!dtr) {
uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr); uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr);
k_sleep(K_MSEC(100)); k_sleep(K_MSEC(100));
} }
LOG_INF("Client connected to server on %s", dev->name); LOG_INF("Client connected to server on %s", dev->name);
#endif #endif
modbus_iface = modbus_iface_get_by_name(iface_name); modbus_iface = modbus_iface_get_by_name(iface_name);
if (modbus_iface < 0) { if (modbus_iface < 0) {
return modbus_iface; return modbus_iface;
} }
server_param.server.user_cb = &mbs_cbs; server_param.server.user_cb = &mbs_cbs;
LOG_INF("Starting Modbus server: baudrate=%u, unit_id=%u", saved_baudrate, LOG_INF("Starting Modbus server: baudrate=%u, unit_id=%u", saved_baudrate, saved_unit_id);
saved_unit_id); return modbus_init_server(modbus_iface, server_param);
return modbus_init_server(modbus_iface, server_param);
} }
int modbus_reconfigure(uint32_t baudrate, uint8_t unit_id) { int modbus_reconfigure(uint32_t baudrate, uint8_t unit_id)
// Update parameters {
server_param.serial.baud = baudrate; // Update parameters
server_param.server.unit_id = unit_id; server_param.serial.baud = baudrate;
server_param.server.unit_id = unit_id;
// Try to reinitialize - this should work for most cases // Try to reinitialize - this should work for most cases
int ret = modbus_init_server(modbus_iface, server_param); int ret = modbus_init_server(modbus_iface, server_param);
if (ret == 0) { if (ret == 0) {
settings_save_one("modbus/baudrate", &baudrate, sizeof(baudrate)); settings_save_one("modbus/baudrate", &baudrate, sizeof(baudrate));
settings_save_one("modbus/unit_id", &unit_id, sizeof(unit_id)); settings_save_one("modbus/unit_id", &unit_id, sizeof(unit_id));
LOG_INF("Modbus reconfigured: baudrate=%u, unit_id=%u", baudrate, unit_id); LOG_INF("Modbus reconfigured: baudrate=%u, unit_id=%u", baudrate, unit_id);
} else { } else {
LOG_ERR("Failed to reconfigure Modbus: %d", ret); LOG_ERR("Failed to reconfigure Modbus: %d", ret);
LOG_INF("Modbus reconfiguration requires restart to take effect"); LOG_INF("Modbus reconfiguration requires restart to take effect");
// Save settings for next boot // Save settings for next boot
settings_save_one("modbus/baudrate", &baudrate, sizeof(baudrate)); settings_save_one("modbus/baudrate", &baudrate, sizeof(baudrate));
settings_save_one("modbus/unit_id", &unit_id, sizeof(unit_id)); settings_save_one("modbus/unit_id", &unit_id, sizeof(unit_id));
LOG_INF( LOG_INF("Settings saved. Type 'reset' to restart the device and apply the "
"Settings saved. Type 'reset' to restart the device and apply the " "change.");
"change."); return 0; // Return success since settings are saved
return 0; // Return success since settings are saved }
}
return ret; return ret;
} }
uint32_t modbus_get_baudrate(void) { return server_param.serial.baud; } uint32_t modbus_get_baudrate(void)
uint8_t modbus_get_unit_id(void) { return server_param.server.unit_id; } {
return server_param.serial.baud;
}
uint8_t modbus_get_unit_id(void)
{
return server_param.server.unit_id;
}

View File

@ -8,10 +8,10 @@
* storage. * storage.
*/ */
#include <zephyr/shell/shell.h>
#include <lib/modbus_server.h> #include <lib/modbus_server.h>
#include <lib/valve.h> #include <lib/valve.h>
#include <stdlib.h> #include <stdlib.h>
#include <zephyr/shell/shell.h>
/** /**
* @brief Shell command to set the Modbus baudrate. * @brief Shell command to set the Modbus baudrate.
@ -21,44 +21,45 @@
* @param argv Argument values. * @param argv Argument values.
* @return 0 on success, -EINVAL on error. * @return 0 on success, -EINVAL on error.
*/ */
static int cmd_modbus_set_baud(const struct shell *sh, size_t argc, static int cmd_modbus_set_baud(const struct shell *sh, size_t argc, char **argv)
char **argv) { {
if (argc != 2) { if (argc != 2) {
shell_error(sh, "Usage: set_baud <baudrate>"); shell_error(sh, "Usage: set_baud <baudrate>");
return -EINVAL; return -EINVAL;
} }
uint32_t new_baud = (uint32_t)strtoul(argv[1], NULL, 10); uint32_t new_baud = (uint32_t)strtoul(argv[1], NULL, 10);
const uint32_t valid_baud_rates[] = {1200, 2400, 4800, 9600, const uint32_t valid_baud_rates[] = {1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
19200, 38400, 57600, 115200}; bool is_valid = false;
bool is_valid = false;
for (int i = 0; i < ARRAY_SIZE(valid_baud_rates); i++) { for (int i = 0; i < ARRAY_SIZE(valid_baud_rates); i++) {
if (new_baud == valid_baud_rates[i]) { if (new_baud == valid_baud_rates[i]) {
is_valid = true; is_valid = true;
break; break;
} }
} }
if (!is_valid) { if (!is_valid) {
char error_msg[128]; char error_msg[128];
int offset = snprintf(error_msg, sizeof(error_msg), int offset =
"Invalid baudrate. Valid rates are: "); snprintf(error_msg, sizeof(error_msg), "Invalid baudrate. Valid rates are: ");
for (int i = 0; i < ARRAY_SIZE(valid_baud_rates); i++) { for (int i = 0; i < ARRAY_SIZE(valid_baud_rates); i++) {
offset += snprintf(error_msg + offset, sizeof(error_msg) - offset, "%u ", offset += snprintf(error_msg + offset,
valid_baud_rates[i]); sizeof(error_msg) - offset,
} "%u ",
shell_error(sh, "%s", error_msg); valid_baud_rates[i]);
return -EINVAL; }
} shell_error(sh, "%s", error_msg);
return -EINVAL;
}
if (modbus_reconfigure(new_baud, modbus_get_unit_id()) != 0) { if (modbus_reconfigure(new_baud, modbus_get_unit_id()) != 0) {
shell_error(sh, "Failed to apply new baudrate"); shell_error(sh, "Failed to apply new baudrate");
} else { } else {
shell_print(sh, "Modbus baudrate set to: %u (and saved)", new_baud); shell_print(sh, "Modbus baudrate set to: %u (and saved)", new_baud);
} }
return 0; return 0;
} }
/** /**
@ -69,27 +70,27 @@ static int cmd_modbus_set_baud(const struct shell *sh, size_t argc,
* @param argv Argument values. * @param argv Argument values.
* @return 0 on success, -EINVAL on error. * @return 0 on success, -EINVAL on error.
*/ */
static int cmd_modbus_set_id(const struct shell *sh, size_t argc, char **argv) { static int cmd_modbus_set_id(const struct shell *sh, size_t argc, char **argv)
if (argc != 2) { {
shell_error(sh, "Usage: set_id <slave_id>"); if (argc != 2) {
return -EINVAL; shell_error(sh, "Usage: set_id <slave_id>");
} return -EINVAL;
}
uint32_t new_id_u32 = (uint32_t)strtoul(argv[1], NULL, 10); uint32_t new_id_u32 = (uint32_t)strtoul(argv[1], NULL, 10);
if (new_id_u32 == 0 || new_id_u32 > 247) { if (new_id_u32 == 0 || new_id_u32 > 247) {
shell_error(sh, "Invalid slave ID: %s. Must be between 1 and 247.", shell_error(sh, "Invalid slave ID: %s. Must be between 1 and 247.", argv[1]);
argv[1]); return -EINVAL;
return -EINVAL; }
} uint8_t new_id = (uint8_t)new_id_u32;
uint8_t new_id = (uint8_t)new_id_u32;
if (modbus_reconfigure(modbus_get_baudrate(), new_id) != 0) { if (modbus_reconfigure(modbus_get_baudrate(), new_id) != 0) {
shell_error(sh, "Failed to apply new slave ID"); shell_error(sh, "Failed to apply new slave ID");
} else { } else {
shell_print(sh, "Modbus slave ID set to: %u (and saved)", new_id); shell_print(sh, "Modbus slave ID set to: %u (and saved)", new_id);
} }
return 0; return 0;
} }
/** /**
@ -100,18 +101,18 @@ static int cmd_modbus_set_id(const struct shell *sh, size_t argc, char **argv) {
* @param argv Argument values. * @param argv Argument values.
* @return 0 on success, -EINVAL on error. * @return 0 on success, -EINVAL on error.
*/ */
static int cmd_valve_set_open_time(const struct shell *sh, size_t argc, static int cmd_valve_set_open_time(const struct shell *sh, size_t argc, char **argv)
char **argv) { {
if (argc != 2) { if (argc != 2) {
shell_error(sh, "Usage: set_open_time <seconds>"); shell_error(sh, "Usage: set_open_time <seconds>");
return -EINVAL; return -EINVAL;
} }
uint16_t seconds = (uint16_t)strtoul(argv[1], NULL, 10); uint16_t seconds = (uint16_t)strtoul(argv[1], NULL, 10);
valve_set_max_open_time(seconds); valve_set_max_open_time(seconds);
shell_print(sh, "Max opening time set to: %u seconds (and saved)", seconds); shell_print(sh, "Max opening time set to: %u seconds (and saved)", seconds);
return 0; return 0;
} }
/** /**
@ -122,18 +123,18 @@ static int cmd_valve_set_open_time(const struct shell *sh, size_t argc,
* @param argv Argument values. * @param argv Argument values.
* @return 0 on success, -EINVAL on error. * @return 0 on success, -EINVAL on error.
*/ */
static int cmd_valve_set_close_time(const struct shell *sh, size_t argc, static int cmd_valve_set_close_time(const struct shell *sh, size_t argc, char **argv)
char **argv) { {
if (argc != 2) { if (argc != 2) {
shell_error(sh, "Usage: set_close_time <seconds>"); shell_error(sh, "Usage: set_close_time <seconds>");
return -EINVAL; return -EINVAL;
} }
uint16_t seconds = (uint16_t)strtoul(argv[1], NULL, 10); uint16_t seconds = (uint16_t)strtoul(argv[1], NULL, 10);
valve_set_max_close_time(seconds); valve_set_max_close_time(seconds);
shell_print(sh, "Max closing time set to: %u seconds (and saved)", seconds); shell_print(sh, "Max closing time set to: %u seconds (and saved)", seconds);
return 0; return 0;
} }
/** /**
@ -144,33 +145,27 @@ static int cmd_valve_set_close_time(const struct shell *sh, size_t argc,
* @param argv Argument values. * @param argv Argument values.
* @return 0 on success. * @return 0 on success.
*/ */
static int cmd_config_show(const struct shell *sh, size_t argc, char **argv) { static int cmd_config_show(const struct shell *sh, size_t argc, char **argv)
shell_print(sh, "Current Modbus Configuration:"); {
shell_print(sh, " Baudrate: %u", modbus_get_baudrate()); shell_print(sh, "Current Modbus Configuration:");
shell_print(sh, " Slave ID: %u", modbus_get_unit_id()); shell_print(sh, " Baudrate: %u", modbus_get_baudrate());
shell_print(sh, "Current Valve Configuration:"); shell_print(sh, " Slave ID: %u", modbus_get_unit_id());
shell_print(sh, " Max Opening Time: %u s", valve_get_max_open_time()); shell_print(sh, "Current Valve Configuration:");
shell_print(sh, " Max Closing Time: %u s", valve_get_max_close_time()); shell_print(sh, " Max Opening Time: %u s", valve_get_max_open_time());
return 0; shell_print(sh, " Max Closing Time: %u s", valve_get_max_close_time());
return 0;
} }
SHELL_STATIC_SUBCMD_SET_CREATE(sub_modbus_cmds, SHELL_STATIC_SUBCMD_SET_CREATE(sub_modbus_cmds,
SHELL_CMD(set_baud, NULL, "Set Modbus baudrate", SHELL_CMD(set_baud, NULL, "Set Modbus baudrate", cmd_modbus_set_baud),
cmd_modbus_set_baud), SHELL_CMD(set_id, NULL, "Set Modbus slave ID", cmd_modbus_set_id),
SHELL_CMD(set_id, NULL, "Set Modbus slave ID", SHELL_SUBCMD_SET_END);
cmd_modbus_set_id),
SHELL_SUBCMD_SET_END);
SHELL_STATIC_SUBCMD_SET_CREATE(sub_valve_cmds, SHELL_STATIC_SUBCMD_SET_CREATE(sub_valve_cmds,
SHELL_CMD(set_open_time, NULL, SHELL_CMD(set_open_time, NULL, "Set max valve opening time", cmd_valve_set_open_time),
"Set max valve opening time", SHELL_CMD(set_close_time, NULL, "Set max valve closing time", cmd_valve_set_close_time),
cmd_valve_set_open_time), SHELL_SUBCMD_SET_END);
SHELL_CMD(set_close_time, NULL,
"Set max valve closing time",
cmd_valve_set_close_time),
SHELL_SUBCMD_SET_END);
SHELL_CMD_REGISTER(modbus, &sub_modbus_cmds, "Modbus configuration", NULL); SHELL_CMD_REGISTER(modbus, &sub_modbus_cmds, "Modbus configuration", NULL);
SHELL_CMD_REGISTER(valve, &sub_valve_cmds, "Valve configuration", NULL); SHELL_CMD_REGISTER(valve, &sub_valve_cmds, "Valve configuration", NULL);
SHELL_CMD_REGISTER(show_config, NULL, "Show all configurations", SHELL_CMD_REGISTER(show_config, NULL, "Show all configurations", cmd_config_show);
cmd_config_show);

View File

@ -20,11 +20,12 @@
* @param argv Argument values. * @param argv Argument values.
* @return 0 on success. * @return 0 on success.
*/ */
static int cmd_reset(const struct shell *sh, size_t argc, char **argv) { static int cmd_reset(const struct shell *sh, size_t argc, char **argv)
shell_print(sh, "Rebooting system..."); {
k_sleep(K_MSEC(100)); // Allow the shell to print the message shell_print(sh, "Rebooting system...");
sys_reboot(SYS_REBOOT_WARM); k_sleep(K_MSEC(100)); // Allow the shell to print the message
return 0; sys_reboot(SYS_REBOOT_WARM);
return 0;
} }
SHELL_CMD_REGISTER(reset, NULL, "Reboot the system", cmd_reset); SHELL_CMD_REGISTER(reset, NULL, "Reboot the system", cmd_reset);