Skip to main content

knx_rs_ip/
lib.rs

1// SPDX-License-Identifier: GPL-3.0-only
2// Copyright (C) 2026 Fabian Schmieder
3
4//! `knx-ip` — async KNXnet/IP tunnel and router connections.
5//!
6//! This crate provides a complete async KNXnet/IP implementation:
7//!
8//! - [`TunnelConnection`] — unicast tunnel with retry, heartbeat, auto-reconnect
9//! - [`RouterConnection`] — multicast routing with rate limiting (50 pkt/s)
10//! - [`discovery`] — gateway discovery on the local network
11//! - [`Multiplexer`] / [`MultiplexHandle`] — fan out one connection to many handles
12//! - [`connect`] / [`parse_url`] — URL-based connection factory
13//!
14//! # Example
15//!
16//! ```rust,no_run
17//! use knx_rs_ip::{connect, ConnectionSpec};
18//!
19//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
20//! let spec = ConnectionSpec::Tunnel("192.168.1.50:3671".parse()?);
21//! let mut conn = connect(spec).await?;
22//! // conn.send(...) / conn.recv() ...
23//! # Ok(())
24//! # }
25//! ```
26
27mod error;
28mod router;
29mod tunnel;
30pub mod tunnel_server;
31mod url;
32
33pub mod discovery;
34pub mod multiplex;
35pub mod ops;
36
37pub use error::KnxIpError;
38pub use multiplex::{MultiplexHandle, Multiplexer};
39pub use router::{KNX_MULTICAST_ADDR, KNX_PORT, RouterConnection};
40pub use tunnel::{TunnelConfig, TunnelConnection};
41pub use tunnel_server::{DeviceServer, ServerEvent};
42pub use url::{ConnectionSpec, connect, parse_url};
43
44use knx_rs_core::cemi::CemiFrame;
45
46/// Trait for KNXnet/IP connections that can send and receive CEMI frames.
47///
48/// Both tunnel (unicast) and router (multicast) connections implement this.
49#[allow(async_fn_in_trait)] // All impls are Send — we control the full set
50pub trait KnxConnection: Send {
51    /// Send a CEMI frame to the KNX bus.
52    ///
53    /// # Errors
54    ///
55    /// Returns [`KnxIpError`] if the frame could not be sent.
56    async fn send(&self, frame: CemiFrame) -> Result<(), KnxIpError>;
57
58    /// Receive the next CEMI frame from the KNX bus.
59    ///
60    /// Returns `None` if the connection is closed.
61    async fn recv(&mut self) -> Option<CemiFrame>;
62
63    /// Close the connection gracefully.
64    async fn close(&mut self);
65}
66
67/// A type-erased KNX connection — either tunnel or router.
68///
69/// Returned by [`connect()`] when the connection type is determined at runtime.
70pub enum AnyConnection {
71    /// Tunnel connection.
72    Tunnel(TunnelConnection),
73    /// Router connection.
74    Router(RouterConnection),
75}
76
77impl KnxConnection for AnyConnection {
78    async fn send(&self, frame: CemiFrame) -> Result<(), KnxIpError> {
79        match self {
80            Self::Tunnel(c) => c.send(frame).await,
81            Self::Router(c) => c.send(frame).await,
82        }
83    }
84
85    async fn recv(&mut self) -> Option<CemiFrame> {
86        match self {
87            Self::Tunnel(c) => c.recv().await,
88            Self::Router(c) => c.recv().await,
89        }
90    }
91
92    async fn close(&mut self) {
93        match self {
94            Self::Tunnel(c) => c.close().await,
95            Self::Router(c) => c.close().await,
96        }
97    }
98}