rsiot/components/cmp_plc/
config.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::time::Duration;

use serde::Serialize;

use crate::message::{Message, MsgDataBound};

use super::plc::{FunctionBlockBase, IFunctionBlock};

type TFnExport<TMsg, I, Q, S> = fn(&I, &Q, &S) -> Option<Vec<Message<TMsg>>>;

/// Конфигурация компонента ПЛК
#[derive(Clone)]
pub struct Config<TMsg, I, Q, S>
where
    TMsg: MsgDataBound,
    I: Clone + Default + Serialize,
    Q: Clone + Default + Serialize,
    S: Clone + Default + Serialize,
    FunctionBlockBase<I, Q, S>: IFunctionBlock<I, Q, S>,
{
    /// Функция инициализации входной структуры в начале цикла ПЛК
    ///
    /// **Примеры**
    ///
    /// ```rust
    /// fn_cycle_init: |_input: &mut fb_main::I| {}
    /// ```
    pub fn_cycle_init: fn(&mut I) -> (),

    /// Функция преобразования входящих сообщений во входную структуру ПЛК.
    ///
    /// **Примеры**
    /// ```rust
    #[doc = include_str!("./tests/config_fn_input.rs")]
    /// ```
    pub fn_input: fn(&mut I, &Message<TMsg>) -> (),

    /// Функция преобразования выходной структуры ПЛК в исходящие сообщения.
    ///
    /// **Примеры**
    ///
    /// ```rust
    /// fn_output: |output: &fb_main::Q| vec![]
    /// ```
    pub fn_output: fn(&Q) -> Vec<Message<TMsg>>,

    /// Главный функциональный блок ПЛК
    ///
    /// **Примеры**
    ///
    /// ```rust
    /// fb_main: fb_main::FB::new()
    /// ```
    pub fb_main: FunctionBlockBase<I, Q, S>,

    /// Периодичность выполнения логики ПЛК
    ///
    /// **Примеры**
    ///
    /// ```rust
    /// period: Duration::from_millis(100)
    /// ```
    pub period: Duration,

    /// Настройки сохранения состояния и восстановления при запуске
    pub retention: Option<ConfigRetention<TMsg, I, Q, S>>,
}

impl<TMsg, I, Q, S> Default for Config<TMsg, I, Q, S>
where
    TMsg: MsgDataBound,
    I: Clone + Default + Serialize,
    Q: Clone + Default + Serialize,
    S: Clone + Default + Serialize,
    FunctionBlockBase<I, Q, S>: IFunctionBlock<I, Q, S>,
{
    fn default() -> Self {
        Self {
            fn_cycle_init: |_| (),
            fn_input: |_, _| (),
            fn_output: |_| vec![],
            fb_main: FunctionBlockBase::new(Duration::default()),
            period: Duration::default(),
            retention: None,
        }
    }
}

/// Настройка сохранения и восстановления области Static
#[derive(Clone)]
pub struct ConfigRetention<TMsg, I, Q, S>
where
    TMsg: MsgDataBound,
    I: Clone + Default + Serialize,
    Q: Clone + Default + Serialize,
    S: Clone + Default + Serialize,
{
    /// Периодичность сохранения текущего состояния
    pub save_period: Duration,

    /// Функция преобразования состояния ПЛК в исходящие сообщения
    pub fn_export: TFnExport<TMsg, I, Q, S>,

    /// Функция восстановления состояния из входящих сообщений
    pub fn_import_static: fn(&Message<TMsg>) -> anyhow::Result<Option<S>>,

    /// Таймаут восстановления
    ///
    /// Если в течение заданного времени не будет получено сообщение с данными для восстановления,
    /// считаем что восттановление не удалось и запускаем ПЛК с дефолтным состоянием
    pub restore_timeout: Duration,
}

pub enum ConfigRetentionRestoreResult<S>
where
    S: Clone + Default + Serialize,
{
    NoRestoreData,
    RestoreDeserializationError,
    RestoreData(S),
}