提交 95eb55b6 authored 作者: Serhij S's avatar Serhij S

added missing docs

上级 2bb1cb92
...@@ -9,8 +9,10 @@ use std::{ ...@@ -9,8 +9,10 @@ use std::{
use crate::Result; use crate::Result;
pub mod serial; // Serial communications /// Serial communications
pub mod tcp; // TCP communications pub mod serial;
/// TCP communications
pub mod tcp;
/// A versatile (TCP/serial) client /// A versatile (TCP/serial) client
#[derive(Clone)] #[derive(Clone)]
...@@ -83,12 +85,14 @@ impl Write for Client { ...@@ -83,12 +85,14 @@ impl Write for Client {
} }
} }
/// A guard for the session lock
pub struct SessionGuard { pub struct SessionGuard {
client: Client, client: Client,
session_id: usize, session_id: usize,
} }
impl SessionGuard { impl SessionGuard {
/// Get the session id
pub fn session_id(&self) -> usize { pub fn session_id(&self) -> usize {
self.session_id self.session_id
} }
...@@ -100,11 +104,15 @@ impl Drop for SessionGuard { ...@@ -100,11 +104,15 @@ impl Drop for SessionGuard {
} }
} }
/// Communication protocol
pub enum Protocol { pub enum Protocol {
/// TCP
Tcp, Tcp,
/// Serial
Serial, Serial,
} }
/// Stream trait
pub trait Stream: Read + Write + Send {} pub trait Stream: Read + Write + Send {}
trait Communicator { trait Communicator {
...@@ -122,12 +130,14 @@ trait Communicator { ...@@ -122,12 +130,14 @@ trait Communicator {
fn unlock_session(&self); fn unlock_session(&self);
} }
/// A communication reader container (used to pass the reader via policy channels)
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub struct CommReader { pub struct CommReader {
reader: Option<Box<dyn Read + Send + 'static>>, reader: Option<Box<dyn Read + Send + 'static>>,
} }
impl CommReader { impl CommReader {
/// Take reader from the container
pub fn take(&mut self) -> Option<Box<dyn Read + Send + 'static>> { pub fn take(&mut self) -> Option<Box<dyn Read + Send + 'static>> {
self.reader.take() self.reader.take()
} }
...@@ -137,10 +147,14 @@ impl DataDeliveryPolicy for CommReader {} ...@@ -137,10 +147,14 @@ impl DataDeliveryPolicy for CommReader {}
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(1); const DEFAULT_TIMEOUT: Duration = Duration::from_secs(1);
/// Timeouts
#[derive(Clone)] #[derive(Clone)]
pub struct Timeouts { pub struct Timeouts {
/// Connect timeout
pub connect: Duration, pub connect: Duration,
/// Read timeout
pub read: Duration, pub read: Duration,
/// Write timeout
pub write: Duration, pub write: Duration,
} }
...@@ -151,6 +165,7 @@ impl Default for Timeouts { ...@@ -151,6 +165,7 @@ impl Default for Timeouts {
} }
impl Timeouts { impl Timeouts {
/// Create new timeouts with the default value
pub fn new(default: Duration) -> Self { pub fn new(default: Duration) -> Self {
Self { Self {
connect: default, connect: default,
...@@ -158,6 +173,7 @@ impl Timeouts { ...@@ -158,6 +173,7 @@ impl Timeouts {
write: default, write: default,
} }
} }
/// Create new timeouts with zero values
pub fn none() -> Self { pub fn none() -> Self {
Self { Self {
connect: Duration::from_secs(0), connect: Duration::from_secs(0),
...@@ -167,6 +183,7 @@ impl Timeouts { ...@@ -167,6 +183,7 @@ impl Timeouts {
} }
} }
/// Connection handler object, used to perform initial chat in custom protocols
pub trait ConnectionHandler { pub trait ConnectionHandler {
/// called right after the connection is established /// called right after the connection is established
fn on_connect( fn on_connect(
......
...@@ -24,12 +24,18 @@ pub fn connect(path: &str, timeout: Duration, frame_delay: Duration) -> Result<C ...@@ -24,12 +24,18 @@ pub fn connect(path: &str, timeout: Duration, frame_delay: Duration) -> Result<C
Ok(Client(Serial::create(path, timeout, frame_delay)?)) Ok(Client(Serial::create(path, timeout, frame_delay)?))
} }
/// Serial port parameters
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Parameters { pub struct Parameters {
/// Serial port device path
pub port_dev: String, pub port_dev: String,
/// Baud rate
pub baud_rate: serial::BaudRate, pub baud_rate: serial::BaudRate,
/// Character size
pub char_size: serial::CharSize, pub char_size: serial::CharSize,
/// Parity
pub parity: serial::Parity, pub parity: serial::Parity,
/// Stop bits
pub stop_bits: serial::StopBits, pub stop_bits: serial::StopBits,
} }
...@@ -111,6 +117,7 @@ fn parse_path(path: &str) -> Result<Parameters> { ...@@ -111,6 +117,7 @@ fn parse_path(path: &str) -> Result<Parameters> {
}) })
} }
/// Open a serial port
pub fn open(params: &Parameters, timeout: Duration) -> Result<SystemPort> { pub fn open(params: &Parameters, timeout: Duration) -> Result<SystemPort> {
let mut port = serial::open(&params.port_dev).map_err(Error::io)?; let mut port = serial::open(&params.port_dev).map_err(Error::io)?;
port.reconfigure(&|settings| { port.reconfigure(&|settings| {
...@@ -128,6 +135,7 @@ pub fn open(params: &Parameters, timeout: Duration) -> Result<SystemPort> { ...@@ -128,6 +135,7 @@ pub fn open(params: &Parameters, timeout: Duration) -> Result<SystemPort> {
Ok(port) Ok(port)
} }
/// Serial port client
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub struct Serial { pub struct Serial {
port: Mutex<SPort>, port: Mutex<SPort>,
...@@ -145,6 +153,7 @@ struct SPort { ...@@ -145,6 +153,7 @@ struct SPort {
last_frame: Option<Instant>, last_frame: Option<Instant>,
} }
/// Serial port client type
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub type SerialClient = Arc<Serial>; pub type SerialClient = Arc<Serial>;
...@@ -218,6 +227,7 @@ impl Communicator for Serial { ...@@ -218,6 +227,7 @@ impl Communicator for Serial {
} }
impl Serial { impl Serial {
/// Create a new serial client
pub fn create(path: &str, timeout: Duration, frame_delay: Duration) -> Result<Arc<Self>> { pub fn create(path: &str, timeout: Duration, frame_delay: Duration) -> Result<Arc<Self>> {
let params = parse_path(path)?; let params = parse_path(path)?;
Ok(Self { Ok(Self {
......
...@@ -38,6 +38,7 @@ pub fn connect_with_options<A: ToSocketAddrs + fmt::Debug>( ...@@ -38,6 +38,7 @@ pub fn connect_with_options<A: ToSocketAddrs + fmt::Debug>(
impl Stream for TcpStream {} impl Stream for TcpStream {}
/// A TCP client structure
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub struct Tcp { pub struct Tcp {
addr: SocketAddr, addr: SocketAddr,
...@@ -50,6 +51,7 @@ pub struct Tcp { ...@@ -50,6 +51,7 @@ pub struct Tcp {
connection_handler: Option<Box<dyn ConnectionHandler + Send + Sync>>, connection_handler: Option<Box<dyn ConnectionHandler + Send + Sync>>,
} }
/// A TCP client type
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub type TcpClient = Arc<Tcp>; pub type TcpClient = Arc<Tcp>;
......
...@@ -23,6 +23,7 @@ use signal_hook::{ ...@@ -23,6 +23,7 @@ use signal_hook::{
}; };
use tracing::error; use tracing::error;
/// Controller prelude
pub mod prelude { pub mod prelude {
pub use super::{Context, Controller, WResult, Worker, WorkerOptions}; pub use super::{Context, Controller, WResult, Worker, WorkerOptions};
pub use roboplc_derive::WorkerOpts; pub use roboplc_derive::WorkerOpts;
...@@ -31,6 +32,7 @@ pub mod prelude { ...@@ -31,6 +32,7 @@ pub mod prelude {
/// Result type, which must be returned by workers' `run` method /// Result type, which must be returned by workers' `run` method
pub type WResult = std::result::Result<(), Box<dyn std::error::Error + Send + Sync>>; pub type WResult = std::result::Result<(), Box<dyn std::error::Error + Send + Sync>>;
/// Sleep step (used in blocking)
pub const SLEEP_STEP: Duration = Duration::from_millis(100); pub const SLEEP_STEP: Duration = Duration::from_millis(100);
/// Controller state beacon. Can be cloned and shared with no limitations. /// Controller state beacon. Can be cloned and shared with no limitations.
...@@ -40,7 +42,7 @@ pub struct State { ...@@ -40,7 +42,7 @@ pub struct State {
} }
impl State { impl State {
pub fn new() -> Self { fn new() -> Self {
Self { Self {
state: AtomicI8::new(ControllerStateKind::Starting as i8).into(), state: AtomicI8::new(ControllerStateKind::Starting as i8).into(),
} }
...@@ -71,11 +73,17 @@ impl Default for State { ...@@ -71,11 +73,17 @@ impl Default for State {
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub enum ControllerStateKind { pub enum ControllerStateKind {
#[default] #[default]
/// The controller is starting
Starting = 0, Starting = 0,
/// The controller is active (accepting tasks)
Active = 1, Active = 1,
/// The controller is running (tasks are being executed)
Running = 2, Running = 2,
/// The controller is stopping
Stopping = -1, Stopping = -1,
/// The controller is stopped
Stopped = -100, Stopped = -100,
/// The controller state is unknown
Unknown = -128, Unknown = -128,
} }
......
...@@ -10,6 +10,7 @@ use self::prelude::DataChannel; ...@@ -10,6 +10,7 @@ use self::prelude::DataChannel;
type ConditionFunction<T> = Box<dyn Fn(&T) -> bool + Send + Sync>; type ConditionFunction<T> = Box<dyn Fn(&T) -> bool + Send + Sync>;
/// The hub prelude
pub mod prelude { pub mod prelude {
pub use super::Hub; pub use super::Hub;
pub use crate::event_matches; pub use crate::event_matches;
...@@ -17,8 +18,10 @@ pub mod prelude { ...@@ -17,8 +18,10 @@ pub mod prelude {
pub use rtsc::DataChannel; pub use rtsc::DataChannel;
} }
/// The default priority for the client channel
pub const DEFAULT_PRIORITY: usize = 100; pub const DEFAULT_PRIORITY: usize = 100;
/// The default client channel capacity
pub const DEFAULT_CHANNEL_CAPACITY: usize = 1024; pub const DEFAULT_CHANNEL_CAPACITY: usize = 1024;
/// Sync data communcation hub to implement in-process pub/sub model for thread workers /// Sync data communcation hub to implement in-process pub/sub model for thread workers
...@@ -43,6 +46,7 @@ impl<T: DataDeliveryPolicy + Clone> Default for Hub<T> { ...@@ -43,6 +46,7 @@ impl<T: DataDeliveryPolicy + Clone> Default for Hub<T> {
} }
impl<T: DataDeliveryPolicy + Clone> Hub<T> { impl<T: DataDeliveryPolicy + Clone> Hub<T> {
/// Creates a new hub with default settings
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
...@@ -238,6 +242,7 @@ where ...@@ -238,6 +242,7 @@ where
} }
} }
/// A client for the hub
pub struct Client<T: DataDeliveryPolicy + Clone> { pub struct Client<T: DataDeliveryPolicy + Clone> {
name: Arc<str>, name: Arc<str>,
hub: Hub<T>, hub: Hub<T>,
...@@ -285,6 +290,7 @@ impl<T: DataDeliveryPolicy + Clone> Drop for Client<T> { ...@@ -285,6 +290,7 @@ impl<T: DataDeliveryPolicy + Clone> Drop for Client<T> {
} }
} }
/// Client options
pub struct ClientOptions<T: DataDeliveryPolicy + Clone> { pub struct ClientOptions<T: DataDeliveryPolicy + Clone> {
name: Arc<str>, name: Arc<str>,
priority: usize, priority: usize,
...@@ -294,6 +300,7 @@ pub struct ClientOptions<T: DataDeliveryPolicy + Clone> { ...@@ -294,6 +300,7 @@ pub struct ClientOptions<T: DataDeliveryPolicy + Clone> {
} }
impl<T: DataDeliveryPolicy + Clone> ClientOptions<T> { impl<T: DataDeliveryPolicy + Clone> ClientOptions<T> {
/// Creates a new client options object
pub fn new<F>(name: &str, condition: F) -> Self pub fn new<F>(name: &str, condition: F) -> Self
where where
F: Fn(&T) -> bool + Send + Sync + 'static, F: Fn(&T) -> bool + Send + Sync + 'static,
......
...@@ -8,8 +8,10 @@ use crate::{DataDeliveryPolicy, Error, Result}; ...@@ -8,8 +8,10 @@ use crate::{DataDeliveryPolicy, Error, Result};
type ConditionFunction<T> = Box<dyn Fn(&T) -> bool + Send + Sync>; type ConditionFunction<T> = Box<dyn Fn(&T) -> bool + Send + Sync>;
/// The default priority for the client channel
pub const DEFAULT_PRIORITY: usize = 100; pub const DEFAULT_PRIORITY: usize = 100;
/// The default client channel capacity
pub const DEFAULT_CHANNEL_CAPACITY: usize = 1024; pub const DEFAULT_CHANNEL_CAPACITY: usize = 1024;
/// Async data communcation hub to implement in-process pub/sub model for thread workers /// Async data communcation hub to implement in-process pub/sub model for thread workers
...@@ -34,6 +36,7 @@ impl<T: DataDeliveryPolicy + Clone> Default for Hub<T> { ...@@ -34,6 +36,7 @@ impl<T: DataDeliveryPolicy + Clone> Default for Hub<T> {
} }
impl<T: DataDeliveryPolicy + Clone> Hub<T> { impl<T: DataDeliveryPolicy + Clone> Hub<T> {
/// Creates a new hub instance
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
...@@ -191,6 +194,7 @@ where ...@@ -191,6 +194,7 @@ where
} }
} }
/// A client for the hub
pub struct Client<T: DataDeliveryPolicy + Clone> { pub struct Client<T: DataDeliveryPolicy + Clone> {
name: Arc<str>, name: Arc<str>,
hub: Hub<T>, hub: Hub<T>,
...@@ -232,6 +236,7 @@ impl<T: DataDeliveryPolicy + Clone> Drop for Client<T> { ...@@ -232,6 +236,7 @@ impl<T: DataDeliveryPolicy + Clone> Drop for Client<T> {
} }
} }
/// Client options
pub struct ClientOptions<T: DataDeliveryPolicy + Clone> { pub struct ClientOptions<T: DataDeliveryPolicy + Clone> {
name: Arc<str>, name: Arc<str>,
priority: usize, priority: usize,
...@@ -241,6 +246,7 @@ pub struct ClientOptions<T: DataDeliveryPolicy + Clone> { ...@@ -241,6 +246,7 @@ pub struct ClientOptions<T: DataDeliveryPolicy + Clone> {
} }
impl<T: DataDeliveryPolicy + Clone> ClientOptions<T> { impl<T: DataDeliveryPolicy + Clone> ClientOptions<T> {
/// Creates a new client options object
pub fn new<F>(name: &str, condition: F) -> Self pub fn new<F>(name: &str, condition: F) -> Self
where where
F: Fn(&T) -> bool + Send + Sync + 'static, F: Fn(&T) -> bool + Send + Sync + 'static,
......
...@@ -103,6 +103,7 @@ where ...@@ -103,6 +103,7 @@ where
} }
config config
} }
/// Creates a new EAPI connection configuration with the given path
pub fn new(path: &str) -> Self { pub fn new(path: &str) -> Self {
Self { Self {
path: path.to_owned(), path: path.to_owned(),
...@@ -140,10 +141,12 @@ where ...@@ -140,10 +141,12 @@ where
self.reconnect_delay = reconnect_delay; self.reconnect_delay = reconnect_delay;
self self
} }
/// Set action handler for the given OID
pub fn action_handler(mut self, oid: OID, handler: ActionHandlerFn<D, V>) -> Self { pub fn action_handler(mut self, oid: OID, handler: ActionHandlerFn<D, V>) -> Self {
self.action_handlers.insert(oid, handler); self.action_handlers.insert(oid, handler);
self self
} }
/// Set bulk action handler for the given OID mask
pub fn bulk_action_handler(mut self, mask: OIDMask, handler: ActionHandlerFn<D, V>) -> Self { pub fn bulk_action_handler(mut self, mask: OIDMask, handler: ActionHandlerFn<D, V>) -> Self {
self.bulk_action_handlers.push((mask, handler)); self.bulk_action_handlers.push((mask, handler));
self self
...@@ -467,6 +470,7 @@ where ...@@ -467,6 +470,7 @@ where
warn!(client = self.inner.name, "disconnected from EAPI bus"); warn!(client = self.inner.name, "disconnected from EAPI bus");
Ok(()) Ok(())
} }
/// Pushes a data object to the EVA ICS node core
pub fn dobj_push<T>(&self, name: Arc<String>, value: T) -> Result<()> pub fn dobj_push<T>(&self, name: Arc<String>, value: T) -> Result<()>
where where
T: for<'a> BinWrite<Args<'a> = ()>, T: for<'a> BinWrite<Args<'a> = ()>,
...@@ -481,12 +485,14 @@ where ...@@ -481,12 +485,14 @@ where
}) })
.map_err(Into::into) .map_err(Into::into)
} }
/// Pushes a data object error to the EVA ICS node core
pub fn dobj_error(&self, name: Arc<String>) -> Result<()> { pub fn dobj_error(&self, name: Arc<String>) -> Result<()> {
self.inner self.inner
.tx .tx
.try_send(PushPayload::DObjError(name)) .try_send(PushPayload::DObjError(name))
.map_err(Into::into) .map_err(Into::into)
} }
/// Pushes a state event to the EVA ICS node core
pub fn state_push<T: Serialize>(&self, oid: Arc<OID>, value: T) -> Result<()> { pub fn state_push<T: Serialize>(&self, oid: Arc<OID>, value: T) -> Result<()> {
self.inner self.inner
.tx .tx
...@@ -496,12 +502,14 @@ where ...@@ -496,12 +502,14 @@ where
}) })
.map_err(Into::into) .map_err(Into::into)
} }
/// Pushes a custom (raw) state event to the EVA ICS node core
pub fn raw_state_push(&self, oid: Arc<OID>, event: RawStateEventOwned) -> Result<()> { pub fn raw_state_push(&self, oid: Arc<OID>, event: RawStateEventOwned) -> Result<()> {
self.inner self.inner
.tx .tx
.try_send(PushPayload::State { oid, event }) .try_send(PushPayload::State { oid, event })
.map_err(Into::into) .map_err(Into::into)
} }
/// Pushes a state error event to the EVA ICS node core
pub fn state_error(&self, oid: Arc<OID>) -> Result<()> { pub fn state_error(&self, oid: Arc<OID>) -> Result<()> {
self.inner self.inner
.tx .tx
......
...@@ -19,17 +19,22 @@ pub mod pipe; ...@@ -19,17 +19,22 @@ pub mod pipe;
/// Raw UDP communication /// Raw UDP communication
pub mod raw_udp; pub mod raw_udp;
/// Generic I/O mapping trait
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub trait IoMapping { pub trait IoMapping {
/// Options for the mapping
type Options; type Options;
/// Read data from the raw buffer
fn read<T>(&mut self) -> Result<T> fn read<T>(&mut self) -> Result<T>
where where
T: for<'a> BinRead<Args<'a> = ()>; T: for<'a> BinRead<Args<'a> = ()>;
/// Write data to the raw buffer
fn write<T>(&mut self, value: T) -> Result<()> fn write<T>(&mut self, value: T) -> Result<()>
where where
T: for<'a> BinWrite<Args<'a> = ()>; T: for<'a> BinWrite<Args<'a> = ()>;
} }
/// I/O mapping prelude
pub mod prelude { pub mod prelude {
pub use super::IoMapping as _; pub use super::IoMapping as _;
pub use binrw::prelude::*; pub use binrw::prelude::*;
......
...@@ -26,6 +26,7 @@ use super::IoMapping; ...@@ -26,6 +26,7 @@ use super::IoMapping;
mod regs; mod regs;
mod server; mod server;
/// Modbus prelude
pub mod prelude { pub mod prelude {
pub use super::{ pub use super::{
ModbusMapping, ModbusMappingOptions, ModbusRegister, ModbusRegisterKind, ModbusServer, ModbusMapping, ModbusMappingOptions, ModbusRegister, ModbusRegisterKind, ModbusServer,
...@@ -35,6 +36,7 @@ pub mod prelude { ...@@ -35,6 +36,7 @@ pub mod prelude {
/// Swaps endianess of floating point numbers in case of non-standard IEEE 754 layout. /// Swaps endianess of floating point numbers in case of non-standard IEEE 754 layout.
pub trait SwapModbusEndianess { pub trait SwapModbusEndianess {
/// Swaps endianess of floating point numbers in case of non-standard IEEE 754 layout.
fn to_swapped_modbus_endianness(&self) -> Self; fn to_swapped_modbus_endianness(&self) -> Self;
} }
...@@ -69,9 +71,11 @@ pub struct ModbusMappingOptions { ...@@ -69,9 +71,11 @@ pub struct ModbusMappingOptions {
} }
impl ModbusMappingOptions { impl ModbusMappingOptions {
/// Creates new options for Modbus value mapping
pub fn new() -> Self { pub fn new() -> Self {
Self { bulk_write: true } Self { bulk_write: true }
} }
/// Enables or disables bulk writes
pub fn bulk_write(mut self, value: bool) -> Self { pub fn bulk_write(mut self, value: bool) -> Self {
self.bulk_write = value; self.bulk_write = value;
self self
...@@ -99,6 +103,7 @@ pub struct ModbusMapping { ...@@ -99,6 +103,7 @@ pub struct ModbusMapping {
} }
impl ModbusMapping { impl ModbusMapping {
/// Creates new Modbus value mapping
pub fn create<R>(client: &Client, unit_id: u8, register: R, count: u16) -> Result<Self> pub fn create<R>(client: &Client, unit_id: u8, register: R, count: u16) -> Result<Self>
where where
R: TryInto<ModbusRegister>, R: TryInto<ModbusRegister>,
...@@ -117,6 +122,7 @@ impl ModbusMapping { ...@@ -117,6 +122,7 @@ impl ModbusMapping {
options: <_>::default(), options: <_>::default(),
}) })
} }
/// Sets options for Modbus value mapping
pub fn with_options(mut self, options: ModbusMappingOptions) -> Self { pub fn with_options(mut self, options: ModbusMappingOptions) -> Self {
self.options = options; self.options = options;
self self
......
...@@ -5,20 +5,27 @@ use crate::{Error, Result}; ...@@ -5,20 +5,27 @@ use crate::{Error, Result};
/// A Modbus register kind. /// A Modbus register kind.
#[derive(Eq, PartialEq, Copy, Clone, Debug)] #[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Kind { pub enum Kind {
/// Coil register (boolean)
Coil, Coil,
/// Discrete register (boolean)
Discrete, Discrete,
/// Input register (16-bit)
Input, Input,
/// Holding register (16-bit)
Holding, Holding,
} }
/// A Modbus register type, contains the kind and the offset. /// A Modbus register type, contains the kind and the offset.
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Register { pub struct Register {
/// The register kind.
pub kind: Kind, pub kind: Kind,
/// The register offset.
pub offset: u16, pub offset: u16,
} }
impl Register { impl Register {
/// Creates a new register.
pub fn new(kind: Kind, offset: u16) -> Self { pub fn new(kind: Kind, offset: u16) -> Self {
Self { kind, offset } Self { kind, offset }
} }
......
...@@ -88,8 +88,10 @@ fn handle_client< ...@@ -88,8 +88,10 @@ fn handle_client<
Ok(()) Ok(())
} }
/// Function to block certain context storage
pub type AllowFn = fn(ModbusRegisterKind, std::ops::Range<u16>) -> WritePermission; pub type AllowFn = fn(ModbusRegisterKind, std::ops::Range<u16>) -> WritePermission;
/// Context storage write permission
pub enum WritePermission { pub enum WritePermission {
/// Write is allowed. /// Write is allowed.
Allow, Allow,
...@@ -126,6 +128,7 @@ pub struct ModbusServer<const C: usize, const D: usize, const I: usize, const H: ...@@ -126,6 +128,7 @@ pub struct ModbusServer<const C: usize, const D: usize, const I: usize, const H:
allow_external_write_fn: Arc<AllowFn>, allow_external_write_fn: Arc<AllowFn>,
} }
impl<const C: usize, const D: usize, const I: usize, const H: usize> ModbusServer<C, D, I, H> { impl<const C: usize, const D: usize, const I: usize, const H: usize> ModbusServer<C, D, I, H> {
/// Creates new Modbus server
pub fn bind( pub fn bind(
protocol: Protocol, protocol: Protocol,
unit: u8, unit: u8,
...@@ -152,6 +155,7 @@ impl<const C: usize, const D: usize, const I: usize, const H: usize> ModbusServe ...@@ -152,6 +155,7 @@ impl<const C: usize, const D: usize, const I: usize, const H: usize> ModbusServe
pub fn set_allow_external_write_fn(&mut self, f: AllowFn) { pub fn set_allow_external_write_fn(&mut self, f: AllowFn) {
self.allow_external_write_fn = f.into(); self.allow_external_write_fn = f.into();
} }
/// Creates a new mapping for the server storage context.
pub fn mapping(&self, register: ModbusRegister, count: u16) -> ModbusServerMapping<C, D, I, H> { pub fn mapping(&self, register: ModbusRegister, count: u16) -> ModbusServerMapping<C, D, I, H> {
let buf_capacity = match register.kind { let buf_capacity = match register.kind {
ModbusRegisterKind::Coil | ModbusRegisterKind::Discrete => usize::from(count), ModbusRegisterKind::Coil | ModbusRegisterKind::Discrete => usize::from(count),
...@@ -164,9 +168,11 @@ impl<const C: usize, const D: usize, const I: usize, const H: usize> ModbusServe ...@@ -164,9 +168,11 @@ impl<const C: usize, const D: usize, const I: usize, const H: usize> ModbusServe
data_buf: Vec::with_capacity(buf_capacity), data_buf: Vec::with_capacity(buf_capacity),
} }
} }
/// Returns a reference to the internal storage.
pub fn storage(&self) -> Arc<Mutex<ModbusStorage<C, D, I, H>>> { pub fn storage(&self) -> Arc<Mutex<ModbusStorage<C, D, I, H>>> {
self.storage.clone() self.storage.clone()
} }
/// Runs the server. This function blocks the current thread.
pub fn serve(&mut self) -> Result<()> { pub fn serve(&mut self) -> Result<()> {
let timeout = self.timeout; let timeout = self.timeout;
let unit = self.unit; let unit = self.unit;
......
//! Data processing with subprocesses
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
ffi::{OsStr, OsString}, ffi::{OsStr, OsString},
...@@ -17,16 +18,19 @@ use crate::{ ...@@ -17,16 +18,19 @@ use crate::{
DataDeliveryPolicy, Result, DataDeliveryPolicy, Result,
}; };
/// Pipe reader
pub struct Reader { pub struct Reader {
rx: Receiver<String>, rx: Receiver<String>,
} }
impl Reader { impl Reader {
/// Reads a line from the pipe. Blocks until a line is available.
pub fn line(&self) -> Result<String> { pub fn line(&self) -> Result<String> {
self.rx.recv_blocking().map_err(Into::into) self.rx.recv_blocking().map_err(Into::into)
} }
} }
/// Data pipe with a subprocess
pub struct Pipe { pub struct Pipe {
program: OsString, program: OsString,
args: Vec<OsString>, args: Vec<OsString>,
...@@ -37,6 +41,7 @@ pub struct Pipe { ...@@ -37,6 +41,7 @@ pub struct Pipe {
} }
impl Pipe { impl Pipe {
/// Creates a new pipe with a subprocess
pub fn new<P: AsRef<OsStr>>(program: P) -> (Self, Reader) { pub fn new<P: AsRef<OsStr>>(program: P) -> (Self, Reader) {
let (tx, rx) = pchannel_async::bounded(10); let (tx, rx) = pchannel_async::bounded(10);
( (
...@@ -51,19 +56,23 @@ impl Pipe { ...@@ -51,19 +56,23 @@ impl Pipe {
Reader { rx }, Reader { rx },
) )
} }
/// Adds a command line argument
pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
self.args.push(arg.as_ref().to_owned()); self.args.push(arg.as_ref().to_owned());
self self
} }
/// Adds multiple command line arguments
pub fn args(&mut self, args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> &mut Self { pub fn args(&mut self, args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> &mut Self {
self.args self.args
.extend(args.into_iter().map(|x| x.as_ref().to_owned())); .extend(args.into_iter().map(|x| x.as_ref().to_owned()));
self self
} }
/// Adds an environment variable
pub fn env(&mut self, key: impl Into<String>, value: impl Into<String>) -> &mut Self { pub fn env(&mut self, key: impl Into<String>, value: impl Into<String>) -> &mut Self {
self.environment.insert(key.into(), value.into()); self.environment.insert(key.into(), value.into());
self self
} }
/// Adds multiple environment variables
pub fn envs( pub fn envs(
&mut self, &mut self,
envs: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>, envs: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
...@@ -77,6 +86,7 @@ impl Pipe { ...@@ -77,6 +86,7 @@ impl Pipe {
self.input_data = Some(data.into()); self.input_data = Some(data.into());
self self
} }
/// Delay before restarting the subprocess after it terminates
pub fn restart_delay(&mut self, delay: Duration) -> &mut Self { pub fn restart_delay(&mut self, delay: Duration) -> &mut Self {
self.restart_delay = delay; self.restart_delay = delay;
self self
......
...@@ -26,6 +26,7 @@ impl<T> UdpReceiver<T> ...@@ -26,6 +26,7 @@ impl<T> UdpReceiver<T>
where where
T: for<'a> BinRead<Args<'a> = ()>, T: for<'a> BinRead<Args<'a> = ()>,
{ {
/// Binds to the specified address and creates a new receiver
pub fn bind<A: ToSocketAddrs>(addr: A, buf_size: usize) -> Result<Self> { pub fn bind<A: ToSocketAddrs>(addr: A, buf_size: usize) -> Result<Self> {
let server = UdpSocket::bind(addr)?; let server = UdpSocket::bind(addr)?;
Ok(Self { Ok(Self {
...@@ -70,6 +71,7 @@ impl<T> UdpSender<T> ...@@ -70,6 +71,7 @@ impl<T> UdpSender<T>
where where
T: for<'a> BinWrite<Args<'a> = ()>, T: for<'a> BinWrite<Args<'a> = ()>,
{ {
/// Connects to the specified address and creates a new sender
pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self> { pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self> {
let socket = UdpSocket::bind(("0.0.0.0", 0))?; let socket = UdpSocket::bind(("0.0.0.0", 0))?;
let target = addr let target = addr
...@@ -84,6 +86,7 @@ where ...@@ -84,6 +86,7 @@ where
}) })
} }
/// Sends a value to the target address
pub fn send(&mut self, value: T) -> Result<()> { pub fn send(&mut self, value: T) -> Result<()> {
let mut buf = Cursor::new(&mut self.data_buf); let mut buf = Cursor::new(&mut self.data_buf);
value.write_le(&mut buf)?; value.write_le(&mut buf)?;
......
#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "README.md" ) ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "README.md" ) ) ]
#![deny(missing_docs)]
use core::{fmt, num}; use core::{fmt, num};
use std::io::Write; use std::io::Write;
use std::panic::PanicInfo; use std::panic::PanicInfo;
...@@ -41,6 +42,7 @@ pub mod supervisor; ...@@ -41,6 +42,7 @@ pub mod supervisor;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub mod thread_rt; pub mod thread_rt;
/// The crate result type
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
/// The crate error type /// The crate error type
...@@ -71,7 +73,7 @@ pub enum Error { ...@@ -71,7 +73,7 @@ pub enum Error {
/// Standard I/O errors /// Standard I/O errors
#[error("I/O error: {0}")] #[error("I/O error: {0}")]
IO(#[from] std::io::Error), IO(#[from] std::io::Error),
// Non-standard I/O errors /// Non-standard I/O errors
#[error("Communication error: {0}")] #[error("Communication error: {0}")]
Comm(String), Comm(String),
/// 3rd party API errors /// 3rd party API errors
...@@ -160,15 +162,19 @@ impl_error!(num::ParseFloatError, InvalidData); ...@@ -160,15 +162,19 @@ impl_error!(num::ParseFloatError, InvalidData);
impl_error!(binrw::Error, BinRw); impl_error!(binrw::Error, BinRw);
impl Error { impl Error {
/// Returns true if the data is skipped
pub fn is_data_skipped(&self) -> bool { pub fn is_data_skipped(&self) -> bool {
matches!(self, Error::ChannelSkipped) matches!(self, Error::ChannelSkipped)
} }
/// Creates new invalid data error
pub fn invalid_data<S: fmt::Display>(msg: S) -> Self { pub fn invalid_data<S: fmt::Display>(msg: S) -> Self {
Error::InvalidData(msg.to_string()) Error::InvalidData(msg.to_string())
} }
/// Creates new I/O error (for non-standard I/O)
pub fn io<S: fmt::Display>(msg: S) -> Self { pub fn io<S: fmt::Display>(msg: S) -> Self {
Error::Comm(msg.to_string()) Error::Comm(msg.to_string())
} }
/// Creates new function failed error
pub fn failed<S: fmt::Display>(msg: S) -> Self { pub fn failed<S: fmt::Display>(msg: S) -> Self {
Error::Failed(msg.to_string()) Error::Failed(msg.to_string())
} }
...@@ -266,6 +272,7 @@ pub fn configure_logger(filter: LevelFilter) { ...@@ -266,6 +272,7 @@ pub fn configure_logger(filter: LevelFilter) {
builder.init(); builder.init();
} }
/// Prelude module
pub mod prelude { pub mod prelude {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub use super::suicide; pub use super::suicide;
......
...@@ -7,6 +7,7 @@ use crate::thread_rt::{Builder, ScopedTask, Task}; ...@@ -7,6 +7,7 @@ use crate::thread_rt::{Builder, ScopedTask, Task};
use crate::time::Interval; use crate::time::Interval;
use crate::{Error, Result}; use crate::{Error, Result};
/// The supervisor prelude
pub mod prelude { pub mod prelude {
pub use super::Supervisor; pub use super::Supervisor;
pub use crate::thread_rt::{Builder, Scheduling}; pub use crate::thread_rt::{Builder, Scheduling};
...@@ -35,6 +36,7 @@ macro_rules! vacant_entry { ...@@ -35,6 +36,7 @@ macro_rules! vacant_entry {
} }
impl<T> Supervisor<T> { impl<T> Supervisor<T> {
/// Creates a new supervisor object
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
...@@ -101,6 +103,7 @@ impl<T> Supervisor<T> { ...@@ -101,6 +103,7 @@ impl<T> Supervisor<T> {
} }
} }
/// A scoped supervisor object
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
#[derive(Serialize)] #[derive(Serialize)]
pub struct ScopedSupervisor<'a, 'env: 'a, T> { pub struct ScopedSupervisor<'a, 'env: 'a, T> {
...@@ -110,6 +113,7 @@ pub struct ScopedSupervisor<'a, 'env: 'a, T> { ...@@ -110,6 +113,7 @@ pub struct ScopedSupervisor<'a, 'env: 'a, T> {
} }
impl<'a, 'env, T> ScopedSupervisor<'a, 'env, T> { impl<'a, 'env, T> ScopedSupervisor<'a, 'env, T> {
/// Creates a new scoped supervisor object
pub fn new(scope: &'a thread::Scope<'a, 'env>) -> Self { pub fn new(scope: &'a thread::Scope<'a, 'env>) -> Self {
Self { Self {
tasks: <_>::default(), tasks: <_>::default(),
......
...@@ -85,12 +85,18 @@ pub struct Builder { ...@@ -85,12 +85,18 @@ pub struct Builder {
#[serde(rename_all = "UPPERCASE")] #[serde(rename_all = "UPPERCASE")]
pub enum Scheduling { pub enum Scheduling {
#[serde(rename = "RR")] #[serde(rename = "RR")]
/// Round-robin
RoundRobin, RoundRobin,
/// First in, first out
FIFO, FIFO,
/// Idle
Idle, Idle,
/// Batch
Batch, Batch,
/// Deadline
DeadLine, DeadLine,
#[default] #[default]
/// Other
Other, Other,
} }
...@@ -134,6 +140,7 @@ impl_builder_from!(&str); ...@@ -134,6 +140,7 @@ impl_builder_from!(&str);
impl_builder_from!(String); impl_builder_from!(String);
impl Builder { impl Builder {
/// Creates a new thread builder
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
...@@ -316,9 +323,11 @@ pub struct Task<T> { ...@@ -316,9 +323,11 @@ pub struct Task<T> {
} }
impl<T> Task<T> { impl<T> Task<T> {
/// Returns the task name
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
&self.name &self.name
} }
/// Returns the task handle
pub fn handle(&self) -> &JoinHandle<T> { pub fn handle(&self) -> &JoinHandle<T> {
&self.handle &self.handle
} }
...@@ -335,12 +344,15 @@ impl<T> Task<T> { ...@@ -335,12 +344,15 @@ impl<T> Task<T> {
self.rt_params = rt_params; self.rt_params = rt_params;
Ok(()) Ok(())
} }
/// Returns true if the task is finished
pub fn is_finished(&self) -> bool { pub fn is_finished(&self) -> bool {
self.handle.is_finished() self.handle.is_finished()
} }
/// Joins the task
pub fn join(self) -> thread::Result<T> { pub fn join(self) -> thread::Result<T> {
self.handle.join() self.handle.join()
} }
/// Converts the task into a standard [`JoinHandle`]
pub fn into_join_handle(self) -> JoinHandle<T> { pub fn into_join_handle(self) -> JoinHandle<T> {
self.into() self.into()
} }
...@@ -348,6 +360,7 @@ impl<T> Task<T> { ...@@ -348,6 +360,7 @@ impl<T> Task<T> {
pub fn elapsed(&self) -> Duration { pub fn elapsed(&self) -> Duration {
self.info.started_mt.elapsed() self.info.started_mt.elapsed()
} }
/// Returns true if the task is blocking
pub fn is_blocking(&self) -> bool { pub fn is_blocking(&self) -> bool {
self.blocking self.blocking
} }
...@@ -377,9 +390,11 @@ pub struct ScopedTask<'scope, T> { ...@@ -377,9 +390,11 @@ pub struct ScopedTask<'scope, T> {
} }
impl<'scope, T> ScopedTask<'scope, T> { impl<'scope, T> ScopedTask<'scope, T> {
/// Returns the task name
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
&self.name &self.name
} }
/// Returns the task handle
pub fn handle(&self) -> &ScopedJoinHandle<T> { pub fn handle(&self) -> &ScopedJoinHandle<T> {
&self.handle &self.handle
} }
...@@ -396,12 +411,15 @@ impl<'scope, T> ScopedTask<'scope, T> { ...@@ -396,12 +411,15 @@ impl<'scope, T> ScopedTask<'scope, T> {
self.rt_params = rt_params; self.rt_params = rt_params;
Ok(()) Ok(())
} }
/// Returns true if the task is finished
pub fn is_finished(&self) -> bool { pub fn is_finished(&self) -> bool {
self.handle.is_finished() self.handle.is_finished()
} }
/// Joins the task
pub fn join(self) -> thread::Result<T> { pub fn join(self) -> thread::Result<T> {
self.handle.join() self.handle.join()
} }
/// Converts the task into a standard [`ScopedJoinHandle`]
pub fn into_join_handle(self) -> ScopedJoinHandle<'scope, T> { pub fn into_join_handle(self) -> ScopedJoinHandle<'scope, T> {
self.into() self.into()
} }
...@@ -409,6 +427,7 @@ impl<'scope, T> ScopedTask<'scope, T> { ...@@ -409,6 +427,7 @@ impl<'scope, T> ScopedTask<'scope, T> {
pub fn elapsed(&self) -> Duration { pub fn elapsed(&self) -> Duration {
self.info.started_mt.elapsed() self.info.started_mt.elapsed()
} }
/// Returns true if the task is blocking
pub fn is_blocking(&self) -> bool { pub fn is_blocking(&self) -> bool {
self.blocking self.blocking
} }
...@@ -429,6 +448,7 @@ pub struct RTParams { ...@@ -429,6 +448,7 @@ pub struct RTParams {
} }
impl RTParams { impl RTParams {
/// Creates a new real-time parameters object
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
...@@ -659,6 +679,7 @@ pub struct SystemConfig { ...@@ -659,6 +679,7 @@ pub struct SystemConfig {
} }
impl SystemConfig { impl SystemConfig {
/// Creates a new system config object
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
...@@ -681,6 +702,7 @@ impl SystemConfig { ...@@ -681,6 +702,7 @@ impl SystemConfig {
} }
} }
/// A guard object to restore system parameters when dropped
pub struct SystemConfigGuard { pub struct SystemConfigGuard {
config: SystemConfig, config: SystemConfig,
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论