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 core::future::Future;
45use core::pin::Pin;
46
47use knx_rs_core::cemi::CemiFrame;
48
49/// Boxed `Send` future returned by KNX connection traits.
50pub type KnxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
51
52/// Trait for KNXnet/IP connections that can send and receive CEMI frames.
53///
54/// Both tunnel (unicast) and router (multicast) connections implement this.
55pub trait KnxConnection: Send {
56    /// Send a CEMI frame to the KNX bus.
57    ///
58    /// # Errors
59    ///
60    /// Returns [`KnxIpError`] if the frame could not be sent.
61    fn send(&self, frame: CemiFrame) -> KnxFuture<'_, Result<(), KnxIpError>>;
62
63    /// Receive the next CEMI frame from the KNX bus.
64    ///
65    /// Returns `None` if the connection is closed.
66    fn recv(&mut self) -> KnxFuture<'_, Option<CemiFrame>>;
67
68    /// Close the connection gracefully.
69    fn close(&mut self) -> KnxFuture<'_, ()>;
70}
71
72/// A type-erased KNX connection — either tunnel or router.
73///
74/// Returned by [`connect()`] when the connection type is determined at runtime.
75pub enum AnyConnection {
76    /// Tunnel connection.
77    Tunnel(TunnelConnection),
78    /// Router connection.
79    Router(RouterConnection),
80}
81
82impl KnxConnection for AnyConnection {
83    fn send(&self, frame: CemiFrame) -> KnxFuture<'_, Result<(), KnxIpError>> {
84        match self {
85            Self::Tunnel(c) => c.send(frame),
86            Self::Router(c) => c.send(frame),
87        }
88    }
89
90    fn recv(&mut self) -> KnxFuture<'_, Option<CemiFrame>> {
91        match self {
92            Self::Tunnel(c) => c.recv(),
93            Self::Router(c) => c.recv(),
94        }
95    }
96
97    fn close(&mut self) -> KnxFuture<'_, ()> {
98        match self {
99            Self::Tunnel(c) => c.close(),
100            Self::Router(c) => c.close(),
101        }
102    }
103}