Browse Source

【功能】csv格式转化为指令,英博PCS协议

yuanan 1 tháng trước cách đây
mục cha
commit
9db5dc17bf
9 tập tin đã thay đổi với 375 bổ sung41 xóa
  1. 65 36
      Cargo.lock
  2. 3 0
      Cargo.toml
  3. 133 0
      config/pcs.csv
  4. 2 2
      emu-config.yaml
  5. 38 0
      src/ems/pcs/mod.rs
  6. 52 3
      src/ems/pcs/pcs.rs
  7. 2 0
      src/internal/mod.rs
  8. 8 0
      src/internal/modbus/mod.rs
  9. 72 0
      src/internal/modbus/tcp_code.rs

+ 65 - 36
Cargo.lock

@@ -118,9 +118,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.95"
+version = "1.0.96"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
+checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4"
 
 [[package]]
 name = "async-trait"
@@ -186,9 +186,9 @@ checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
 
 [[package]]
 name = "cc"
-version = "1.2.14"
+version = "1.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9"
+checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
 dependencies = [
  "shlex",
 ]
@@ -207,23 +207,23 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
 
 [[package]]
 name = "chrono"
-version = "0.4.39"
+version = "0.4.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
+checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
  "js-sys",
  "num-traits",
  "wasm-bindgen",
- "windows-targets",
+ "windows-link",
 ]
 
 [[package]]
 name = "clap"
