use std::net::SocketAddr;
use std::time::Duration;
use mabi_core::tags::Tags;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModbusServerConfig {
#[serde(default = "default_bind_address")]
pub bind_address: SocketAddr,
#[serde(default = "default_max_connections")]
pub max_connections: usize,
#[serde(default = "default_timeout_secs")]
pub timeout_secs: u64,
#[serde(default = "default_true")]
pub keep_alive: bool,
#[serde(default = "default_true")]
pub tcp_nodelay: bool,
#[serde(default)]
pub rate_limit: u32,
}
fn default_bind_address() -> SocketAddr {
"0.0.0.0:502".parse().unwrap()
}
fn default_max_connections() -> usize {
1000
}
fn default_timeout_secs() -> u64 {
30
}
fn default_true() -> bool {
true
}
impl Default for ModbusServerConfig {
fn default() -> Self {
Self {
bind_address: default_bind_address(),
max_connections: default_max_connections(),
timeout_secs: default_timeout_secs(),
keep_alive: true,
tcp_nodelay: true,
rate_limit: 0,
}
}
}
impl ModbusServerConfig {
pub fn with_bind_address(mut self, addr: SocketAddr) -> Self {
self.bind_address = addr;
self
}
pub fn with_max_connections(mut self, max: usize) -> Self {
self.max_connections = max;
self
}
pub fn timeout(&self) -> Duration {
Duration::from_secs(self.timeout_secs)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModbusDeviceConfig {
pub unit_id: u8,
pub name: String,
#[serde(default = "default_coils")]
pub coils: u16,
#[serde(default = "default_discrete_inputs")]
pub discrete_inputs: u16,
#[serde(default = "default_holding_registers")]
pub holding_registers: u16,
#[serde(default = "default_input_registers")]
pub input_registers: u16,
#[serde(default)]
pub response_delay_ms: u64,
#[serde(default, skip_serializing_if = "Tags::is_empty")]
pub tags: Tags,
}
fn default_coils() -> u16 {
10000
}
fn default_discrete_inputs() -> u16 {
10000
}
fn default_holding_registers() -> u16 {
10000
}
fn default_input_registers() -> u16 {
10000
}
impl Default for ModbusDeviceConfig {
fn default() -> Self {
Self {
unit_id: 1,
name: "Modbus Device".to_string(),
coils: default_coils(),
discrete_inputs: default_discrete_inputs(),
holding_registers: default_holding_registers(),
input_registers: default_input_registers(),
response_delay_ms: 0,
tags: Tags::new(),
}
}
}
impl ModbusDeviceConfig {
pub fn new(unit_id: u8, name: impl Into<String>) -> Self {
Self {
unit_id,
name: name.into(),
..Default::default()
}
}
pub fn with_response_delay(mut self, delay_ms: u64) -> Self {
self.response_delay_ms = delay_ms;
self
}
pub fn with_tags(mut self, tags: Tags) -> Self {
self.tags = tags;
self
}
pub fn with_tag(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.tags.insert(key.into(), value.into());
self
}
pub fn with_label(mut self, label: impl Into<String>) -> Self {
self.tags.add_label(label.into());
self
}
pub fn validate(&self) -> Result<(), String> {
if self.unit_id == 0 || self.unit_id > 247 {
return Err(format!("Invalid unit ID: {} (must be 1-247)", self.unit_id));
}
Ok(())
}
}