///| IEC 61131-3 标准功能块 (Function Blocks) 实现
///|
/// TON: 通电延时定时器 (Timer On-Delay)
pub(all) struct TonTimer {
mut in_state : Bool
mut pt : Int64 // 预置延时 (ms)
mut et : Int64 // 已用时间 (ms)
mut q : Bool // 输出
} derive(Debug)
///|
pub fn TonTimer::new() -> TonTimer {
{ in_state: false, pt: 0L, et: 0L, q: false, }
}
///|
/// TON 周期步进刷新
pub fn TonTimer::tick(
self : TonTimer,
in_val : Bool,
pt_val : Int64,
delta_ms : Int64,
) -> Unit {
self.in_state = in_val
self.pt = pt_val
if self.in_state {
if self.et < self.pt {
self.et = self.et + delta_ms
if self.et > self.pt {
self.et = self.pt
}
}
self.q = self.et >= self.pt
} else {
self.et = 0L
self.q = false
}
}
///|
/// TOF: 断电延时定时器 (Timer Off-Delay)
pub(all) struct TofTimer {
mut in_state : Bool
mut pt : Int64
mut et : Int64
mut q : Bool
} derive(Debug)
///|
pub fn TofTimer::new() -> TofTimer {
{ in_state: false, pt: 0L, et: 0L, q: false, }
}
///|
/// TOF 周期步进刷新
pub fn TofTimer::tick(
self : TofTimer,
in_val : Bool,
pt_val : Int64,
delta_ms : Int64,
) -> Unit {
self.in_state = in_val
self.pt = pt_val
if self.in_state {
self.q = true
self.et = 0L
} else if self.q {
self.et = self.et + delta_ms
if self.et >= self.pt {
self.et = self.pt
self.q = false
}
} else {
self.et = 0L
}
}
///|
/// TP: 脉冲定时器 (Timer Pulse)
pub(all) struct TpTimer {
mut in_prev : Bool
mut active : Bool
mut pt : Int64
mut et : Int64
mut q : Bool
} derive(Debug)
///|
pub fn TpTimer::new() -> TpTimer {
{ in_prev: false, active: false, pt: 0L, et: 0L, q: false, }
}
///|
/// TP 周期步进刷新
pub fn TpTimer::tick(
self : TpTimer,
in_val : Bool,
pt_val : Int64,
delta_ms : Int64,
) -> Unit {
self.pt = pt_val
let rising_edge = in_val && !self.in_prev
self.in_prev = in_val
if rising_edge && !self.active {
self.active = true
self.q = true
self.et = 0L
}
if self.active {
self.et = self.et + delta_ms
if self.et >= self.pt {
self.active = false
self.q = false
self.et = self.pt
}
} else {
self.q = false
}
}
///|
/// TONR: 保持型通电延时定时器 (Retentive On-Delay Timer)
pub(all) struct TonrTimer {
mut in_state : Bool
mut pt : Int64
mut et : Int64
mut q : Bool
} derive(Debug)
///|
pub fn TonrTimer::new() -> TonrTimer {
{ in_state: false, pt: 0L, et: 0L, q: false, }
}
///|
pub fn TonrTimer::tick(
self : TonrTimer,
in_val : Bool,
reset_val : Bool,
pt_val : Int64,
delta_ms : Int64,
) -> Unit {
self.pt = pt_val
self.in_state = in_val
if reset_val {
self.et = 0L
self.q = false
} else {
if self.in_state && self.et < self.pt {
self.et = self.et + delta_ms
if self.et > self.pt {
self.et = self.pt
}
}
self.q = self.et >= self.pt
}
}
///|
/// CTU: 增计数器 (Count Up)
pub(all) struct CtuCounter {
mut cu_prev : Bool
mut pv : Int // 预置计数值
mut cv : Int // 当前计数值
mut q : Bool // 达到计数值输出
} derive(Debug)
///|
pub fn CtuCounter::new() -> CtuCounter {
{ cu_prev: false, pv: 0, cv: 0, q: false, }
}
///|
/// CTU 步进计算
pub fn CtuCounter::tick(
self : CtuCounter,
cu_val : Bool,
reset_val : Bool,
pv_val : Int,
) -> Unit {
self.pv = pv_val
let rising_edge = cu_val && !self.cu_prev
self.cu_prev = cu_val
if reset_val {
self.cv = 0
self.q = false
} else {
if rising_edge && self.cv < 32767 {
self.cv = self.cv + 1
}
self.q = self.cv >= self.pv
}
}
///|
/// CTUD: 增减双向计数器 (Count Up/Down)
pub(all) struct CtudCounter {
mut cu_prev : Bool
mut cd_prev : Bool
mut pv : Int
mut cv : Int
mut qu : Bool
mut qd : Bool
} derive(Debug)
///|
pub fn CtudCounter::new() -> CtudCounter {
{ cu_prev: false, cd_prev: false, pv: 0, cv: 0, qu: false, qd: true, }
}
///|
pub fn CtudCounter::tick(
self : CtudCounter,
cu_val : Bool,
cd_val : Bool,
r_val : Bool,
ld_val : Bool,
pv_val : Int,
) -> Unit {
self.pv = pv_val
let cu_edge = cu_val && !self.cu_prev
let cd_edge = cd_val && !self.cd_prev
self.cu_prev = cu_val
self.cd_prev = cd_val
if r_val {
self.cv = 0
} else if ld_val {
self.cv = self.pv
} else if cu_edge && !cd_edge && self.cv < 32767 {
self.cv = self.cv + 1
} else if cd_edge && !cu_edge && self.cv > -32768 {
self.cv = self.cv - 1
}
self.qu = self.cv >= self.pv
self.qd = self.cv <= 0
}
///|
/// SR: 置位优先双稳态触发器 (Set-Dominant Bistable)
pub(all) struct SrFlipFlop {
mut q1 : Bool
} derive(Debug)
///|
pub fn SrFlipFlop::new() -> SrFlipFlop {
{ q1: false, }
}
///|
pub fn SrFlipFlop::tick(self : SrFlipFlop, s1_val : Bool, r_val : Bool) -> Bool {
self.q1 = s1_val || (!r_val && self.q1)
self.q1
}
///|
/// RS: 复位优先双稳态触发器 (Reset-Dominant Bistable)
pub(all) struct RsFlipFlop {
mut q1 : Bool
} derive(Debug)
///|
pub fn RsFlipFlop::new() -> RsFlipFlop {
{ q1: false, }
}
///|
pub fn RsFlipFlop::tick(self : RsFlipFlop, s_val : Bool, r1_val : Bool) -> Bool {
self.q1 = !r1_val && (s_val || self.q1)
self.q1
}
///|
/// R_TRIG: 上升沿检测触发器 (Rising Edge Detector)
pub(all) struct RTrig {
mut clk_prev : Bool
mut q : Bool
} derive(Debug)
///|
pub fn RTrig::new() -> RTrig {
{ clk_prev: false, q: false, }
}
///|
pub fn RTrig::tick(self : RTrig, clk_val : Bool) -> Bool {
self.q = clk_val && !self.clk_prev
self.clk_prev = clk_val
self.q
}
///|
/// F_TRIG: 下降沿检测触发器 (Falling Edge Detector)
pub(all) struct FTrig {
mut clk_prev : Bool
mut q : Bool
} derive(Debug)
///|
pub fn FTrig::new() -> FTrig {
{ clk_prev: false, q: false, }
}
///|
pub fn FTrig::tick(self : FTrig, clk_val : Bool) -> Bool {
self.q = !clk_val && self.clk_prev
self.clk_prev = clk_val
self.q
}
///|
/// 通用功能块实例封装
pub(all) enum FbInstance {
Ton(TonTimer)
Tof(TofTimer)
Tp(TpTimer)
Tonr(TonrTimer)
Ctu(CtuCounter)
Ctud(CtudCounter)
Sr(SrFlipFlop)
Rs(RsFlipFlop)
Rtrig(RTrig)
Ftrig(FTrig)
} derive(Debug)
///|
/// 获取功能块内部字段值 (如 Timer1.Q 或 Counter1.CV)
pub fn FbInstance::get_field(self : FbInstance, field : String) -> PlcValue {
let f = field
match self {
FbInstance::Ton(t) =>
if f == "Q" || f == "q" {
PlcValue::Bool(t.q)
} else if f == "ET" || f == "et" {
PlcValue::Time(t.et)
} else {
PlcValue::Null
}
FbInstance::Tof(t) =>
if f == "Q" || f == "q" {
PlcValue::Bool(t.q)
} else if f == "ET" || f == "et" {
PlcValue::Time(t.et)
} else {
PlcValue::Null
}
FbInstance::Tp(t) =>
if f == "Q" || f == "q" {
PlcValue::Bool(t.q)
} else if f == "ET" || f == "et" {
PlcValue::Time(t.et)
} else {
PlcValue::Null
}
FbInstance::Tonr(t) =>
if f == "Q" || f == "q" {
PlcValue::Bool(t.q)
} else if f == "ET" || f == "et" {
PlcValue::Time(t.et)
} else {
PlcValue::Null
}
FbInstance::Ctu(c) =>
if f == "Q" || f == "q" {
PlcValue::Bool(c.q)
} else if f == "CV" || f == "cv" {
PlcValue::Int(c.cv)
} else {
PlcValue::Null
}
FbInstance::Ctud(c) =>
if f == "QU" || f == "qu" {
PlcValue::Bool(c.qu)
} else if f == "QD" || f == "qd" {
PlcValue::Bool(c.qd)
} else if f == "CV" || f == "cv" {
PlcValue::Int(c.cv)
} else {
PlcValue::Null
}
FbInstance::Sr(s) =>
if f == "Q1" || f == "q1" || f == "Q" || f == "q" {
PlcValue::Bool(s.q1)
} else {
PlcValue::Null
}
FbInstance::Rs(r) =>
if f == "Q1" || f == "q1" || f == "Q" || f == "q" {
PlcValue::Bool(r.q1)
} else {
PlcValue::Null
}
FbInstance::Rtrig(r) =>
if f == "Q" || f == "q" {
PlcValue::Bool(r.q)
} else {
PlcValue::Null
}
FbInstance::Ftrig(f_inst) =>
if f == "Q" || f == "q" {
PlcValue::Bool(f_inst.q)
} else {
PlcValue::Null
}
}
}