pub mod address;
pub mod config;
pub mod error;
pub mod cemi;
pub mod dpt;
pub mod frame;
pub mod device;
pub mod diagnostics;
pub mod error_tracker;
pub mod factory;
pub mod filter;
pub mod group;
pub mod group_cache;
pub mod heartbeat;
pub mod metrics;
pub mod runtime;
pub mod server;
pub mod tunnel;
pub use address::{AddressType, GroupAddress, GroupAddressRange, IndividualAddress};
pub use cemi::{AdditionalInfo, AdditionalInfoType, Apci, CemiFrame, MessageCode, Priority};
pub use config::TunnelBehaviorConfig;
pub use config::{
GroupObjectConfig, GroupObjectFlagsConfig, KnxDeviceConfig, KnxServerConfig, TunnelConfig,
};
pub use device::{KnxDevice, KnxDeviceBuilder};
pub use diagnostics::{
DiagnosticConfig, DiagnosticResult, DiagnosticRule, DiagnosticSeverity, KnxDiagnostics,
};
pub use dpt::{decode_dpt9, encode_dpt9, BoxedDptCodec, DptCodec, DptId, DptRegistry, DptValue};
pub use error::{KnxError, KnxResult};
pub use error_tracker::{
ChannelErrorSummary, ErrorCategory, SendErrorTracker, SendErrorTrackerConfig,
TrackerStatsSnapshot, TrackingResult,
};
pub use factory::{register_knx_factory, KnxDeviceFactory};
pub use filter::{
CircuitBreakerState, FilterChain, FilterChainConfig, FilterChainStats,
FilterChainStatsSnapshot, FilterDirection, FilterResult, FrameEnvelope, PaceFilter,
PaceFilterConfig, PaceFilterStats, PaceFilterStatsSnapshot, PaceState, QueueFilter,
QueueFilterConfig, QueueFilterStats, QueueFilterStatsSnapshot, QueuePriority, RetryFilter,
RetryFilterConfig, RetryFilterStats, RetryFilterStatsSnapshot,
};
pub use frame::{
DibDeviceInfo, FrameBuilder, Hpai, KnxFrame, KnxNetIpHeader, ServiceFamily, ServiceType,
SupportedServiceFamilies,
};
pub use group::{GroupEvent, GroupObject, GroupObjectFlags, GroupObjectTable};
pub use group_cache::{
CacheEntry, CacheEntryInfo, CacheStatsSnapshot, GroupValueCache, GroupValueCacheConfig,
UpdateSource,
};
pub use heartbeat::{
HeartbeatAction, HeartbeatSchedule, HeartbeatScheduler, HeartbeatSchedulerConfig,
HeartbeatStatsSnapshot,
};
pub use metrics::{ConnectionMetricsSnapshot, KnxMetricsCollector, KnxMetricsSnapshot};
pub use runtime::{descriptor, driver};
pub use server::{ConnectionManager, KnxServer, ServerEvent, ServerState};
pub use tunnel::{
AckMessage,
AckResult,
AckValidation,
AckWaiter,
AckWaiterStatsSnapshot,
ConnectRequest,
ConnectResponse,
ConnectionStateRequest,
ConnectionStateResponse,
ConnectionType,
DisconnectRequest,
DisconnectResponse,
FsmStatsSnapshot,
ReceivedValidation,
SequenceStatsSnapshot,
SequenceTracker,
TunnelConnection,
TunnelErrorReason,
TunnelFsm,
TunnelState,
TunnellingAck,
TunnellingRequest,
};
pub type Config = KnxServerConfig;
pub type Server = KnxServer;
pub type Device = KnxDevice;
pub type Factory = KnxDeviceFactory;
pub type Stats = KnxMetricsSnapshot;
pub type Error = KnxError;
pub type Result<T> = KnxResult<T>;
#[derive(Clone, Default)]
pub struct Builder {
config: Config,
group_objects: Option<std::sync::Arc<GroupObjectTable>>,
}
impl Builder {
pub fn new() -> Self {
Self::default()
}
pub fn config(mut self, config: Config) -> Self {
self.config = config;
self
}
pub fn group_objects(mut self, table: std::sync::Arc<GroupObjectTable>) -> Self {
self.group_objects = Some(table);
self
}
pub fn build(self) -> Server {
let server = Server::new(self.config);
if let Some(table) = self.group_objects {
server.with_group_objects(table)
} else {
server
}
}
}
pub const KNXNETIP_VERSION: u8 = 0x10;
pub const DEFAULT_PORT: u16 = 3671;
pub const DEFAULT_MULTICAST_ADDR: &str = "224.0.23.12";
pub mod prelude {
pub use crate::{
DptCodec,
DptId,
DptRegistry,
DptValue,
GroupAddress,
GroupEvent,
GroupObject,
GroupObjectConfig,
GroupObjectTable,
IndividualAddress,
KnxDevice,
KnxDeviceBuilder,
KnxDeviceConfig,
KnxError,
KnxResult,
KnxServer,
KnxServerConfig,
};
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cemi::MessageCode;
#[test]
fn test_group_address_parsing() {
let addr: GroupAddress = "1/2/3".parse().unwrap();
assert_eq!(addr.main(), 1);
assert_eq!(addr.middle(), 2);
assert_eq!(addr.sub(), 3);
assert_eq!(addr.to_string(), "1/2/3");
}
#[test]
fn test_individual_address_parsing() {
let addr: IndividualAddress = "1.2.3".parse().unwrap();
assert_eq!(addr.area(), 1);
assert_eq!(addr.line(), 2);
assert_eq!(addr.device(), 3);
assert_eq!(addr.to_string(), "1.2.3");
}
#[test]
fn test_dpt_id_parsing() {
let dpt: DptId = "1.001".parse().unwrap();
assert_eq!(dpt.main, 1);
assert_eq!(dpt.sub, 1);
assert!(dpt.to_string().contains("1.001"));
}
#[test]
fn test_dpt_registry_lookup() {
let registry = DptRegistry::new();
assert!(registry.get(&DptId::new(1, 1)).is_some());
assert!(registry.get(&DptId::new(5, 1)).is_some());
assert!(registry.get(&DptId::new(9, 1)).is_some());
}
#[test]
fn test_service_type_round_trip() {
let service = ServiceType::TunnellingRequest;
let code: u16 = service.into();
let parsed = ServiceType::try_from(code).unwrap();
assert_eq!(parsed, service);
}
#[test]
fn test_cemi_frame_creation() {
let frame = CemiFrame::group_value_write(
IndividualAddress::new(1, 1, 1),
GroupAddress::three_level(1, 0, 1),
vec![0x00], );
assert_eq!(frame.message_code, MessageCode::LDataInd);
}
#[test]
fn test_group_address_range() {
let range = GroupAddressRange::new(
GroupAddress::three_level(1, 0, 0),
GroupAddress::three_level(1, 0, 255),
);
assert!(range.contains(&GroupAddress::three_level(1, 0, 100)));
assert!(!range.contains(&GroupAddress::three_level(1, 1, 0)));
}
#[test]
fn test_dpt_value_encoding() {
let registry = DptRegistry::new();
let codec = registry.get(&DptId::new(1, 1)).unwrap();
let encoded = codec.encode(&DptValue::Bool(true)).unwrap();
assert_eq!(encoded, vec![0x01]);
let decoded = codec.decode(&[0x01]).unwrap();
assert_eq!(decoded, DptValue::Bool(true));
}
#[test]
fn test_knx_device_builder() {
let device = KnxDeviceBuilder::new("test-device", "Test Device")
.individual_address(IndividualAddress::new(1, 1, 1))
.description("A test device")
.build()
.unwrap();
assert_eq!(device.id(), "test-device");
assert_eq!(device.individual_address().to_string(), "1.1.1");
}
#[test]
fn test_factory_protocol() {
use mabi_core::{DeviceFactory, Protocol};
let factory = KnxDeviceFactory::new();
assert_eq!(factory.protocol(), Protocol::KnxIp);
}
}