-version = "4.5.30"
+version = "4.5.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
+checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -231,9 +231,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.30"
+version = "4.5.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
+checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
 dependencies = [
  "anstream",
  "anstyle",
@@ -314,6 +314,27 @@ version = "0.8.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
 
+[[package]]
+name = "csv"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
+dependencies = [
+ "csv-core",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "csv-core"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "equivalent"
 version = "1.0.2"
@@ -322,9 +343,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "flate2"
-version = "1.0.35"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
+checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -489,8 +510,10 @@ dependencies = [
  "amqprs",
  "anyhow",
  "async-trait",
+ "bytes",
  "chrono",
  "clap",
+ "csv",
  "log",
  "rand",
  "serde",
@@ -537,9 +560,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.169"
+version = "0.2.170"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
+checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
 
 [[package]]
 name = "libyml"
@@ -563,9 +586,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.25"
+version = "0.4.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
+checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
 
 [[package]]
 name = "mach2"
@@ -584,9 +607,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b"
+checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
 dependencies = [
  "adler2",
 ]
@@ -744,7 +767,7 @@ checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
 dependencies = [
  "rand_chacha",
  "rand_core",
- "zerocopy 0.8.20",
+ "zerocopy 0.8.21",
 ]
 
 [[package]]
@@ -759,19 +782,19 @@ dependencies = [
 
 [[package]]
 name = "rand_core"
-version = "0.9.1"
+version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3"
+checksum = "7a509b1a2ffbe92afab0e55c8fd99dea1c280e8171bd2d88682bb20bc41cbc2c"
 dependencies = [
  "getrandom",
- "zerocopy 0.8.20",
+ "zerocopy 0.8.21",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.8"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
+checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f"
 dependencies = [
  "bitflags 2.8.0",
 ]
@@ -831,9 +854,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "serde"
-version = "1.0.217"
+version = "1.0.218"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
+checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
 dependencies = [
  "serde_derive",
 ]
@@ -858,9 +881,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.217"
+version = "1.0.218"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
+checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1155,9 +1178,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
 name = "uuid"
-version = "1.13.2"
+version = "1.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6"
+checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587"
 dependencies = [
  "getrandom",
 ]
@@ -1272,6 +1295,12 @@ dependencies = [
  "windows-targets",
 ]
 
+[[package]]
+name = "windows-link"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
+
 [[package]]
 name = "windows-sys"
 version = "0.52.0"
@@ -1375,11 +1404,11 @@ dependencies = [
 
 [[package]]
 name = "zerocopy"
-version = "0.8.20"
+version = "0.8.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dde3bb8c68a8f3f1ed4ac9221aad6b10cece3e60a8e2ea54a6a2dec806d0084c"
+checksum = "dcf01143b2dd5d134f11f545cf9f1431b13b749695cb33bcce051e7568f99478"
 dependencies = [
- "zerocopy-derive 0.8.20",
+ "zerocopy-derive 0.8.21",
 ]
 
 [[package]]
@@ -1395,9 +1424,9 @@ dependencies = [
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.8.20"
+version = "0.8.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eea57037071898bf96a6da35fd626f4f27e9cee3ead2a6c703cf09d472b2e700"
+checksum = "712c8386f4f4299382c9abee219bee7084f78fb939d88b6840fcc1320d5f6da2"
 dependencies = [
  "proc-macro2",
  "quote",

+ 3 - 0
Cargo.toml

@@ -35,5 +35,8 @@ rand = "0.9.0"
 async-trait = "0.1.86"
 # RammitMQ 消息队列支持
 amqprs = "2.1.0"
+# CSV 文件读写
+csv = "1.3.1"
+bytes = "1.10.0"
 
 

+ 133 - 0
config/pcs.csv

@@ -0,0 +1,133 @@
+address,code,name,rw,type,factor,unit,note,desc
+00001,5,故障复位,3,bool,1,,1:复位,
+00002,5,设备启动,3,bool,1,,1:启动,
+00003,5,设备停机,3,bool,1,,1:停机,
+00004,5,远程急停,3,bool,1,,1:急停,
+00005,5,累计充电电量清零,3,bool,1,,1:清零,
+00006,5,累计放电电量清零,3,bool,1,,1:清零,
+00007,5,远程/就地设置,3,bool,1,,"1:远程
+0:就地",
+00008,5,设备待机,3,bool,1,,"1:待机
+0:无效",
+00009,5,,3,bool,1,,,
+00010,5,,3,bool,1,,,
+00011,5,,3,bool,1,,,
+00012,5,,3,bool,1,,,
+00013,5,,3,bool,1,,,
+00014,5,,3,bool,1,,,
+00015,5,,3,bool,1,,,
+00016,5,,3,bool,1,,,
+,,,,,,,,
+00081,2,停机状态,1,bool,1,,1:停机,
+00082,2,待机状态,1,bool,1,,1:待机,
+00083,2,运行状态,1,bool,1,,1:运行,
+00084,2,总故障状态,1,bool,1,,1:故障,
+00085,2,总报警状态,1,bool,1,,1:告警,
+00086,2,远程/就地状态,1,bool,1,,"1:远程
+0:就地",
+00087,2,急停输入状态,1,bool,1,,1:急停有效,
+00088,2,并网状态,1,bool,1,,1:并网,
+00089,2,VF 离网状态,1,bool,1,,1:VF 离网,
+00090,2,过载降容,1,bool,1,,1:过载发生,
+00091,2,,1,bool,1,,,
+00092,2,,1,bool,1,,,
+00093,2,,1,bool,1,,,
+00094,2,BMS 干接点输入状态,1,bool,1,,,
+00095,2,正直流主接合闸状态,1,bool,1,,,
+00096,2,负直流主接合闸状态,1,bool,1,,,
+,,,,,,,,
+00201,4,PCS 端口 A 相电压,1,u16,0.1,V,,
+00202,4,PCS 端口 B 相电压,1,u16,0.1,V,,
+00203,4,PCS 端口 C 相电压,1,u16,0.1,V,,
+00204,4,PCS 输出 A 相电流,1,s16,0.1,A,,
+00205,4,PCS 输出 B 相电流,1,s16,0.1,A,,
+00206,4,PCS 输出 C 相电流,1,s16,0.1,A,,
+00207,4,电网频率,1,u16,0.01,Hz,,
+00208,4,PCS A 相输出有功功率,1,s16,0.1,kW,,
+00209,4,PCS B 相输出有功功率,1,s16,0.1,kW,,
+00210,4,PCS C 相输出有功功率,1,s16,0.1,kW,,
+00211,4,PCS 总输出有功功率,1,s16,0.1,kW,,
+00212,4,PCS A 相输出无功功率,1,s16,0.1,kVar,,
+00213,4,PCS B 相输出无功功率,1,s16,0.1,kVar,,
+00214,4,PCS C 相输出无功功率,1,s16,0.1,kVar,,
+00215,4,PCS 总输出无功功率,1,s16,0.1,kVar,,
+00216,4,PCS A 相输出视在功率,1,u16,0.1,kVA,,
+00217,4,PCS B 相输出视在功率,1,u16,0.1,kVA,,
+00218,4,PCS C 相输出视在功率,1,u16,0.1,kVA,,
+00219,4,PCS 总输出视在功率,1,u16,0.1,kVA,,
+00220,4,PCS 输出 A 相功率因数,1,s16,0.001,,,
+00221,4,PCS 输出 B 相功率因数,1,s16,0.001,,,
+00222,4,PCS 输出 C 相功率因数,1,s16,0.001,,,
+00223,4,PCS 输出总功率因数,1,s16,0.001,,,
+00224,4,PCS 输入功率,1,s16,0.1,kW,,PCS 直流输入功率
+00225,4,PCS 输入电压,1,s16,0.1,V,,PCS 直流输入电压
+00226,4,PCS 输入电流,1,s16,0.1,A,,PCS 直流输入电流
+00227,4,PCS 散热器温度,1,s16,1,℃,,IGBT 最大温度,125 不用
+00228,4,BMS 工作状态,1,u16,1,,,125新增
+00229,4,PCS 运行状态,1,u16,1,,"0:停机
+1:自检
+2:运行
+4:故障
+7:待机",125kw PCS 运行状态
+00230,4,PCS 交流累计充电电量低 16 位,1,u16,0.001,kWh,,
+00231,4,PCS 交流累计充电电量高 16 位,1,u16,0.001,kWh,,
+00232,4,PCS 交流累计放电电量低 16 位,1,u16,0.001,kWh,,
+00233,4,PCS 交流累计放电电量高 16 位,1,u16,0.001,kWh,,
+00234,4,PCS 直流累计充电电量低 16 位,1,u16,0.001,kWh,,
+00235,4,PCS 直流累计充电电量高 16 位,1,u16,0.001,kWh,,
+00236,4,PCS 直流累计放电电量低 16 位,1,u16,0.001,kWh,,
+00237,4,PCS 直流累计放电电量高 16 位,1,u16,0.001,kWh,,
+00238,4,PCS 通讯状态字,1,u16,1,,,20ms 自增 1,125 不用
+00239,4,系统时钟-秒,1,u16,1,,,
+00240,4,系统时钟-分,1,u16,1,,,
+00241,4,统时钟-时,1,u16,1,,,
+00242,4,系统时钟-日,1,u16,1,,,
+00243,4,系统时钟-月,1,u16,1,,,
+00244,4,系统时钟-年,1,u16,1,,,
+00245,4,控制软件版本,1,u16,0.1,,,原先是 ARM 版本,现在是125kw PCS的控制软件版本
+00246,4,FPGA 程序版本,1,u16,1,,,125 未使用
+00247,4,N 相电流有效值,1,u16,0.1,A,,用于运行历史查询,125未使用
+00248,4,PCS 状态查询码 1,1,u16,1,,,用于运行历史查询,125未使用
+00249,4,PCS 状态查询码 2,1,u16,1,,,用于运行历史查询,125未使用
+00250,4,PCS 状态查询码 3,1,u16,1,,,用于运行历史查询,125未使用
+00251,4,PCS 状态查询码 4,1,u16,1,,,用于运行历史查询,125未使用
+00252,4,PCS 状态查询码 5,1,u16,1,,,用于运行历史查询,125未使用
+00253,4,PCS 状态查询码 6,1,u16,1,,,用于运行历史查询,125未使用
+00254,4,PCS 状态查询码 7,1,u16,1,,,用于运行历史查询,125未使用
+00255,4,PCS 状态查询码 8,1,u16,1,,,用于运行历史查询,125未使用
+00256,4,PCS 故障字 5,1,u16,1,,,125 不用,兼容之前
+00257,4,片上 SOC 温度,1,u16,0.1,,,125 不用,兼容之前
+00258,4,IGBT 温度 1,1,u16,1,,,125 不用,兼容之前
+00259,4,IGBT 温度 2,1,u16,1,,,125 不用,兼容之前
+00260,4,IGBT 温度 3,1,u16,1,,,125 不用,兼容之前
+00261,4,IGBT 温度 4,1,u16,1,,,125 不用,兼容之前
+00262,4,通讯软件版本号,1,u16,1,,,1650表示V1.6.5.0,125kw PCS 的通讯软件版本
+00263,4,DCDC 输入电压,1,s16,0.1,V,,
+00264,4,DCDC 输出电压,1,s16,0.1,V,,
+00265,4,DCDC 输入电流,1,s16,0.1,A,,
+00266,4,DCDC 输出电流,1,s16,0.1,A,,
+00267,4,DCDC 输入功率,1,s16,0.1,kW,,
+00268,4,DCDC 散热器温度,1,,1,,,
+00269,4,,1,,,,,
+00270,4,,1,,,,,
+00271,4,DCDC 程序版本,1,u16,0.1,,,125 不用,兼容之前
+00272,4,PCS 故障字 1,1,u16,1,,,125 不用,兼容之前
+00273,4,PCS 故障字 2,1,u16,1,,,125 不用,兼容之前
+00274,4,PCS 故障字 3,1,u16,1,,,125 不用,兼容之前
+00275,4,PCS 故障字 4,1,u16,1,,,
+00276,4,DCDC 故障字 1,1,u16,1,,,
+00277,4,DCDC 故障字 2,1,u16,1,,,
+00278,4,DCDC 故障字 3,1,u16,1,,,
+00279,4,DCDC 故障字 4,1,u16,1,,,
+00280,4,BMS 工作指令,3,u16,1,,"0x1111:禁充
+0x2222:禁放
+0x5555:待机
+0xaaaa:故障
+0xbbbb:正常
+0xcccc:告警",
+00281,4,BMS 允许充电电流,3,u16,0.1,A,,
+00282,4,BMS 允许放电电流,3,u16,0.1,A,,
+00283,4,BMS SOC,3,u16,0.1,%,,
+00284,4,BMS 可充电电量,3,u16,0.1,kWh,,
+00285,4,BMS 可放电电量,3,u16,0.1,kWh,,
+00286,4,BMS 总电压,3,u16,0.1,V,,

+ 2 - 2
emu-config.yaml

@@ -1,12 +1,12 @@
 emu:
   ver: '0.0.1'
   pcs:
-    host: ""
+    host: "127.0.0.1"
     port: 33434
   bms:
   ems:
     # 读取间隔, 单位ms
-    read_interval: 1000
+    read_interval: 5000
 rabbitmq:
   host: '122.51.163.61'
   port: 5672

+ 38 - 0
src/ems/pcs/mod.rs

@@ -1 +1,39 @@
+use crate::internal::modbus::tcp_code::ModbusTcpCode;
+use serde::{Deserialize, Serialize};
+
 pub mod pcs;
+
+#[derive(Debug, Serialize, Deserialize)]
+pub(crate) struct PcsCsvData {
+    pub address: Option<u16>,
+    pub code: Option<u8>,
+    pub name: Option<String>,
+    pub rw: Option<u8>,
+    #[serde(rename = "type")]
+    pub t: Option<String>,
+    pub factor: Option<f32>,
+    pub unit: Option<String>,
+    pub note: Option<String>,
+    pub desc: Option<String>,
+}
+
+/// pcs config
+pub(crate) fn pcs_conf() -> anyhow::Result<Vec<ModbusTcpCode>> {
+    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()?;
+        vec.push(code);
+    }
+    Ok(vec)
+}
+
+mod test {
+    use crate::ems::pcs::pcs_conf;
+
+    #[test]
+    fn test_pcs_conf() {
+        assert!(pcs_conf().is_ok());
+    }
+}

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

@@ -1,15 +1,23 @@
 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::utils;
-use log::info;
+use anyhow::bail;
+use bytes::Bytes;
+use log::{debug, info};
+use std::ops::Deref;
 use std::sync::Arc;
 use tokio::sync::Mutex;
+use tokio::time::Instant;
 use tokio_modbus::client::{Reader, Writer};
+use tokio_modbus::FunctionCode;
 
 pub struct Pcs {
     pub id: String,
     pub producer: Producer,
     pub consumer: Arc<Mutex<Consumer>>,
+    pub modbus_code: Arc<Mutex<Vec<ModbusTcpCode>>>,
     pub ctx: Arc<Mutex<tokio_modbus::client::Context>>,
 }
 
@@ -24,26 +32,67 @@ impl Pcs {
             format!("{}:{}", pcs_config.host, pcs_config.port).parse()?,
         )
         .await?;
+        let modbus_code = pcs_conf()?;
         Ok(Pcs {
             id,
             producer,
             consumer: Arc::new(Mutex::new(consumer)),
+            modbus_code: Arc::new(Mutex::new(modbus_code)),
             ctx: Arc::new(Mutex::new(ctx)),
         })
     }
+
+    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| {
+                it.addr.is_some()
+                    && it.name.is_some()
+                    && 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
+                    .ctx
+                    .lock()
+                    .await
+                    .read_input_registers(addr, input_registers.len() as u16)
+                    .await??;
+                if words.len() == input_registers.len() {
+                    for (i, word2) in words.chunks(2).enumerate() {
+                        if let Some(tcp_code) = input_registers.get_mut(i) {
+                            //大端序
+                            tcp_code.data = Some([word2[0] as u8, word2[1] as u8]);
+                        }
+                    }
+                } else {
+                    bail!(
+                        "返回的数据长度不正确, register长度:{}, data长度:{}",
+                        input_registers.len(),
+                        words.len()
+                    )
+                }
+            }
+        }
+        Ok(())
+    }
 }
 
 #[async_trait::async_trait]
 impl Service for Pcs {
     async fn read_task(&self) {
         let producer = self.producer.clone();
-        let ctx = self.ctx.clone();
         loop {
             tokio::time::sleep(tokio::time::Duration::from_millis(
                 app_config().emu.ems.read_interval,
             ))
             .await;
-            let a = ctx.lock().await.read_holding_registers(1000, 10).await;
+            self.read_input_register()
+                .await
+                .expect("read_input_register");
         }
     }
 

+ 2 - 0
src/internal/mod.rs

@@ -1 +1,3 @@
 pub mod utils;
+
+pub mod modbus;

+ 8 - 0
src/internal/modbus/mod.rs

@@ -0,0 +1,8 @@
+pub mod tcp_code;
+
+#[derive(Debug)]
+pub enum ModbusDataType {
+    BOOL,
+    U16,
+    S16,
+}

+ 72 - 0
src/internal/modbus/tcp_code.rs

@@ -0,0 +1,72 @@
+use crate::ems::pcs::PcsCsvData;
+use crate::internal::modbus::ModbusDataType;
+use std::collections::HashMap;
+
+#[derive(Debug)]
+pub struct ModbusTcpCode {
+    pub addr: Option<u16>,
+    pub code: Option<u8>,
+    pub data: Option<[u8; 2]>,
+    pub name: Option<String>,
+    pub data_type: Option<ModbusDataType>,
+    pub factor: Option<f32>,
+    pub unit: Option<String>,
+    pub note: Option<HashMap<i32, String>>,
+    pub desc: Option<String>,
+}
+
+impl ModbusTcpCode {}
+
+impl TryFrom<PcsCsvData> for ModbusTcpCode {
+    type Error = anyhow::Error;
+
+    fn try_from(value: PcsCsvData) -> Result<Self, Self::Error> {
+        let addr = value.address;
+        let code = value.code;
+        let name = value.name;
+        let mut data_type = None;
+        if let Some(ts) = value.t {
+            data_type = if ts == "bool" {
+                Some(ModbusDataType::BOOL)
+            } else if ts == "u16" {
+                Some(ModbusDataType::U16)
+            } else if ts == "s16" {
+                Some(ModbusDataType::S16)
+            } else {
+                None
+            }
+        };
+        let factor = value.factor;
+        let unit = value.unit;
+        let desc = value.desc;
+        let mut note = None;
+        if let Some(n) = value.note {
+            let mut hash_map = HashMap::new();
+            for x in n.split('\n').into_iter() {
+                let kv = x.split(':').collect::<Vec<&str>>();
+                if let Some(key) = kv.get(0) {
+                    let k = if key.starts_with("0x") {
+                        i32::from_str_radix(key.trim().replace("0x", "").as_ref(), 16)?
+                    } else {
+                        key.parse::<i32>()?
+                    };
+                    if let Some(val) = kv.get(1) {
+                        hash_map.insert(k, val.trim().to_string());
+                    }
+                }
+            }
+            note = Some(hash_map);
+        }
+        Ok(ModbusTcpCode {
+            addr,
+            code,
+            data: None,
+            name,
+            data_type,
+            factor,
+            unit,
+            note,
+            desc,
+        })
+    }
+}