Ввод калибровок

master

1
.gitignore vendored

@ -0,0 +1 @@
/target

3815
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,16 @@
[package]
name = "HARG_Client"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rmodbus="0.9.*"
eframe = "0.27.*"
serialport= "4.2.*"
async-std = "1.12.*"
local-encoding="0.2.*"
[profile.release]
opt-level = "z"

@ -0,0 +1,6 @@
H2_A = 0.0
H2_B = 0.0
H2_C = 1.0
H2_D = 0.0
HUMI_K = 1.0
HUMI_B = 0.0

@ -0,0 +1,432 @@
//! Show a custom window frame instead of the default OS window chrome decorations.
// #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
use local_encoding::{Encoder, Encoding};
use rmodbus::client::ModbusRequest;
use rmodbus::{guess_response_frame_len, ModbusProto};
use std::collections::HashMap;
use std::f32::consts::E;
use std::fs::OpenOptions;
use std::io::{BufRead, BufReader, Read};
use std::os::raw;
use std::process::exit;
use std::rc::Rc;
use std::sync::mpsc::{Receiver, Sender};
use std::sync::{mpsc, Arc, Mutex};
use std::thread::ThreadId;
use std::{
collections::btree_set::Union,
io::{self, ErrorKind},
thread,
time::Duration,
};
use std::{default, mem, process};
use eframe::{
egui::{self, Button, RichText},
epaint::Vec2,
};
use serialport::{
ClearBuffer, DataBits, Error, FlowControl, Parity, Result, SerialPort, SerialPortInfo,
SerialPortType, StopBits, UsbPortInfo,
};
//custom types
fn main() {
let port = serialport::available_ports().unwrap();
println!("Доступные порты:");
if port.len() > 0 {
for spinfo in port {
print!("{:#?} ☭ ", spinfo.port_name);
if let SerialPortType::UsbPort(info) = spinfo.port_type {
println!("{:#?}\n", info.product.unwrap());
}
}
loop {
if let Err(e) = mb_port_loop() {
match e.kind {
serialport::ErrorKind::Io(ErrorKind::TimedOut) => {
println!("Нет ответа по данному порту:{:#?}!", e.kind);
println!("Может другой?");
}
serialport::ErrorKind::Io(ErrorKind::Other) => {
println!("asda{:#?}!", e.kind);
break;
}
_ => {
println!("Другая ошибка:{:#?}!", e.kind);
break;
}
}
}
break;
}
} else {
println!("Нет доступных портов. Завершение работы . . .");
}
// let options = eframe::NativeOptions {
// // Hide the OS-specific "chrome" around the window:
// decorated: true,
// // To have rounded corners we need transparency:
// transparent: true,
// default_theme: eframe::Theme::Dark,
// initial_window_size: Some(egui::vec2(640.0, 300.0)),
// min_window_size: Some(egui::vec2(640.0, 300.0)),
// resizable:true,
// ..Default::default()
// };
// eframe::run_native(
// "HARG+ Client", // unused title
// options,
// Box::new(|_cc| {
// Box::new(MyApp {
// ..Default::default()
// })
// }),
// ).unwrap();
}
fn mb_trancieve(port: &mut Box<dyn SerialPort>, buf: &Vec<u8>) -> Result<Vec<u8>> {
let mut response: Vec<u8> = Vec::new();
port.write(&buf)?;
// read first 6 bytes of response frame
let mut buf = [0u8; 3]; //3 байта если есть ошибки, иначе их больше
port.read_exact(&mut buf)?;
response.extend_from_slice(&buf); //Если ошибок нет, то ответ будет больше 3-х байтов
let len = guess_response_frame_len(&buf, ModbusProto::Rtu).unwrap();
// read rest of response frame
if len > 3 {
let mut resp = vec![0u8; (len - 3) as usize];
port.read_exact(&mut resp)?;
response.extend(resp);
}
port.clear(serialport::ClearBuffer::All)?;
return Ok(response);
}
fn mb_port_loop() -> Result<ErrorKind> {
println!("Введите имя файла с коэффициентами:");
let mut path = String::new();
let _ = io::stdin().read_line(&mut path);
println!("{:#?}", path);
let path = path.trim_end();
let file = OpenOptions::new().read(true).open(&path);
let file = match file {
Ok(file) => file,
Err(e) => {
println!("Не удаётся открыть {:?}\r\n{}", &path, e);
exit(1);
}
};
//парсинг коэффициентов
let coef_buffer = BufReader::new(file);
let mut coef_lines: Vec<String> = Vec::new();
for (_num, line) in coef_buffer.lines().enumerate() {
coef_lines.push(line.unwrap());
}
#[derive(Default,Debug)]
struct CoefsCmds {
coef: [f32; 6],
cmd: [u16; 6],
}
let mut coefs_cmds = CoefsCmds ::default();
for line in coef_lines {
// println!("{}", &line);
let word: Vec<_> = line.split_whitespace().collect();
// let word: Vec<_> = line.split(|c| c == ' ' || c == '_').collect();
// println!("{:#?}", word.len());
if word.len() != 0 {
if word[0] == "H2_A" && word[1] == "=" && word.len() == 3 {
coefs_cmds.coef[0] = word[2].parse().unwrap();
coefs_cmds.cmd[0]=0x000Au16;
}
if word[0] == "H2_B" && word[1] == "=" && word.len() == 3 {
coefs_cmds.coef[1] = word[2].parse().unwrap();
coefs_cmds.cmd[1]=0x000Bu16;
}
if word[0] == "H2_C" && word[1] == "=" && word.len() == 3 {
coefs_cmds.coef[2] = word[2].parse().unwrap();
coefs_cmds.cmd[2]=0x000Cu16;
}
if word[0] == "H2_D" && word[1] == "=" && word.len() == 3 {
coefs_cmds.coef[3] = word[2].parse().unwrap();
coefs_cmds.cmd[3]=0x000Du16;
}
if word[0] == "HUMI_K" && word[1] == "=" && word.len() == 3 {
coefs_cmds.coef[4] = word[2].parse().unwrap();
coefs_cmds.cmd[4]=0x001Au16;
}
if word[0] == "HUMI_B" && word[1] == "=" && word.len() == 3 {
coefs_cmds.coef[5] = word[2].parse().unwrap();
coefs_cmds.cmd[5]=0x001Bu16;
}
}
};
println!("Выберите нужный порт:");
let mut input_port_name = String::new();
let _ = io::stdin().read_line(&mut input_port_name);
let port_name = input_port_name.trim_end();
let port = serialport::new(port_name, 38400)
.data_bits(DataBits::Eight)
.parity(Parity::None)
.stop_bits(StopBits::One)
.flow_control(FlowControl::None)
.timeout(Duration::from_millis(1000))
.open();
match port {
Ok(mut port_wf) => {
const MB_ADDRESS: u8 = 6u8;
const MB_PASSWORD_1: u16 = 0x1234u16;
const MB_PASSWORD_2: u16 = 0x5678u16;
const MB_CMD_FW_WC: u16 = 0x5743u16;
const MB_CMD_FW_RC: u16 = 0x5243;
const MB_STATUS_FW_OK: u16 = 0x4F4Bu16;
const MB_STATUS_FW_ER: u16 = 0x4552u16;
const MB_REG_CAL_CTRL: u16 = 72;
const MB_REG_PASSWORD: u16 = 70;
const MB_REG_FW_CTRL: u16 = 76;
const MB_REG_CALIBR: u16 = 80;
println!("Задайте адрес ModBUS устройства:");
let mut input_port_name = String::new();
let _ = io::stdin().read_line(&mut input_port_name);
let addr = input_port_name.trim_end().parse::<u8>().unwrap();
println!("Адрес: {:?}", addr);
let mut mb_req = ModbusRequest::new(addr, ModbusProto::Rtu);
let mut request = Vec::new();
// let mut response = Vec::new();
mb_req.generate_get_holdings(0, 1, &mut request).unwrap();
let response = mb_trancieve(&mut port_wf, &request)?;
// check if frame has no Modbus error inside
mb_req.parse_ok(&response).unwrap();
let mut addr = Vec::new();
mb_req.parse_u16(&response, &mut addr).unwrap();
println!("В регистре 0: {:?}", addr);
for i in 0..=5 {
let uint32 = coefs_cmds.coef[i].to_bits();
let a = (uint32 & 0xFFFF) as u16;
let b = ((uint32 >> 16) & 0xFFFF) as u16;
println!(
"{:#06X?} {:#06X?} {:#06X?} {:#?}",
a, b, coefs_cmds.cmd[i], coefs_cmds.coef[i]
);
let cmd = [
MB_PASSWORD_1,
MB_PASSWORD_2,
MB_CMD_FW_WC,
coefs_cmds.cmd[i],
a,
b,
];
mb_req
.generate_set_holdings_bulk(MB_REG_PASSWORD, &cmd, &mut request)
.unwrap();
let response = mb_trancieve(&mut port_wf, &request)?;
mb_req.parse_ok(&response).unwrap();
thread::sleep(Duration::from_millis(20));
//Проверка ввода коэффициента
mb_req
.generate_get_holdings(MB_REG_CAL_CTRL, 1, &mut request)
.unwrap();
let response = mb_trancieve(&mut port_wf, &request)?;
mb_req.parse_ok(&response).unwrap();
let mut status = Vec::new();
mb_req.parse_u16(&response, &mut status).unwrap();
let status = status[0];
let status = match status {
MB_STATUS_FW_OK => "FW_OK",
_ => "FW_ER",
};
println!("Статус: {:#?}", status);
}
println!("0x000F");
let cmd = [
MB_PASSWORD_1,
MB_PASSWORD_2,
MB_CMD_FW_WC,
0x000Fu16,
1,
];
mb_req
.generate_set_holdings_bulk(MB_REG_PASSWORD, &cmd, &mut request)
.unwrap();
let response = mb_trancieve(&mut port_wf, &request)?;
mb_req.parse_ok(&response).unwrap();
thread::sleep(Duration::from_millis(20));
//Проверка ввода коэффициента
mb_req
.generate_get_holdings(MB_REG_CAL_CTRL, 1, &mut request)
.unwrap();
let response = mb_trancieve(&mut port_wf, &request)?;
mb_req.parse_ok(&response).unwrap();
let mut status = Vec::new();
mb_req.parse_u16(&response, &mut status).unwrap();
let status = status[0];
let status = match status {
MB_STATUS_FW_OK => "FW_OK",
_ => "FW_ER",
};
println!("Статус: {:#?}", status);
//Проверка коэффициентов
mb_req
.generate_set_holding(MB_REG_FW_CTRL, MB_CMD_FW_RC, &mut request)
.unwrap();
let response = mb_trancieve(&mut port_wf, &request)?;
// check if frame has no Modbus error inside
mb_req.parse_ok(&response).unwrap();
mb_req
.generate_get_holdings(MB_REG_CALIBR, 13, &mut request)
.unwrap();
let response = mb_trancieve(&mut port_wf, &request)?;
mb_req.parse_ok(&response).unwrap();
let mut raw_str = Vec::new();
mb_req.parse_u16(&response, &mut raw_str).unwrap();
for i in (1..12).step_by(2) {
let f = (raw_str[i] as u32) + (raw_str[i + 1] as u32) << 16;
let f = unsafe { mem::transmute::<u32, f32>(f) };
print!("{:#06X?}: ", coefs_cmds.cmd[i / 2]);
if coefs_cmds.coef[i / 2] != f {
println!("ERR");
} else {
println!("OK")
}
}
return Ok(ErrorKind::Other);
}
Err(error) => Err(error),
}
}
#[derive(Default)]
struct MyApp {
enabled: bool,
}
impl eframe::App for MyApp {
fn clear_color(&self, _visuals: &egui::Visuals) -> [f32; 4] {
[0.3f32, 0.3f32, 0.3f32, 0.9f32] // Make sure we don't paint anything behind the rounded corners
// egui::Rgba::TRANSPARENT;
}
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
let title = "HARG+ Client".to_string();
// custom_window_frame(ctx, frame, title.as_str(), |ui| {
// self.side_bar(ui);
// });
}
}
impl MyApp {
fn side_bar(&mut self, ui: &mut egui::Ui) {
egui::SidePanel::left("backend_panel")
.default_width(200.0)
.resizable(false)
.show_inside(ui, |ui| {
ui.vertical_centered(|ui| {
ui.heading("Микрогаз");
});
});
}
}
fn custom_window_frame(
ctx: &egui::Context,
frame: &mut eframe::Frame,
title: &str,
add_contents: impl FnOnce(&mut egui::Ui),
) {
use egui::*;
let text_color = ctx.style().visuals.text_color();
// Height of the title bar
let height = 28.0;
CentralPanel::default()
.frame(Frame::none())
.show(ctx, |ui| {
let rect = Rect::from_min_max(pos2(0.0, 0.0), pos2(640.0, 300.0));
// ui.clip_rect();
let painter = ui.painter();
// Paint the frame:
painter.rect(
rect.shrink(0.1),
4.0,
ctx.style().visuals.window_fill(),
// Color32::LIGHT_RED,
Stroke::new(1.0, text_color),
);
// Paint the title:
painter.text(
rect.left_top() + vec2(4.0, height / 2.0),
Align2::LEFT_CENTER,
title,
FontId::proportional(16.0),
text_color,
);
// Paint the line under the title:
painter.line_segment(
[
rect.left_top() + vec2(2.0, height),
rect.right_top() + vec2(-2.0, height),
],
Stroke::new(1.0, text_color),
);
// Interact with the title bar (drag to move window):
let title_bar_rect = {
let mut rect = rect;
rect.max.y = rect.min.y + height;
rect
};
let title_bar_response =
ui.interact(title_bar_rect, Id::new("title_bar"), Sense::click());
if title_bar_response.is_pointer_button_down_on() {
// frame.drag_window();
}
// Add the close button:
let close_response = ui.put(
Rect::from_min_size(rect.right_top() - vec2(height, 0.0), Vec2::splat(height)),
Button::new(RichText::new("❌").size(height - 4.0)).frame(false),
);
if close_response.clicked() {
// frame.close();
}
// Add the contents:
let content_rect = {
let mut rect = rect;
rect.min.y = title_bar_rect.max.y;
rect
}
.shrink(4.0);
// if ui.a
// let mut content_ui = ui.child_ui(content_rect, *ui.layout());
// add_contents(&mut content_ui);
});
}
Loading…
Cancel
Save