提交 6d5800dc authored 作者: Serhij S's avatar Serhij S

raw udp for primary ipc

上级 e805cf4f
[package] [package]
name = "roboplc" name = "roboplc"
version = "0.1.14" version = "0.1.15"
edition = "2021" edition = "2021"
authors = ["Serhij S. <div@altertech.com>"] authors = ["Serhij S. <div@altertech.com>"]
license = "Apache-2.0" license = "Apache-2.0"
......
use roboplc::io::raw_udp::{UdpInput, UdpOutput}; use roboplc::io::{UdpReceiver, UdpSender};
use roboplc::prelude::*; use roboplc::prelude::*;
use roboplc::time::interval; use roboplc::time::interval;
use tracing::{error, info}; use tracing::{error, info};
...@@ -10,6 +10,8 @@ enum Message { ...@@ -10,6 +10,8 @@ enum Message {
// A raw UDP structure, to be sent and received // A raw UDP structure, to be sent and received
// //
// The recommended way of IPC for RoboPLC
//
// Raw UDP structures are used by various software, e.g. Matlab, LabView, etc. as well as by some // Raw UDP structures are used by various software, e.g. Matlab, LabView, etc. as well as by some
// fieldbus devices // fieldbus devices
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
...@@ -28,7 +30,7 @@ struct UdpIn {} ...@@ -28,7 +30,7 @@ struct UdpIn {}
impl Worker<Message, ()> for UdpIn { impl Worker<Message, ()> for UdpIn {
fn run(&mut self, context: &Context<Message, ()>) -> WResult { fn run(&mut self, context: &Context<Message, ()>) -> WResult {
let server = UdpInput::<EnvData>::bind("127.0.0.1:25000", 24)?; let server = UdpReceiver::<EnvData>::bind("127.0.0.1:25000", 24)?;
// [`UdpInput`] is an iterator of incoming UDP packets which are automatically parsed // [`UdpInput`] is an iterator of incoming UDP packets which are automatically parsed
for data in server { for data in server {
match data { match data {
...@@ -52,7 +54,7 @@ struct UdpOut {} ...@@ -52,7 +54,7 @@ struct UdpOut {}
impl Worker<Message, ()> for UdpOut { impl Worker<Message, ()> for UdpOut {
fn run(&mut self, context: &Context<Message, ()>) -> WResult { fn run(&mut self, context: &Context<Message, ()>) -> WResult {
let mut client = UdpOutput::connect("localhost:25000")?; let mut client = UdpSender::connect("localhost:25000")?;
for _ in interval(Duration::from_secs(1)) { for _ in interval(Duration::from_secs(1)) {
let data = EnvData { let data = EnvData {
temp: 25.0, temp: 25.0,
......
...@@ -4,7 +4,9 @@ use binrw::{BinRead, BinWrite}; ...@@ -4,7 +4,9 @@ use binrw::{BinRead, BinWrite};
use crate::Result; use crate::Result;
pub mod modbus; pub mod modbus;
pub mod raw_udp; mod raw_udp;
pub use raw_udp::{UdpReceiver, UdpSender};
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub trait IoMapping { pub trait IoMapping {
......
...@@ -7,7 +7,8 @@ use std::{ ...@@ -7,7 +7,8 @@ use std::{
use crate::{Error, Result}; use crate::{Error, Result};
pub struct UdpInput<T> /// Raw UDP receiver
pub struct UdpReceiver<T>
where where
T: for<'a> BinRead<Args<'a> = ()>, T: for<'a> BinRead<Args<'a> = ()>,
{ {
...@@ -16,7 +17,7 @@ where ...@@ -16,7 +17,7 @@ where
_phantom: PhantomData<T>, _phantom: PhantomData<T>,
} }
impl<T> UdpInput<T> impl<T> UdpReceiver<T>
where where
T: for<'a> BinRead<Args<'a> = ()>, T: for<'a> BinRead<Args<'a> = ()>,
{ {
...@@ -30,7 +31,7 @@ where ...@@ -30,7 +31,7 @@ where
} }
} }
impl<T> Iterator for UdpInput<T> impl<T> Iterator for UdpReceiver<T>
where where
T: for<'a> BinRead<Args<'a> = ()>, T: for<'a> BinRead<Args<'a> = ()>,
{ {
...@@ -47,13 +48,23 @@ where ...@@ -47,13 +48,23 @@ where
} }
} }
pub struct UdpOutput { /// Raw UDP sender
pub struct UdpSender<T>
where
T: for<'a> BinWrite<Args<'a> = ()>,
{
socket: UdpSocket, socket: UdpSocket,
target: SocketAddr, target: SocketAddr,
data_buf: Vec<u8>, data_buf: Vec<u8>,
// keep the generic `T` global (including traits) as each instance is dedicated to send a
// specific type only
_phantom: PhantomData<T>,
} }
impl UdpOutput { impl<T> UdpSender<T>
where
T: for<'a> BinWrite<Args<'a> = ()>,
{
pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self> { pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self> {
let socket = UdpSocket::bind(("0.0.0.0", 0))?; let socket = UdpSocket::bind(("0.0.0.0", 0))?;
let target = addr let target = addr
...@@ -64,13 +75,11 @@ impl UdpOutput { ...@@ -64,13 +75,11 @@ impl UdpOutput {
socket, socket,
target, target,
data_buf: <_>::default(), data_buf: <_>::default(),
_phantom: PhantomData,
}) })
} }
pub fn send<T>(&mut self, value: T) -> Result<()> pub fn send(&mut self, value: T) -> Result<()> {
where
T: for<'a> BinWrite<Args<'a> = ()>,
{
let mut buf = Cursor::new(&mut self.data_buf); let mut buf = Cursor::new(&mut self.data_buf);
value.write_le(&mut buf)?; value.write_le(&mut buf)?;
self.socket.send_to(&self.data_buf, self.target)?; self.socket.send_to(&self.data_buf, self.target)?;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论