Fix tests
parent
32cd2b2e78
commit
1698959de9
|
@ -196,3 +196,145 @@ pub(crate) fn default_modbus_flow_control() -> tokio_serial::FlowControl {
|
||||||
pub(crate) fn default_modbus_parity() -> tokio_serial::Parity {
|
pub(crate) fn default_modbus_parity() -> tokio_serial::Parity {
|
||||||
tokio_serial::Parity::None
|
tokio_serial::Parity::None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_minimal_tcp_connect_config() {
|
||||||
|
use serde_json::json;
|
||||||
|
let result = serde_json::from_value::<Config>(json!({
|
||||||
|
"proto": "tcp",
|
||||||
|
"host": "1.1.1.1"
|
||||||
|
}));
|
||||||
|
|
||||||
|
let connect = result.unwrap();
|
||||||
|
assert!(matches!(
|
||||||
|
connect.settings,
|
||||||
|
ModbusProto::Tcp {
|
||||||
|
ref host,
|
||||||
|
port: 502
|
||||||
|
} if host == "1.1.1.1"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_full_tcp_connect_config() {
|
||||||
|
use serde_json::json;
|
||||||
|
let _ = serde_json::from_value::<Config>(json!({
|
||||||
|
"proto": "tcp",
|
||||||
|
"host": "10.10.10.219",
|
||||||
|
"unit": 1,
|
||||||
|
"address_offset": -1,
|
||||||
|
"input": [
|
||||||
|
{
|
||||||
|
"address": 5017,
|
||||||
|
"type": "u32",
|
||||||
|
"name": "dc_power",
|
||||||
|
"swap_words": false,
|
||||||
|
"period": "3s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": 5008,
|
||||||
|
"type": "s16",
|
||||||
|
"name": "internal_temperature",
|
||||||
|
"period": "1m"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": 13008,
|
||||||
|
"type": "s32",
|
||||||
|
"name": "load_power",
|
||||||
|
"swap_words": false,
|
||||||
|
"period": "3s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": 13010,
|
||||||
|
"type": "s32",
|
||||||
|
"name": "export_power",
|
||||||
|
"swap_words": false,
|
||||||
|
"period": "3s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": 13022,
|
||||||
|
"name": "battery_power",
|
||||||
|
"period": "3s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": 13023,
|
||||||
|
"name": "battery_level",
|
||||||
|
"period": "1m"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": 13024,
|
||||||
|
"name": "battery_health",
|
||||||
|
"period": "10m"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hold": [
|
||||||
|
{
|
||||||
|
"address": 13058,
|
||||||
|
"name": "max_soc",
|
||||||
|
"period": "90s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": 13059,
|
||||||
|
"name": "min_soc",
|
||||||
|
"period": "90s"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_minimal_rtu_connect_config() {
|
||||||
|
use serde_json::json;
|
||||||
|
let result = serde_json::from_value::<Config>(json!({
|
||||||
|
"proto": "rtu",
|
||||||
|
"tty": "/dev/ttyUSB0",
|
||||||
|
"baud_rate": 9600,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let connect = result.unwrap();
|
||||||
|
use tokio_serial::*;
|
||||||
|
assert!(matches!(
|
||||||
|
connect.settings,
|
||||||
|
ModbusProto::Rtu {
|
||||||
|
ref tty,
|
||||||
|
baud_rate: 9600,
|
||||||
|
data_bits: DataBits::Eight,
|
||||||
|
stop_bits: StopBits::One,
|
||||||
|
flow_control: FlowControl::None,
|
||||||
|
parity: Parity::None,
|
||||||
|
..
|
||||||
|
} if tty == "/dev/ttyUSB0"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_complete_rtu_connect_config() {
|
||||||
|
use serde_json::json;
|
||||||
|
let result = serde_json::from_value::<Config>(json!({
|
||||||
|
"proto": "rtu",
|
||||||
|
"tty": "/dev/ttyUSB0",
|
||||||
|
"baud_rate": 12800,
|
||||||
|
|
||||||
|
// TODO: make lowercase words work
|
||||||
|
"data_bits": "Seven", // TODO: make 7 work
|
||||||
|
"stop_bits": "Two", // TODO: make 2 work
|
||||||
|
"flow_control": "Software",
|
||||||
|
"parity": "Even",
|
||||||
|
}));
|
||||||
|
|
||||||
|
let connect = result.unwrap();
|
||||||
|
use tokio_serial::*;
|
||||||
|
assert!(matches!(
|
||||||
|
connect.settings,
|
||||||
|
ModbusProto::Rtu {
|
||||||
|
ref tty,
|
||||||
|
baud_rate: 12800,
|
||||||
|
data_bits: DataBits::Seven,
|
||||||
|
stop_bits: StopBits::Two,
|
||||||
|
flow_control: FlowControl::Software,
|
||||||
|
parity: Parity::Even,
|
||||||
|
..
|
||||||
|
} if tty == "/dev/ttyUSB0"
|
||||||
|
),);
|
||||||
|
}
|
||||||
|
|
|
@ -15,139 +15,5 @@ pub enum ConnectState {
|
||||||
Errored,
|
Errored,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Serialize)]
|
|
||||||
// pub struct ConnectStatus {
|
|
||||||
// #[serde(flatten)]
|
|
||||||
// pub connect: config::Connect,
|
|
||||||
// pub status: ConnectState,
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub type UnitId = tokio_modbus::prelude::SlaveId;
|
pub type UnitId = tokio_modbus::prelude::SlaveId;
|
||||||
pub type Unit = tokio_modbus::prelude::Slave;
|
pub type Unit = tokio_modbus::prelude::Slave;
|
||||||
|
|
||||||
impl RegisterValueType {
|
|
||||||
pub fn parse_words(&self, words: &[u16]) -> serde_json::Value {
|
|
||||||
use self::register::RegisterValueType as T;
|
|
||||||
use self::register::{RegisterArray, RegisterNumeric as N, RegisterString};
|
|
||||||
use serde_json::json;
|
|
||||||
|
|
||||||
let bytes: Vec<u8> = words.iter().flat_map(|v| v.to_ne_bytes()).collect();
|
|
||||||
|
|
||||||
match *self {
|
|
||||||
T::Numeric { ref of, ref adjust } => {
|
|
||||||
use rust_decimal::MathematicalOps;
|
|
||||||
let scale: Decimal = Decimal::TEN.powi(adjust.scale.into()).normalize();
|
|
||||||
let offset = Decimal::from(adjust.offset);
|
|
||||||
match of {
|
|
||||||
N::U8 => json!(scale * Decimal::from(bytes[1]) + offset), // or is it 0?
|
|
||||||
N::U16 => json!(scale * Decimal::from(words[0]) + offset),
|
|
||||||
N::U32 => {
|
|
||||||
json!(bytes
|
|
||||||
.try_into()
|
|
||||||
.map(|bytes| scale * Decimal::from(u32::from_le_bytes(bytes)) + offset)
|
|
||||||
.ok())
|
|
||||||
}
|
|
||||||
N::U64 => {
|
|
||||||
json!(bytes
|
|
||||||
.try_into()
|
|
||||||
.map(|bytes| scale * Decimal::from(u64::from_le_bytes(bytes)) + offset)
|
|
||||||
.ok())
|
|
||||||
}
|
|
||||||
N::I8 => {
|
|
||||||
json!(vec![bytes[1]]
|
|
||||||
.try_into()
|
|
||||||
.map(|bytes| scale * Decimal::from(i8::from_le_bytes(bytes)) + offset)
|
|
||||||
.ok())
|
|
||||||
}
|
|
||||||
N::I16 => {
|
|
||||||
json!(bytes
|
|
||||||
.try_into()
|
|
||||||
.map(|bytes| scale * Decimal::from(i16::from_le_bytes(bytes)) + offset)
|
|
||||||
.ok())
|
|
||||||
}
|
|
||||||
N::I32 => {
|
|
||||||
json!(bytes
|
|
||||||
.try_into()
|
|
||||||
.map(|bytes| scale * Decimal::from(i32::from_le_bytes(bytes)) + offset)
|
|
||||||
.ok())
|
|
||||||
}
|
|
||||||
N::I64 => {
|
|
||||||
json!(bytes
|
|
||||||
.try_into()
|
|
||||||
.map(|bytes| scale * Decimal::from(i64::from_le_bytes(bytes)) + offset)
|
|
||||||
.ok())
|
|
||||||
}
|
|
||||||
N::F32 => {
|
|
||||||
json!(bytes
|
|
||||||
.try_into()
|
|
||||||
.map(|bytes| scale
|
|
||||||
* Decimal::from_f32(f32::from_le_bytes(bytes)).unwrap()
|
|
||||||
+ offset)
|
|
||||||
.ok())
|
|
||||||
}
|
|
||||||
N::F64 => {
|
|
||||||
json!(bytes
|
|
||||||
.try_into()
|
|
||||||
.map(|bytes| scale
|
|
||||||
* Decimal::from_f64(f64::from_le_bytes(bytes)).unwrap()
|
|
||||||
+ offset)
|
|
||||||
.ok())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
T::String(RegisterString { .. }) => {
|
|
||||||
json!(String::from_utf16_lossy(words))
|
|
||||||
}
|
|
||||||
T::Array(RegisterArray { .. }) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Register {
|
|
||||||
pub fn parse_words(&self, words: &[u16]) -> serde_json::Value {
|
|
||||||
self.parse.value_type.parse_words(words)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply_swaps(&self, words: &[u16]) -> Vec<u16> {
|
|
||||||
let words: Vec<u16> = if self.parse.swap_bytes.0 {
|
|
||||||
words.iter().map(|v| v.swap_bytes()).collect()
|
|
||||||
} else {
|
|
||||||
words.into()
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.parse.swap_words.0 {
|
|
||||||
words
|
|
||||||
.chunks_exact(2)
|
|
||||||
.flat_map(|chunk| vec![chunk[1], chunk[0]])
|
|
||||||
.collect()
|
|
||||||
} else {
|
|
||||||
words
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(test)]
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
#[test]
|
|
||||||
fn test_parse_1() {
|
|
||||||
use self::register::{RegisterParse, Swap};
|
|
||||||
use serde_json::json;
|
|
||||||
|
|
||||||
let reg = Register {
|
|
||||||
address: 42,
|
|
||||||
name: None,
|
|
||||||
interval: Default::default(),
|
|
||||||
parse: RegisterParse {
|
|
||||||
swap_bytes: Swap(false),
|
|
||||||
swap_words: Swap(false),
|
|
||||||
value_type: RegisterValueType::Numeric {
|
|
||||||
of: register::RegisterNumeric::I32,
|
|
||||||
adjust: register::RegisterNumericAdjustment {
|
|
||||||
scale: 0,
|
|
||||||
offset: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(reg.parse_words(&[843, 0]), json!(843));
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::Duration;
|
use std::{ops::Add, time::Duration};
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "lowercase", default)]
|
#[serde(rename_all = "lowercase", default)]
|
||||||
|
@ -180,249 +180,245 @@ fn default_register_interval() -> Duration {
|
||||||
Duration::from_secs(60)
|
Duration::from_secs(60)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn parse_minimal_tcp_connect_config() {
|
fn parse_empty_register_parser_defaults() {
|
||||||
// let result = serde_json::from_value::<Connect>(json!({
|
use serde_json::json;
|
||||||
// "proto": "tcp",
|
let empty = serde_json::from_value::<RegisterParse>(json!({}));
|
||||||
// "host": "1.1.1.1"
|
assert!(matches!(
|
||||||
// }));
|
empty.unwrap(),
|
||||||
|
RegisterParse {
|
||||||
|
swap_bytes: Swap(false),
|
||||||
|
swap_words: Swap(false),
|
||||||
|
value_type: RegisterValueType::Numeric {
|
||||||
|
of: RegisterNumeric::U16,
|
||||||
|
adjust: RegisterNumericAdjustment {
|
||||||
|
scale: 0,
|
||||||
|
offset: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// let connect = result.unwrap();
|
#[test]
|
||||||
// assert!(matches!(
|
fn parse_register_parser_type() {
|
||||||
// connect.settings,
|
use serde_json::json;
|
||||||
// ModbusProto::Tcp {
|
let result = serde_json::from_value::<RegisterParse>(json!({
|
||||||
// ref host,
|
"type": "s32"
|
||||||
// port: 502
|
}));
|
||||||
// } if host == "1.1.1.1"
|
assert!(matches!(
|
||||||
// ))
|
result.unwrap().value_type,
|
||||||
// }
|
RegisterValueType::Numeric {
|
||||||
|
of: RegisterNumeric::I32,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn parse_full_tcp_connect_config() {
|
fn parse_register_parser_array() {
|
||||||
// let _ = serde_json::from_value::<Connect>(json!({
|
use serde_json::json;
|
||||||
// "proto": "tcp",
|
let result = serde_json::from_value::<RegisterParse>(json!({
|
||||||
// "host": "10.10.10.219",
|
"type": "array",
|
||||||
// "unit": 1,
|
"of": "s32",
|
||||||
// "address_offset": -1,
|
"count": 10,
|
||||||
// "input": [
|
}));
|
||||||
// {
|
let payload = result.unwrap();
|
||||||
// "address": 5017,
|
// println!("{:?}", payload);
|
||||||
// "type": "u32",
|
// println!("{}", serde_json::to_string_pretty(&payload).unwrap());
|
||||||
// "name": "dc_power",
|
|
||||||
// "swap_words": false,
|
|
||||||
// "period": "3s"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "address": 5008,
|
|
||||||
// "type": "s16",
|
|
||||||
// "name": "internal_temperature",
|
|
||||||
// "period": "1m"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "address": 13008,
|
|
||||||
// "type": "s32",
|
|
||||||
// "name": "load_power",
|
|
||||||
// "swap_words": false,
|
|
||||||
// "period": "3s"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "address": 13010,
|
|
||||||
// "type": "s32",
|
|
||||||
// "name": "export_power",
|
|
||||||
// "swap_words": false,
|
|
||||||
// "period": "3s"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "address": 13022,
|
|
||||||
// "name": "battery_power",
|
|
||||||
// "period": "3s"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "address": 13023,
|
|
||||||
// "name": "battery_level",
|
|
||||||
// "period": "1m"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "address": 13024,
|
|
||||||
// "name": "battery_health",
|
|
||||||
// "period": "10m"
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// "hold": [
|
|
||||||
// {
|
|
||||||
// "address": 13058,
|
|
||||||
// "name": "max_soc",
|
|
||||||
// "period": "90s"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "address": 13059,
|
|
||||||
// "name": "min_soc",
|
|
||||||
// "period": "90s"
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }))
|
|
||||||
// .unwrap();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
assert!(matches!(
|
||||||
// fn parse_minimal_rtu_connect_config() {
|
payload.value_type,
|
||||||
// let result = serde_json::from_value::<Connect>(json!({
|
RegisterValueType::Array(RegisterArray {
|
||||||
// "proto": "rtu",
|
of: RegisterNumeric::I32,
|
||||||
// "tty": "/dev/ttyUSB0",
|
count: 10,
|
||||||
// "baud_rate": 9600,
|
..
|
||||||
// }));
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// let connect = result.unwrap();
|
#[test]
|
||||||
// use tokio_serial::*;
|
fn parse_register_parser_array_implicit_u16() {
|
||||||
// assert!(matches!(
|
use serde_json::json;
|
||||||
// connect.settings,
|
let result = serde_json::from_value::<RegisterParse>(json!({
|
||||||
// ModbusProto::Rtu {
|
"type": "array",
|
||||||
// ref tty,
|
"count": 10,
|
||||||
// baud_rate: 9600,
|
}));
|
||||||
// data_bits: DataBits::Eight,
|
let payload = result.unwrap();
|
||||||
// stop_bits: StopBits::One,
|
// println!("{:?}", payload);
|
||||||
// flow_control: FlowControl::None,
|
// println!("{}", serde_json::to_string_pretty(&payload).unwrap());
|
||||||
// parity: Parity::None,
|
|
||||||
// ..
|
|
||||||
// } if tty == "/dev/ttyUSB0"
|
|
||||||
// ))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
assert!(matches!(
|
||||||
// fn parse_complete_rtu_connect_config() {
|
payload.value_type,
|
||||||
// let result = serde_json::from_value::<Connect>(json!({
|
RegisterValueType::Array(RegisterArray {
|
||||||
// "proto": "rtu",
|
of: RegisterNumeric::U16,
|
||||||
// "tty": "/dev/ttyUSB0",
|
count: 10,
|
||||||
// "baud_rate": 12800,
|
..
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// // TODO: make lowercase words work
|
#[test]
|
||||||
// "data_bits": "Seven", // TODO: make 7 work
|
fn parse_register_parser_string() {
|
||||||
// "stop_bits": "Two", // TODO: make 2 work
|
use serde_json::json;
|
||||||
// "flow_control": "Software",
|
let result = serde_json::from_value::<RegisterParse>(json!({
|
||||||
// "parity": "Even",
|
"type": "string",
|
||||||
// }));
|
"length": 10,
|
||||||
|
}));
|
||||||
|
let payload = result.unwrap();
|
||||||
|
// println!("{:?}", payload);
|
||||||
|
// println!("{}", serde_json::to_string_pretty(&payload).unwrap());
|
||||||
|
|
||||||
// let connect = result.unwrap();
|
assert!(matches!(
|
||||||
// use tokio_serial::*;
|
payload.value_type,
|
||||||
// assert!(matches!(
|
RegisterValueType::String(RegisterString { length: 10, .. })
|
||||||
// connect.settings,
|
));
|
||||||
// ModbusProto::Rtu {
|
}
|
||||||
// ref tty,
|
|
||||||
// baud_rate: 12800,
|
|
||||||
// data_bits: DataBits::Seven,
|
|
||||||
// stop_bits: StopBits::Two,
|
|
||||||
// flow_control: FlowControl::Software,
|
|
||||||
// parity: Parity::Even,
|
|
||||||
// ..
|
|
||||||
// } if tty == "/dev/ttyUSB0"
|
|
||||||
// ),);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn parse_empty_register_parser_defaults() {
|
fn parse_register_parser_scale_etc() {
|
||||||
// let empty = serde_json::from_value::<RegisterParse>(json!({}));
|
use serde_json::json;
|
||||||
// assert!(matches!(
|
let result = serde_json::from_value::<RegisterParse>(json!({
|
||||||
// empty.unwrap(),
|
"type": "s32",
|
||||||
// RegisterParse {
|
"scale": -1,
|
||||||
// swap_bytes: Swap(false),
|
"offset": 20,
|
||||||
// swap_words: Swap(false),
|
}));
|
||||||
// value_type: RegisterValueType::Numeric {
|
assert!(matches!(
|
||||||
// of: RegisterNumeric::U16,
|
result.unwrap().value_type,
|
||||||
// adjust: RegisterNumericAdjustment {
|
RegisterValueType::Numeric {
|
||||||
// scale: 0,
|
of: RegisterNumeric::I32,
|
||||||
// offset: 0,
|
adjust: RegisterNumericAdjustment {
|
||||||
// }
|
scale: -1,
|
||||||
// }
|
offset: 20
|
||||||
// }
|
}
|
||||||
// ));
|
}
|
||||||
// }
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
impl RegisterValueType {
|
||||||
// fn parse_register_parser_type() {
|
pub fn parse_words(&self, words: &[u16]) -> serde_json::Value {
|
||||||
// let result = serde_json::from_value::<RegisterParse>(json!({
|
use self::RegisterNumeric as N;
|
||||||
// "type": "s32"
|
use rust_decimal::{prelude::FromPrimitive, Decimal, MathematicalOps};
|
||||||
// }));
|
use serde_json::json;
|
||||||
// assert!(matches!(
|
use RegisterValueType as T;
|
||||||
// result.unwrap().value_type,
|
|
||||||
// RegisterValueType::Numeric {
|
|
||||||
// of: RegisterNumeric::I32,
|
|
||||||
// ..
|
|
||||||
// }
|
|
||||||
// ));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
let bytes: Vec<u8> = words.iter().flat_map(|v| v.to_ne_bytes()).collect();
|
||||||
// fn parse_register_parser_array() {
|
|
||||||
// let result = serde_json::from_value::<RegisterParse>(json!({
|
|
||||||
// "type": "array",
|
|
||||||
// "of": "s32",
|
|
||||||
// "count": 10,
|
|
||||||
// }));
|
|
||||||
// let payload = result.unwrap();
|
|
||||||
// // println!("{:?}", payload);
|
|
||||||
// // println!("{}", serde_json::to_string_pretty(&payload).unwrap());
|
|
||||||
|
|
||||||
// assert!(matches!(
|
match *self {
|
||||||
// payload.value_type,
|
T::Numeric { ref of, ref adjust } => {
|
||||||
// RegisterValueType::Array(RegisterArray {
|
let scale: Decimal = Decimal::TEN.powi(adjust.scale.into()).normalize();
|
||||||
// of: RegisterNumeric::I32,
|
let offset = Decimal::from(adjust.offset);
|
||||||
// count: 10,
|
match of {
|
||||||
// ..
|
N::U8 => json!(scale * Decimal::from(bytes[1]) + offset), // or is it 0?
|
||||||
// })
|
N::U16 => json!(scale * Decimal::from(words[0]) + offset),
|
||||||
// ));
|
N::U32 => {
|
||||||
// }
|
json!(bytes
|
||||||
|
.try_into()
|
||||||
|
.map(|bytes| scale * Decimal::from(u32::from_le_bytes(bytes)) + offset)
|
||||||
|
.ok())
|
||||||
|
}
|
||||||
|
N::U64 => {
|
||||||
|
json!(bytes
|
||||||
|
.try_into()
|
||||||
|
.map(|bytes| scale * Decimal::from(u64::from_le_bytes(bytes)) + offset)
|
||||||
|
.ok())
|
||||||
|
}
|
||||||
|
N::I8 => {
|
||||||
|
json!(vec![bytes[1]]
|
||||||
|
.try_into()
|
||||||
|
.map(|bytes| scale * Decimal::from(i8::from_le_bytes(bytes)) + offset)
|
||||||
|
.ok())
|
||||||
|
}
|
||||||
|
N::I16 => {
|
||||||
|
json!(bytes
|
||||||
|
.try_into()
|
||||||
|
.map(|bytes| scale * Decimal::from(i16::from_le_bytes(bytes)) + offset)
|
||||||
|
.ok())
|
||||||
|
}
|
||||||
|
N::I32 => {
|
||||||
|
json!(bytes
|
||||||
|
.try_into()
|
||||||
|
.map(|bytes| scale * Decimal::from(i32::from_le_bytes(bytes)) + offset)
|
||||||
|
.ok())
|
||||||
|
}
|
||||||
|
N::I64 => {
|
||||||
|
json!(bytes
|
||||||
|
.try_into()
|
||||||
|
.map(|bytes| scale * Decimal::from(i64::from_le_bytes(bytes)) + offset)
|
||||||
|
.ok())
|
||||||
|
}
|
||||||
|
N::F32 => {
|
||||||
|
json!(bytes
|
||||||
|
.try_into()
|
||||||
|
.map(|bytes| scale
|
||||||
|
* Decimal::from_f32(f32::from_le_bytes(bytes)).unwrap()
|
||||||
|
+ offset)
|
||||||
|
.ok())
|
||||||
|
}
|
||||||
|
N::F64 => {
|
||||||
|
json!(bytes
|
||||||
|
.try_into()
|
||||||
|
.map(|bytes| scale
|
||||||
|
* Decimal::from_f64(f64::from_le_bytes(bytes)).unwrap()
|
||||||
|
+ offset)
|
||||||
|
.ok())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
T::String(RegisterString { .. }) => {
|
||||||
|
json!(String::from_utf16_lossy(words))
|
||||||
|
}
|
||||||
|
T::Array(RegisterArray { .. }) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
impl Register {
|
||||||
// fn parse_register_parser_array_implicit_u16() {
|
pub fn parse_words(&self, words: &[u16]) -> serde_json::Value {
|
||||||
// let result = serde_json::from_value::<RegisterParse>(json!({
|
self.parse.value_type.parse_words(words)
|
||||||
// "type": "array",
|
}
|
||||||
// "count": 10,
|
|
||||||
// }));
|
|
||||||
// let payload = result.unwrap();
|
|
||||||
// // println!("{:?}", payload);
|
|
||||||
// // println!("{}", serde_json::to_string_pretty(&payload).unwrap());
|
|
||||||
|
|
||||||
// assert!(matches!(
|
pub fn apply_swaps(&self, words: &[u16]) -> Vec<u16> {
|
||||||
// payload.value_type,
|
let words: Vec<u16> = if self.parse.swap_bytes.0 {
|
||||||
// RegisterValueType::Array(RegisterArray {
|
words.iter().map(|v| v.swap_bytes()).collect()
|
||||||
// of: RegisterNumeric::U16,
|
} else {
|
||||||
// count: 10,
|
words.into()
|
||||||
// ..
|
};
|
||||||
// })
|
|
||||||
// ));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
if self.parse.swap_words.0 {
|
||||||
// fn parse_register_parser_string() {
|
words
|
||||||
// let result = serde_json::from_value::<RegisterParse>(json!({
|
.chunks_exact(2)
|
||||||
// "type": "string",
|
.flat_map(|chunk| vec![chunk[1], chunk[0]])
|
||||||
// "length": 10,
|
.collect()
|
||||||
// }));
|
} else {
|
||||||
// let payload = result.unwrap();
|
words
|
||||||
// // println!("{:?}", payload);
|
}
|
||||||
// // println!("{}", serde_json::to_string_pretty(&payload).unwrap());
|
}
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
#[test]
|
||||||
|
fn test_parse_1() {
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
// assert!(matches!(
|
let reg = AddressedRegister {
|
||||||
// payload.value_type,
|
address: 42,
|
||||||
// RegisterValueType::String(RegisterString { length: 10, .. })
|
register: Register {
|
||||||
// ));
|
name: None,
|
||||||
// }
|
interval: Default::default(),
|
||||||
|
parse: RegisterParse {
|
||||||
|
swap_bytes: Swap(false),
|
||||||
|
swap_words: Swap(false),
|
||||||
|
value_type: RegisterValueType::Numeric {
|
||||||
|
of: RegisterNumeric::I32,
|
||||||
|
adjust: RegisterNumericAdjustment {
|
||||||
|
scale: 0,
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// #[test]
|
assert_eq!(reg.register.parse_words(&[843, 0]), json!(843));
|
||||||
// fn parse_register_parser_scale_etc() {
|
}
|
||||||
// let result = serde_json::from_value::<RegisterParse>(json!({
|
|
||||||
// "type": "s32",
|
|
||||||
// "scale": -1,
|
|
||||||
// "offset": 20,
|
|
||||||
// }));
|
|
||||||
// assert!(matches!(
|
|
||||||
// result.unwrap().value_type,
|
|
||||||
// RegisterValueType::Numeric {
|
|
||||||
// of: RegisterNumeric::I32,
|
|
||||||
// adjust: RegisterNumericAdjustment {
|
|
||||||
// scale: -1,
|
|
||||||
// offset: 20
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ));
|
|
||||||
// }
|
|
||||||
|
|
Loading…
Reference in New Issue