فهرست منبع

【工具】判断连续子序列

mikasa 1 ماه پیش
والد
کامیت
e50af8ce60
4فایلهای تغییر یافته به همراه104 افزوده شده و 11 حذف شده
  1. 3 3
      src/ems/pcs/mod.rs
  2. 7 2
      src/ems/pcs/pcs.rs
  3. 12 5
      src/internal/modbus/code.rs
  4. 82 1
      src/internal/modbus/mod.rs

+ 3 - 3
src/ems/pcs/mod.rs

@@ -1,4 +1,4 @@
-use crate::internal::modbus::tcp_code::ModbusTcpCode;
+use crate::internal::modbus::code::ModbusCode;
 use serde::{Deserialize, Serialize};
 
 pub mod pcs;
@@ -18,12 +18,12 @@ pub(crate) struct PcsCsvData {
 }
 
 /// pcs config
-pub(crate) fn pcs_conf() -> anyhow::Result<Vec<ModbusTcpCode>> {
+pub(crate) fn pcs_conf() -> anyhow::Result<Vec<ModbusCode>> {
     let mut rdr = csv::Reader::from_path("config/pcs.csv")?;
     let mut vec = Vec::new();
     for result in rdr.deserialize() {
         let csv_data: PcsCsvData = result?;
-        let code: ModbusTcpCode = csv_data.try_into()?;
+        let code: ModbusCode = csv_data.try_into()?;
         vec.push(code);
     }
     Ok(vec)

+ 7 - 2
src/ems/pcs/pcs.rs

@@ -1,7 +1,7 @@
 use crate::cmd::config::app_config;
 use crate::ems::pcs::pcs_conf;
 use crate::ems::{Consumer, Producer, Service};
-use crate::internal::modbus::tcp_code::ModbusTcpCode;
+use crate::internal::modbus::code::ModbusCode;
 use crate::internal::utils;
 use anyhow::bail;
 use log::{error, info};
@@ -14,10 +14,12 @@ pub struct Pcs {
     pub id: String,
     pub producer: Producer,
     pub consumer: Arc<Mutex<Consumer>>,
-    pub modbus_code: Arc<Mutex<Vec<ModbusTcpCode>>>,
+    pub modbus_code: Arc<Mutex<Vec<ModbusCode>>>,
     pub ctx: Arc<Mutex<tokio_modbus::client::Context>>,
 }
 
+/// Modbus-TCP连接
+/// FIXME 考虑重连机制
 async fn connect_modbus_tcp() -> anyhow::Result<tokio_modbus::client::Context> {
     let pcs_config = &app_config().emu.pcs;
     let ctx = tokio_modbus::client::tcp::connect(
@@ -27,6 +29,7 @@ async fn connect_modbus_tcp() -> anyhow::Result<tokio_modbus::client::Context> {
     Ok(ctx)
 }
 
+
 impl Pcs {
     /// 初始化PCS
     pub async fn new(producer: Producer, consumer: Consumer) -> anyhow::Result<Self> {
@@ -63,6 +66,7 @@ impl Pcs {
     async fn read_input_register(&self) -> anyhow::Result<()> {
         let modbus_code_clone = self.modbus_code.clone();
         let mut modbus_guard = modbus_code_clone.lock().await;
+        // 从整个配置中过滤出输入寄存器集合
         let mut input_registers: Vec<_> = modbus_guard
             .iter_mut()
             .filter(|it| {
@@ -71,6 +75,7 @@ impl Pcs {
                     && it.code == Some(FunctionCode::ReadInputRegisters.value())
             })
             .collect();
+
         if let Some(start_register) = input_registers.first() {
             if let Some(addr) = start_register.addr {
                 let words = self

+ 12 - 5
src/internal/modbus/tcp_code.rs → src/internal/modbus/code.rs

@@ -1,9 +1,9 @@
 use crate::ems::pcs::PcsCsvData;
-use crate::internal::modbus::ModbusDataType;
+use crate::internal::modbus::{BaseModbusCode, ModbusDataType};
 use std::collections::HashMap;
 
 #[derive(Debug)]
-pub struct ModbusTcpCode {
+pub struct ModbusCode {
     pub addr: Option<u16>,
     pub code: Option<u8>,
     pub data: Option<[u8; 2]>,
@@ -15,9 +15,16 @@ pub struct ModbusTcpCode {
     pub desc: Option<String>,
 }
 
-impl ModbusTcpCode {}
+impl ModbusCode {}
 
-impl TryFrom<PcsCsvData> for ModbusTcpCode {
+
+impl BaseModbusCode for ModbusCode {
+    fn addr(&self) -> Option<u16> {
+        self.addr
+    }
+}
+
+impl TryFrom<PcsCsvData> for ModbusCode {
     type Error = anyhow::Error;
 
     fn try_from(value: PcsCsvData) -> Result<Self, Self::Error> {
@@ -57,7 +64,7 @@ impl TryFrom<PcsCsvData> for ModbusTcpCode {
             }
             note = Some(hash_map);
         }
-        Ok(ModbusTcpCode {
+        Ok(ModbusCode {
             addr,
             code,
             data: None,

+ 82 - 1
src/internal/modbus/mod.rs

@@ -1,4 +1,10 @@
-pub mod tcp_code;
+pub mod code;
+
+pub trait BaseModbusCode {
+    fn addr(&self) -> Option<u16>;
+}
+
+const MAX_REGISTER_COUNT: usize = 120;
 
 #[derive(Debug)]
 pub enum ModbusDataType {
@@ -6,3 +12,78 @@ pub enum ModbusDataType {
     U16,
     S16,
 }
+
+/// 将序列按照连续子序列分割出来
+/// 如: [1,3,2,7,8,11,10] 分割为 [[1,2,3],[7,8],[10,11]]
+pub fn sequential<T: BaseModbusCode>(mut codes: Vec<T>) -> Vec<Vec<T>> {
+    //按地址升序排序
+    codes.sort_by(|a, b| a.addr().cmp(&b.addr()));
+    if codes.is_empty() {
+        return Vec::new();
+    }
+    let mut vec = Vec::new();
+    let mut current_group = Vec::new();
+    let mut iter = codes.into_iter();
+    if let Some(prev) = iter.next() {
+        current_group.push(prev);
+        for current in iter {
+            if let Some(prev) = current_group.last() {
+                if let Some(prev_addr) = prev.addr() {
+                    if let Some(curr_addr) = current.addr() {
+                        if prev_addr + 1 == curr_addr {
+                            if current_group.len() >= MAX_REGISTER_COUNT {
+                                vec.push(current_group);
+                                current_group = Vec::new();
+                            }
+                            current_group.push(current);
+                        } else {
+                            vec.push(current_group);
+                            current_group = Vec::new();
+                            current_group.push(current)
+                        }
+                    }
+                }
+            }
+        }
+        vec.push(current_group);
+    }
+    vec
+}
+
+mod test {
+    use super::*;
+
+    #[derive(Debug)]
+    struct TestModbusCode {
+        addr: Option<u16>,
+    }
+
+    impl BaseModbusCode for TestModbusCode {
+        fn addr(&self) -> Option<u16> {
+            self.addr
+        }
+    }
+
+    #[test]
+    fn test_sequential() {
+        let base = TestModbusCode { addr: Some(1u16) };
+        let vec = sequential(vec![
+            base,
+            TestModbusCode { addr: Some(3u16) },
+            TestModbusCode { addr: Some(2u16) },
+            TestModbusCode { addr: Some(7u16) },
+            TestModbusCode { addr: Some(8u16) },
+            TestModbusCode { addr: Some(11u16) },
+            TestModbusCode { addr: Some(10u16) },
+        ]);
+        let vec = vec
+            .into_iter()
+            .map(|it| {
+                it.into_iter()
+                    .map(|i| i.addr.unwrap())
+                    .collect::<Vec<u16>>()
+            })
+            .collect::<Vec<Vec<u16>>>();
+        assert_eq!(vec, vec![vec![1, 2, 3], vec![7, 8], vec![10, 11],]);
+    }
+}