//! A pure Rust implementation of MODBUS protocol.
//!
//! `rs-modbus` is designed as a layered architecture, including the physical layer
//! and the application layer:
//!
//! - **Physical layer** implements Serial Port, TCP/IP and UDP/IP.
//! - **Application layer** implements RTU, ASCII and TCP.
//!
//! Both client (master) and server (slave) are provided.
//!
//! ## Features
//!
//! - Full Modbus standard protocol implementation
//! - Support for custom function codes
//! - Support broadcasting
//! - Very lightweight project
//!
//! ### Supported function codes
//!
//! | Code  | Name                           |
//! | ----- | ------------------------------ |
//! | 01    | Read Coils                     |
//! | 02    | Read Discrete Inputs           |
//! | 03    | Read Holding Registers         |
//! | 04    | Read Input Registers           |
//! | 05    | Write Single Coil              |
//! | 06    | Write Single Register          |
//! | 15    | Write Multiple Coils           |
//! | 16    | Write Multiple Registers       |
//! | 17    | Report Server ID               |
//! | 22    | Mask Write Register            |
//! | 23    | Read/Write Multiple Registers  |
//! | 43/14 | Read Device Identification     |
//!
//! ### Supported protocols
//!
//! - Modbus RTU
//! - Modbus ASCII
//! - Modbus TCP/IP
//! - Modbus UDP/IP
//! - Modbus RTU/ASCII Over TCP/IP
//! - Modbus RTU/ASCII Over UDP/IP
//!
//! ## Examples
//!
//! ### Modbus TCP Master
//!
//! ```no_run
//! use rs_modbus::layers::application::TcpApplicationLayer;
//! use rs_modbus::layers::physical::TcpClientPhysicalLayer;
//! use rs_modbus::master::{ModbusMaster, ModbusMasterOptions};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let physical = TcpClientPhysicalLayer::new();
//!     let application = TcpApplicationLayer::new(physical.clone());
//!     let master = ModbusMaster::new(
//!         application,
//!         physical,
//!         ModbusMasterOptions {
//!             timeout_ms: 5000,
//!             concurrent: false,
//!         },
//!     );
//!
//!     master.open(None).await?;
//!     let res = master.read_holding_registers(1, 0, 10, None).await?;
//!     println!("{:?}", res.map(|r| r.data));
//!     master.destroy().await;
//!
//!     Ok(())
//! }
//! ```
//!
//! ### Modbus TCP Slave
//!
//! ```no_run
//! use rs_modbus::layers::application::TcpApplicationLayer;
//! use rs_modbus::layers::physical::TcpServerPhysicalLayer;
//! use rs_modbus::slave::{ModbusSlave, ModbusSlaveModel};
//! use rs_modbus::types::AddressRange;
//! use async_trait::async_trait;
//!
//! struct SimpleModel;
//!
//! #[async_trait]
//! impl ModbusSlaveModel for SimpleModel {
//!     fn unit(&self) -> u8 { 1 }
//!     fn address_range(&self) -> AddressRange {
//!         AddressRange::default()
//!     }
//!     async fn read_holding_registers(
//!         &self, _address: u16, length: u16,
//!     ) -> Result<Vec<u16>, rs_modbus::error::ModbusError> {
//!         Ok(vec![0; length as usize])
//!     }
//! }
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let physical = TcpServerPhysicalLayer::new();
//!     let application = TcpApplicationLayer::new(physical.clone());
//!     let slave = ModbusSlave::new(application, physical);
//!
//!     slave.add(Box::new(SimpleModel));
//!     slave.open(None).await?;
//!
//!     Ok(())
//! }
//! ```

pub mod error;
pub mod layers;
pub mod master;
pub mod master_session;
pub mod slave;
pub mod types;
pub mod utils;
pub mod vars;

// Re-export commonly used types for convenience
pub use error::{get_code_by_error, get_error_by_code, ErrorCode, ModbusError};
pub use layers::application::{ApplicationLayer, ApplicationProtocol, ApplicationRole, Framing};
pub use layers::physical::{ConnectionId, DataEvent, PhysicalLayer, PhysicalLayerType, ResponseFn};
pub use master::{ModbusMaster, ModbusMasterOptions};
pub use master_session::{MasterSession, PreCheck, PreCheckOutcome};
pub use slave::{ModbusSlave, ModbusSlaveModel, ModbusSlaveOptions};
pub use types::{
    AddressRange, ApplicationDataUnit, CustomFunctionCode, DeviceIdentification, DeviceObject,
    FramedDataUnit, MasterResponse, ServerId,
};
pub use vars::{
    limits, ConformityLevel, FunctionCode, ReadDeviceIdCode, COIL_OFF, COIL_ON, EXCEPTION_OFFSET,
    MEI_READ_DEVICE_ID,
};
