1use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
6use std::time::Duration;
7
8use serde::{Deserialize, Serialize};
9
10use crate::address::IndividualAddress;
11use crate::error_tracker::SendErrorTrackerConfig;
12use crate::filter::FilterChainConfig;
13use crate::group_cache::GroupValueCacheConfig;
14use crate::heartbeat::HeartbeatSchedulerConfig;
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct KnxServerConfig {
23 #[serde(default = "default_bind_addr")]
25 pub bind_addr: SocketAddr,
26
27 #[serde(default = "default_multicast_addr")]
29 pub multicast_addr: SocketAddr,
30
31 #[serde(default = "default_individual_address")]
33 pub individual_address: IndividualAddress,
34
35 #[serde(default = "default_device_name")]
37 pub device_name: String,
38
39 #[serde(default = "default_serial_number")]
41 pub serial_number: [u8; 6],
42
43 #[serde(default = "default_mac_address")]
45 pub mac_address: [u8; 6],
46
47 #[serde(default = "default_max_connections")]
49 pub max_connections: usize,
50
51 #[serde(default = "default_heartbeat_interval_secs")]
53 pub heartbeat_interval_secs: u64,
54
55 #[serde(default = "default_connection_timeout_secs")]
57 pub connection_timeout_secs: u64,
58
59 #[serde(default)]
61 pub routing_enabled: bool,
62
63 #[serde(default = "default_true")]
65 pub tunneling_enabled: bool,
66
67 #[serde(default)]
69 pub device_management_enabled: bool,
70
71 #[serde(default)]
73 pub tunnel_behavior: TunnelBehaviorConfig,
74}
75
76fn default_bind_addr() -> SocketAddr {
77 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 3671))
78}
79
80fn default_multicast_addr() -> SocketAddr {
81 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(224, 0, 23, 12), 3671))
83}
84
85fn default_individual_address() -> IndividualAddress {
86 IndividualAddress::new(1, 1, 1)
87}
88
89fn default_device_name() -> String {
90 "OTSim KNX Simulator".to_string()
91}
92
93fn default_serial_number() -> [u8; 6] {
94 [0x00, 0x00, 0x00, 0x00, 0x00, 0x01]
95}
96
97fn default_mac_address() -> [u8; 6] {
98 [0x00, 0x00, 0x00, 0x00, 0x00, 0x01]
99}
100
101fn default_max_connections() -> usize {
102 256
103}
104
105fn default_heartbeat_interval_secs() -> u64 {
106 60
107}
108
109fn default_connection_timeout_secs() -> u64 {
110 120
111}
112
113fn default_true() -> bool {
114 true
115}
116
117impl Default for KnxServerConfig {
118 fn default() -> Self {
119 Self {
120 bind_addr: default_bind_addr(),
121 multicast_addr: default_multicast_addr(),
122 individual_address: default_individual_address(),
123 device_name: default_device_name(),
124 serial_number: default_serial_number(),
125 mac_address: default_mac_address(),
126 max_connections: default_max_connections(),
127 heartbeat_interval_secs: default_heartbeat_interval_secs(),
128 connection_timeout_secs: default_connection_timeout_secs(),
129 routing_enabled: false,
130 tunneling_enabled: true,
131 device_management_enabled: false,
132 tunnel_behavior: TunnelBehaviorConfig::default(),
133 }
134 }
135}
136
137impl KnxServerConfig {
138 pub fn with_bind_addr(mut self, addr: SocketAddr) -> Self {
140 self.bind_addr = addr;
141 self
142 }
143
144 pub fn with_individual_address(mut self, addr: IndividualAddress) -> Self {
146 self.individual_address = addr;
147 self
148 }
149
150 pub fn with_device_name(mut self, name: impl Into<String>) -> Self {
152 self.device_name = name.into();
153 self
154 }
155
156 pub fn with_max_connections(mut self, max: usize) -> Self {
158 self.max_connections = max;
159 self
160 }
161
162 pub fn with_routing(mut self, enabled: bool) -> Self {
164 self.routing_enabled = enabled;
165 self
166 }
167
168 pub fn heartbeat_interval(&self) -> Duration {
170 Duration::from_secs(self.heartbeat_interval_secs)
171 }
172
173 pub fn connection_timeout(&self) -> Duration {
175 Duration::from_secs(self.connection_timeout_secs)
176 }
177
178 pub fn validate(&self) -> Result<(), String> {
180 if self.max_connections == 0 {
181 return Err("max_connections must be greater than 0".to_string());
182 }
183 if self.heartbeat_interval_secs == 0 {
184 return Err("heartbeat_interval_secs must be greater than 0".to_string());
185 }
186 if self.device_name.is_empty() {
187 return Err("device_name cannot be empty".to_string());
188 }
189 if self.device_name.len() > 30 {
190 return Err("device_name cannot exceed 30 characters".to_string());
191 }
192 Ok(())
193 }
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct KnxDeviceConfig {
203 pub id: String,
205
206 pub name: String,
208
209 #[serde(default)]
211 pub description: String,
212
213 pub individual_address: IndividualAddress,
215
216 #[serde(default)]
218 pub group_objects: Vec<GroupObjectConfig>,
219
220 #[serde(default = "default_tick_interval_ms")]
222 pub tick_interval_ms: u64,
223}
224
225fn default_tick_interval_ms() -> u64 {
226 100
227}
228
229impl Default for KnxDeviceConfig {
230 fn default() -> Self {
231 Self {
232 id: "knx-device-1".to_string(),
233 name: "KNX Device".to_string(),
234 description: String::new(),
235 individual_address: IndividualAddress::new(1, 1, 1),
236 group_objects: Vec::new(),
237 tick_interval_ms: default_tick_interval_ms(),
238 }
239 }
240}
241
242impl KnxDeviceConfig {
243 pub fn new(id: impl Into<String>, name: impl Into<String>) -> Self {
245 Self {
246 id: id.into(),
247 name: name.into(),
248 ..Default::default()
249 }
250 }
251
252 pub fn with_individual_address(mut self, addr: IndividualAddress) -> Self {
254 self.individual_address = addr;
255 self
256 }
257
258 pub fn with_group_object(mut self, obj: GroupObjectConfig) -> Self {
260 self.group_objects.push(obj);
261 self
262 }
263
264 pub fn tick_interval(&self) -> Duration {
266 Duration::from_millis(self.tick_interval_ms)
267 }
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
276pub struct GroupObjectConfig {
277 pub address: String,
279
280 pub name: String,
282
283 pub dpt: String,
285
286 #[serde(default)]
288 pub flags: GroupObjectFlagsConfig,
289
290 #[serde(default)]
292 pub initial_value: Option<serde_json::Value>,
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct GroupObjectFlagsConfig {
298 #[serde(default = "default_true")]
300 pub communication: bool,
301
302 #[serde(default = "default_true")]
304 pub read: bool,
305
306 #[serde(default = "default_true")]
308 pub write: bool,
309
310 #[serde(default = "default_true")]
312 pub transmit: bool,
313
314 #[serde(default = "default_true")]
316 pub update: bool,
317}
318
319impl Default for GroupObjectFlagsConfig {
320 fn default() -> Self {
321 Self {
322 communication: true,
323 read: true,
324 write: true,
325 transmit: true,
326 update: true,
327 }
328 }
329}
330
331impl GroupObjectFlagsConfig {
332 pub fn read_only() -> Self {
334 Self {
335 communication: true,
336 read: true,
337 write: false,
338 transmit: true,
339 update: false,
340 }
341 }
342
343 pub fn write_only() -> Self {
345 Self {
346 communication: true,
347 read: false,
348 write: true,
349 transmit: false,
350 update: true,
351 }
352 }
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize)]
361pub struct TunnelConfig {
362 #[serde(default)]
364 pub layer: KnxLayerConfig,
365
366 #[serde(default = "default_request_timeout_ms")]
368 pub request_timeout_ms: u64,
369
370 #[serde(default = "default_max_retries")]
372 pub max_retries: u8,
373
374 #[serde(default = "default_ack_timeout_ms")]
376 pub ack_timeout_ms: u64,
377
378 #[serde(default = "default_confirmation_timeout_ms")]
380 pub confirmation_timeout_ms: u64,
381
382 #[serde(default = "default_send_error_threshold")]
384 pub send_error_threshold: u32,
385
386 #[serde(default = "default_fatal_desync_threshold")]
388 pub fatal_desync_threshold: u8,
389}
390
391fn default_request_timeout_ms() -> u64 {
392 1000
393}
394
395fn default_max_retries() -> u8 {
396 3
397}
398
399fn default_ack_timeout_ms() -> u64 {
400 1000
401}
402
403fn default_confirmation_timeout_ms() -> u64 {
404 3000
405}
406
407fn default_send_error_threshold() -> u32 {
408 5
409}
410
411fn default_fatal_desync_threshold() -> u8 {
412 5
413}
414
415impl Default for TunnelConfig {
416 fn default() -> Self {
417 Self {
418 layer: KnxLayerConfig::default(),
419 request_timeout_ms: default_request_timeout_ms(),
420 max_retries: default_max_retries(),
421 ack_timeout_ms: default_ack_timeout_ms(),
422 confirmation_timeout_ms: default_confirmation_timeout_ms(),
423 send_error_threshold: default_send_error_threshold(),
424 fatal_desync_threshold: default_fatal_desync_threshold(),
425 }
426 }
427}
428
429impl TunnelConfig {
430 pub fn request_timeout(&self) -> Duration {
432 Duration::from_millis(self.request_timeout_ms)
433 }
434
435 pub fn ack_timeout(&self) -> Duration {
437 Duration::from_millis(self.ack_timeout_ms)
438 }
439
440 pub fn confirmation_timeout(&self) -> Duration {
442 Duration::from_millis(self.confirmation_timeout_ms)
443 }
444}
445
446#[derive(Debug, Clone, Serialize, Deserialize)]
451pub struct TunnelBehaviorConfig {
452 #[serde(default = "default_true")]
455 pub ldata_con_enabled: bool,
456
457 #[serde(default = "default_confirmation_success_rate")]
460 pub confirmation_success_rate: f64,
461
462 #[serde(default = "default_bus_delivery_delay_ms")]
464 pub bus_delivery_delay_ms: u64,
465
466 #[serde(default = "default_true")]
468 pub sequence_validation_enabled: bool,
469
470 #[serde(default = "default_true")]
472 pub ack_tracking_enabled: bool,
473
474 #[serde(default)]
477 pub heartbeat_status_override: Option<u8>,
478
479 #[serde(default = "default_server_ack_timeout_ms")]
481 pub server_ack_timeout_ms: u64,
482
483 #[serde(default = "default_max_retries")]
485 pub server_max_retries: u8,
486
487 #[serde(default)]
491 pub bus_monitor_enabled: bool,
492
493 #[serde(default = "default_true")]
496 pub ldata_ind_broadcast_enabled: bool,
497
498 #[serde(default = "default_true")]
502 pub property_service_enabled: bool,
503
504 #[serde(default = "default_true")]
507 pub reset_service_enabled: bool,
508
509 #[serde(default)]
513 pub flow_control: FilterChainConfig,
514
515 #[serde(default)]
519 pub heartbeat_scheduler: HeartbeatSchedulerConfig,
520
521 #[serde(default)]
525 pub group_value_cache: GroupValueCacheConfig,
526
527 #[serde(default)]
531 pub send_error_tracker: SendErrorTrackerConfig,
532}
533
534fn default_confirmation_success_rate() -> f64 {
535 1.0
536}
537
538fn default_bus_delivery_delay_ms() -> u64 {
539 0
540}
541
542fn default_server_ack_timeout_ms() -> u64 {
543 1000
544}
545
546impl Default for TunnelBehaviorConfig {
547 fn default() -> Self {
548 Self {
549 ldata_con_enabled: true,
550 confirmation_success_rate: default_confirmation_success_rate(),
551 bus_delivery_delay_ms: default_bus_delivery_delay_ms(),
552 sequence_validation_enabled: true,
553 ack_tracking_enabled: true,
554 heartbeat_status_override: None,
555 server_ack_timeout_ms: default_server_ack_timeout_ms(),
556 server_max_retries: default_max_retries(),
557 bus_monitor_enabled: false,
558 ldata_ind_broadcast_enabled: true,
559 property_service_enabled: true,
560 reset_service_enabled: true,
561 flow_control: FilterChainConfig::default(),
562 heartbeat_scheduler: HeartbeatSchedulerConfig::default(),
563 group_value_cache: GroupValueCacheConfig::default(),
564 send_error_tracker: SendErrorTrackerConfig::default(),
565 }
566 }
567}
568
569#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
571#[serde(rename_all = "lowercase")]
572pub enum KnxLayerConfig {
573 #[default]
575 LinkLayer,
576 Raw,
578 BusMonitor,
580}
581
582#[cfg(test)]
583mod tests {
584 use super::*;
585
586 #[test]
587 fn test_server_config_default() {
588 let config = KnxServerConfig::default();
589 assert_eq!(config.bind_addr.port(), 3671);
590 assert_eq!(config.max_connections, 256);
591 assert!(config.tunneling_enabled);
592 }
593
594 #[test]
595 fn test_server_config_builder() {
596 let config = KnxServerConfig::default()
597 .with_bind_addr("192.168.1.100:3671".parse().unwrap())
598 .with_max_connections(100)
599 .with_device_name("Test Server");
600
601 assert_eq!(config.device_name, "Test Server");
602 assert_eq!(config.max_connections, 100);
603 }
604
605 #[test]
606 fn test_server_config_validation() {
607 let config = KnxServerConfig::default();
608 assert!(config.validate().is_ok());
609
610 let invalid = KnxServerConfig {
611 max_connections: 0,
612 ..Default::default()
613 };
614 assert!(invalid.validate().is_err());
615 }
616
617 #[test]
618 fn test_device_config() {
619 let config = KnxDeviceConfig::new("dev-1", "Living Room Controller")
620 .with_individual_address(IndividualAddress::new(1, 2, 3));
621
622 assert_eq!(config.id, "dev-1");
623 assert_eq!(config.individual_address.to_string(), "1.2.3");
624 }
625
626 #[test]
627 fn test_group_object_flags() {
628 let ro = GroupObjectFlagsConfig::read_only();
629 assert!(ro.read);
630 assert!(!ro.write);
631
632 let wo = GroupObjectFlagsConfig::write_only();
633 assert!(!wo.read);
634 assert!(wo.write);
635 }
636}