diff --git a/erpc_rust/.gitignore b/erpc_rust/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/erpc_rust/.gitignore @@ -0,0 +1 @@ +/target diff --git a/erpc_rust/Cargo.lock b/erpc_rust/Cargo.lock new file mode 100644 index 00000000..ad8e66da --- /dev/null +++ b/erpc_rust/Cargo.lock @@ -0,0 +1,32 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "erpc_rust" +version = "0.1.0" +dependencies = [ + "byteorder", + "crc", +] diff --git a/erpc_rust/Cargo.toml b/erpc_rust/Cargo.toml new file mode 100644 index 00000000..8ea752ac --- /dev/null +++ b/erpc_rust/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "erpc_rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +crc = "3.0.1" +byteorder = "1.5.0" diff --git a/erpc_rust/src/basic_codec.rs b/erpc_rust/src/basic_codec.rs new file mode 100644 index 00000000..55aaaa93 --- /dev/null +++ b/erpc_rust/src/basic_codec.rs @@ -0,0 +1,203 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +use crate::codec::{Codec, MsgInfo}; +use crate::message_type::MessageType; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::io::Cursor; +use std::io::{Read, Write}; + +#[derive(Debug, Clone)] +pub struct BasicCodec { + cursor: Cursor>, +} + +const BASIC_CODEC_VERSION: u32 = 1; + +impl BasicCodec { + pub fn new() -> Self { + Self { + cursor: Cursor::new(Vec::new()), + } + } +} + +impl Codec for BasicCodec { + fn buffer(&self) -> &[u8] { + self.cursor.get_ref() + } + + fn set_buffer(&mut self, buffer: Vec) { + self.cursor = Cursor::new(buffer); + } + + fn reset(&mut self) { + self.cursor = Cursor::new(Vec::new()); + } + + fn start_write_message(&mut self, msg_info: MsgInfo) { + let header = (BASIC_CODEC_VERSION << 24) + | ((msg_info.service as u32 & 0xff) << 16) + | ((msg_info.request as u32 & 0xff) << 8) + | (msg_info.msg_type as u32 & 0xff); + self.write_u32(header); + self.write_u32(msg_info.sequence); + } + + fn write_bool(&mut self, value: bool) { + self.write_u8(if value { 1 } else { 0 }); + } + + fn write_i8(&mut self, value: i8) { + self.cursor.write_i8(value).unwrap() + } + + fn write_i16(&mut self, value: i16) { + self.cursor.write_i16::(value).unwrap() + } + + fn write_i32(&mut self, value: i32) { + self.cursor.write_i32::(value).unwrap() + } + + fn write_i64(&mut self, value: i64) { + self.cursor.write_i64::(value).unwrap() + } + + fn write_u8(&mut self, value: u8) { + self.cursor.write_u8(value).unwrap() + } + + fn write_u16(&mut self, value: u16) { + self.cursor.write_u16::(value).unwrap() + } + + fn write_u32(&mut self, value: u32) { + self.cursor.write_u32::(value).unwrap() + } + + fn write_u64(&mut self, value: u64) { + self.cursor.write_u64::(value).unwrap() + } + + fn write_f32(&mut self, value: f32) { + self.cursor.write_f32::(value).unwrap() + } + + fn write_f64(&mut self, value: f64) { + self.cursor.write_f64::(value).unwrap() + } + + fn write_string(&mut self, value: &str) { + self.write_u32(value.len() as u32); + self.cursor.write_all(value.as_bytes()).unwrap(); + } + + fn write_binary(&mut self, value: &[u8]) { + self.write_u32(value.len() as u32); + self.cursor.write_all(value).unwrap(); + } + + fn start_write_list(&mut self, length: usize) { + self.write_u32(length as u32); + } + + fn start_write_union(&mut self, discriminator: u32) { + self.write_u32(discriminator); + } + + fn write_null_flag(&mut self, is_null: bool) { + self.write_u8(if is_null { 1 } else { 0 }); + } + + fn start_read_message(&mut self) -> Result { + let version = self.read_u32(); + if version >> 24 != BASIC_CODEC_VERSION { + return Err("Invalid version".to_string()); + } + let service = (version >> 16) & 0xff; + let request = (version >> 8) & 0xff; + let msg_type = version & 0xff; + let sequence = self.read_u32(); + Ok(MsgInfo { + service: service as u8, + request: request as u8, + msg_type: MessageType::from_u8(msg_type as u8), + sequence, + }) + } + + fn read_bool(&mut self) -> bool { + self.read_u8() != 0 + } + + fn read_i8(&mut self) -> i8 { + self.cursor.read_i8().unwrap() + } + + fn read_i16(&mut self) -> i16 { + self.cursor.read_i16::().unwrap() + } + + fn read_i32(&mut self) -> i32 { + self.cursor.read_i32::().unwrap() + } + + fn read_i64(&mut self) -> i64 { + self.cursor.read_i64::().unwrap() + } + + fn read_u8(&mut self) -> u8 { + self.cursor.read_u8().unwrap() + } + + fn read_u16(&mut self) -> u16 { + self.cursor.read_u16::().unwrap() + } + + fn read_u32(&mut self) -> u32 { + self.cursor.read_u32::().unwrap() + } + + fn read_u64(&mut self) -> u64 { + self.cursor.read_u64::().unwrap() + } + + fn read_f32(&mut self) -> f32 { + self.cursor.read_f32::().unwrap() + } + + fn read_f64(&mut self) -> f64 { + self.cursor.read_f64::().unwrap() + } + + fn read_string(&mut self) -> String { + let length = self.read_u32() as usize; + let mut buffer = vec![0; length]; + self.cursor.read_exact(&mut buffer).unwrap(); + String::from_utf8(buffer).unwrap() + } + + fn read_binary(&mut self) -> Vec { + let length = self.read_u32() as usize; + let mut buffer = vec![0; length]; + self.cursor.read_exact(&mut buffer).unwrap(); + buffer + } + + fn start_read_list(&mut self) -> usize { + self.read_u32() as usize + } + + fn start_read_union(&mut self) -> u32 { + self.read_u32() + } + + fn read_null_flag(&mut self) -> bool { + self.read_u8() != 0 + } +} diff --git a/erpc_rust/src/client.rs b/erpc_rust/src/client.rs new file mode 100644 index 00000000..7af45bd1 --- /dev/null +++ b/erpc_rust/src/client.rs @@ -0,0 +1,82 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +use crate::codec::{Codec, MsgInfo}; +use crate::transport::Transport; + +pub struct ClientManager { + pub transport: S, + pub codec: T, + sequence: u32, +} + +impl ClientManager { + pub fn new(transport: S, codec: T) -> Self { + Self { + transport, + codec, + sequence: 0, + } + } + + pub fn sequence(&mut self) -> u32 { + self.sequence += 1; + self.sequence + } + + pub fn create_request(&mut self, is_oneway: bool) -> RequestContext { + let sequence = self.sequence(); + let message = vec![]; + let codec = self.codec.clone(); + RequestContext::new(sequence, message, codec, is_oneway) + } + + pub fn perform_request(&mut self, request: &mut RequestContext) -> Result { + self.transport.send(request.codec.buffer())?; + let response = self.transport.recv()?; + request.codec.set_buffer(response); + request.codec.start_read_message() + } + + pub fn perform_oneway_request(&mut self, request: RequestContext) -> Result<(), String> { + self.transport.send(request.codec.buffer()) + } +} + +pub struct RequestContext { + pub sequence: u32, + pub message: Vec, + pub codec: T, + pub is_oneway: bool, +} + +impl<'a, T: Codec> RequestContext { + pub fn new(sequence: u32, message: Vec, codec: T, is_oneway: bool) -> Self { + Self { + sequence, + message, + codec, + is_oneway, + } + } + + pub fn sequence(&self) -> u32 { + self.sequence + } + + pub fn message(&self) -> &[u8] { + &self.message + } + + pub fn codec(&mut self) -> &mut T { + &mut self.codec + } + + pub fn is_oneway(&self) -> bool { + self.is_oneway + } +} diff --git a/erpc_rust/src/codec.rs b/erpc_rust/src/codec.rs new file mode 100644 index 00000000..537be262 --- /dev/null +++ b/erpc_rust/src/codec.rs @@ -0,0 +1,92 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +use crate::message_type::MessageType; + +#[derive(Debug, Clone)] +pub struct MsgInfo { + pub msg_type: MessageType, + pub service: u8, + pub request: u8, + pub sequence: u32, +} + +pub trait Codec { + fn buffer(&self) -> &[u8]; + + fn set_buffer(&mut self, buffer: Vec); + + fn reset(&mut self); + + fn start_write_message(&mut self, msg_info: MsgInfo); + + fn write_bool(&mut self, value: bool); + + fn write_i8(&mut self, value: i8); + + fn write_i16(&mut self, value: i16); + + fn write_i32(&mut self, value: i32); + + fn write_i64(&mut self, value: i64); + + fn write_u8(&mut self, value: u8); + + fn write_u16(&mut self, value: u16); + + fn write_u32(&mut self, value: u32); + + fn write_u64(&mut self, value: u64); + + fn write_f32(&mut self, value: f32); + + fn write_f64(&mut self, value: f64); + + fn write_string(&mut self, value: &str); + + fn write_binary(&mut self, value: &[u8]); + + fn start_write_list(&mut self, length: usize); + + fn start_write_union(&mut self, discriminator: u32); + + fn write_null_flag(&mut self, is_null: bool); + + fn start_read_message(&mut self) -> Result; + + fn read_bool(&mut self) -> bool; + + fn read_i8(&mut self) -> i8; + + fn read_i16(&mut self) -> i16; + + fn read_i32(&mut self) -> i32; + + fn read_i64(&mut self) -> i64; + + fn read_u8(&mut self) -> u8; + + fn read_u16(&mut self) -> u16; + + fn read_u32(&mut self) -> u32; + + fn read_u64(&mut self) -> u64; + + fn read_f32(&mut self) -> f32; + + fn read_f64(&mut self) -> f64; + + fn read_string(&mut self) -> String; + + fn read_binary(&mut self) -> Vec; + + fn start_read_list(&mut self) -> usize; + + fn start_read_union(&mut self) -> u32; + + fn read_null_flag(&mut self) -> bool; +} diff --git a/erpc_rust/src/lib.rs b/erpc_rust/src/lib.rs new file mode 100644 index 00000000..95593a34 --- /dev/null +++ b/erpc_rust/src/lib.rs @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +pub mod basic_codec; +pub mod client; +pub mod codec; +pub mod message_type; +pub mod server; +pub mod simple_server; +pub mod transport; + +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/erpc_rust/src/message_type.rs b/erpc_rust/src/message_type.rs new file mode 100644 index 00000000..80300d0e --- /dev/null +++ b/erpc_rust/src/message_type.rs @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum MessageType { + Invocation = 0, + Oneway = 1, + Reply = 2, + Notification = 3, +} + +impl MessageType { + pub fn from_u8(value: u8) -> MessageType { + match value { + 0 => MessageType::Invocation, + 1 => MessageType::Oneway, + 2 => MessageType::Reply, + 3 => MessageType::Notification, + _ => panic!("Invalid MessageType value: {}", value), + } + } +} diff --git a/erpc_rust/src/server.rs b/erpc_rust/src/server.rs new file mode 100644 index 00000000..913c4f7c --- /dev/null +++ b/erpc_rust/src/server.rs @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +use crate::codec::Codec; +use crate::transport::Transport; + +pub trait Service { + fn service_id(&self) -> u8; + + fn handle_invocation(&mut self, method_id: u8, sequence: u32, codec: &mut T); +} + +pub trait Server, R: Transport> { + fn transport(&mut self) -> &mut R; + + fn set_transport(&mut self, transport: R); + + fn services(&self) -> &[S]; + + fn add_service(&mut self, service: S); + + fn get_service_with_id(&mut self, service_id: u8) -> Option<&mut S>; + + fn process_request(&mut self) -> Result<(), String>; + + fn run(&mut self) -> Result<(), String>; + + fn stop(&mut self); +} diff --git a/erpc_rust/src/simple_server.rs b/erpc_rust/src/simple_server.rs new file mode 100644 index 00000000..0d77ecae --- /dev/null +++ b/erpc_rust/src/simple_server.rs @@ -0,0 +1,88 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +use crate::codec::{Codec}; +use crate::message_type::MessageType; +use crate::server::{Server, Service}; +use crate::transport::Transport; + +pub struct SimpleServer, R: Transport> { + transport: R, + codec: T, + services: Vec, + running: bool, +} + +impl, R: Transport> SimpleServer { + pub fn new(transport: R, codec: T) -> Self { + Self { + transport, + codec, + services: vec![], + running: true, + } + } + + fn receive_request(&mut self) -> Result<(), String> { + let msg = self.transport.recv()?; + self.codec.set_buffer(msg); + self.process_request()?; + + if !self.codec.buffer().is_empty() { + self.transport.send(self.codec.buffer())?; + } + Ok(()) + } +} + +impl, R: Transport> Server for SimpleServer { + fn transport(&mut self) -> &mut R { + &mut self.transport + } + + fn set_transport(&mut self, transport: R) { + self.transport = transport; + } + + fn services(&self) -> &[S]{ + &self.services + } + + fn add_service(&mut self, service: S) { + self.services.push(service); + } + + fn get_service_with_id(&mut self, service_id: u8) -> Option<&mut S> { + self.services.iter_mut().find(|service| service.service_id() == service_id) + } + + fn process_request(&mut self) -> Result<(), String> { + let mut codec = self.codec.clone(); + let info = codec.start_read_message()?; + if info.msg_type != MessageType::Invocation && info.msg_type != MessageType::Oneway { + return Err("Invalid message type".to_string()); + } + let service = self.get_service_with_id(info.service).ok_or("Service not found")?; + service.handle_invocation(info.request, info.sequence, &mut codec); + if info.msg_type == MessageType::Oneway { + self.codec.reset(); + } + self.codec.set_buffer(codec.buffer().to_vec()); + Ok(()) + } + + fn run(&mut self) -> Result<(), String> { + while self.running { + self.receive_request()?; + } + Ok(()) + } + + fn stop(&mut self) { + self.running = false; + } +} \ No newline at end of file diff --git a/erpc_rust/src/transport.rs b/erpc_rust/src/transport.rs new file mode 100644 index 00000000..eade3502 --- /dev/null +++ b/erpc_rust/src/transport.rs @@ -0,0 +1,112 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +use std::io::{Read, Write}; +use std::net::{TcpListener, TcpStream}; +use crc::{Algorithm, Crc}; + +pub trait Transport { + fn send(&mut self, msg: &[u8]) -> Result<(), String>; + fn recv(&mut self) -> Result, String>; +} + +const ALTERED_KERMIT : Algorithm = Algorithm {width: 16, poly: 0x1021, init: 0xEF4A, xorout: 0x0000, refin: true, refout: false, check: 35244, residue: 0x0000}; + +pub struct TCPTransport { + pub listener: Option, + pub socket: Option, + crc: Crc, + is_server: bool, +} + +impl TCPTransport { + pub fn new(host: &str, port: u16, is_server: bool) -> Self { + let server_socket = if is_server { + let listener = TcpListener::bind(format!("{}:{}", host, port)).unwrap(); + Some(listener) + } else { + None + }; + + let client_socket = if !is_server { + let stream = TcpStream::connect(format!("{}:{}", host, port)).unwrap(); + Some(stream) + } else { + None + }; + + TCPTransport { + listener: server_socket, + socket: client_socket, + crc: Crc::::new(&ALTERED_KERMIT), + is_server, + } + } + + pub fn accept_connection(&mut self) -> Result<(), String> { + if let Some(listener) = &self.listener { + let (socket, _addr) = listener.accept().map_err(|e| e.to_string())?; + println!("Connection accepted"); + self.socket = Some(socket); + } + Ok(()) + } + + pub fn close(&mut self) { + if let Some(client_socket) = &self.socket { + let _ = client_socket.shutdown(std::net::Shutdown::Both); + } + self.socket = None; + } + + fn base_send(&mut self, msg: &[u8]) -> Result<(), String> { + if let Some(socket) = &mut self.socket { + println!("IsServer - {}: writing {} bytes", self.is_server, msg.len()); + socket.write_all(msg).map_err(|e| e.to_string())?; + } + Ok(()) + } + + fn base_recv(&mut self) -> Result, String> { + if self.is_server && self.socket.is_none() { + self.accept_connection()?; + } + if let Some(socket) = &mut self.socket { + let mut len_buf:[u8; 4] = [0; 4]; + socket.read_exact(&mut len_buf).map_err(|e| e.to_string())?; + let len = u32::from_be_bytes(len_buf) as usize; + let mut crc_buff:[u8; 2] = [0; 2]; + socket.read_exact(&mut crc_buff).map_err(|e| e.to_string())?; + let crc = u16::from_be_bytes(crc_buff); + let mut data_buffer: Vec = vec![0u8; len]; + socket.read_exact(&mut data_buffer).map_err(|e| e.to_string())?; + + if crc != self.crc.checksum(&data_buffer) { + return Err("CRC mismatch".to_string()); + } + return Ok(data_buffer) + } + Ok(vec![]) + } +} + +impl Transport for TCPTransport { + fn send(&mut self, msg: &[u8]) -> Result<(), String> { + let crc = self.crc.checksum(msg); + let mut buffer = vec![]; + buffer.extend_from_slice(&(msg.len() as u32).to_be_bytes()); + buffer.extend_from_slice(&crc.to_be_bytes()); + buffer.extend_from_slice(msg); + self.base_send(&buffer) + } + + fn recv(&mut self) -> Result, String> { + let buffer = self.base_recv()?; + let msg = buffer; + Ok(msg.to_vec()) + } +} \ No newline at end of file diff --git a/examples/rust_matrix_multiply/Cargo.lock b/examples/rust_matrix_multiply/Cargo.lock new file mode 100644 index 00000000..f6893303 --- /dev/null +++ b/examples/rust_matrix_multiply/Cargo.lock @@ -0,0 +1,267 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "erpc_rust" +version = "0.1.0" +dependencies = [ + "byteorder", + "crc", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "proc-macro2" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rust_matrix_multiply" +version = "0.1.0" +dependencies = [ + "clap", + "erpc_rust", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/examples/rust_matrix_multiply/Cargo.toml b/examples/rust_matrix_multiply/Cargo.toml new file mode 100644 index 00000000..07080ca9 --- /dev/null +++ b/examples/rust_matrix_multiply/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust_matrix_multiply" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +erpc_rust = { path = "../erpc_rust"} +clap = { version = "4.5.4", features = ["derive"] } \ No newline at end of file diff --git a/examples/rust_matrix_multiply/README.md b/examples/rust_matrix_multiply/README.md new file mode 100644 index 00000000..23296b9e --- /dev/null +++ b/examples/rust_matrix_multiply/README.md @@ -0,0 +1,32 @@ +# Rust matrix multiply + +A short example of the matrix multiplication using the eRPC library in Rust. + +## Prerequisites + +- [Rust](https://www.rust-lang.org/tools/install) +- [Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) (Comes with Rust) + +## Building the Project + +1. Make sure the `erpc_rust` library location `../erpc_rust"`, relative to the Cargo.toml file. + +2. Build the project: + + ``` + cargo build + ``` + +## Running the Project + +1. After building the project, you can run the server with: + + ``` + cargo run -- --server + ``` + +2. You can also run the client with: + + ``` + cargo run -- --client + ``` \ No newline at end of file diff --git a/examples/rust_matrix_multiply/src/main.rs b/examples/rust_matrix_multiply/src/main.rs new file mode 100644 index 00000000..1b3202a2 --- /dev/null +++ b/examples/rust_matrix_multiply/src/main.rs @@ -0,0 +1,149 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +use crate::service::erpc_matrix_multiply::interface::MatrixMultiplyService; +use crate::service::erpc_matrix_multiply::server::MatrixMultiplyServiceService; +use clap::Parser; +use erpc_rust::basic_codec::BasicCodec; +use erpc_rust::client::ClientManager; +use erpc_rust::server::Server; +use erpc_rust::simple_server::SimpleServer; +use erpc_rust::transport::TCPTransport; +use std::io; +use std::io::Read; +use std::process::exit; + +mod service; + +const MAX_VALUE: u32 = 50; + +fn fill_matrix(size: usize, max_value: u32) -> [[u32; 5]; 5] { + let mut matrix = [[u32::default(); 5]; 5]; + for i in 0..size { + for j in 0..size { + matrix[i][j] = (i * j) as u32 % max_value; + } + } + matrix +} + +fn print_matrix(matrix: &[[u32; 5]; 5]) { + for row in matrix { + for cell in row { + print!("{:0>4} ", cell); + } + println!(); + } +} + +#[derive(Default)] +pub struct MatrixMultiplyServiceHandler {} + +impl MatrixMultiplyService for MatrixMultiplyServiceHandler { + fn matrix_multiply( + &mut self, + matrix1: &[[u32; 5]; 5], + matrix2: &[[u32; 5]; 5], + result_matrix: &mut [[u32; 5]; 5], + ) { + println!("Matrix 1:"); + print_matrix(matrix1); + println!("Matrix 2:"); + print_matrix(matrix2); + + for i in 0..matrix1.len() { + for j in 0..matrix2[0].len() { + result_matrix[i][j] = 0; + for k in 0..matrix1[0].len() { + result_matrix[i][j] += matrix1[i][k] * matrix2[k][j]; + } + } + } + + println!("Result matrix:"); + print_matrix(result_matrix); + } +} + +fn run_server(transport: TCPTransport) { + let matrix_multiply_service = MatrixMultiplyServiceHandler::default(); + let matrix_multiply_service_service = + MatrixMultiplyServiceService::new(matrix_multiply_service); + let mut server = SimpleServer::new(transport, BasicCodec::new()); + server.add_service(matrix_multiply_service_service); + println!("Server is running"); + server + .run() + .expect("An error occurred while running the server"); +} + +fn run_client(transport: TCPTransport) { + let client_manager = ClientManager::new(transport, BasicCodec::new()); + let mut matrix_multiply_client = + service::erpc_matrix_multiply::client::MatrixMultiplyClient::new(client_manager); + loop { + let matrix1 = fill_matrix(5, MAX_VALUE); + let matrix2 = fill_matrix(5, MAX_VALUE); + + println!("Matrix 1:"); + print_matrix(&matrix1); + + println!("Matrix 2:"); + print_matrix(&matrix2); + + let mut result_matrix = [[u32::default(); 5]; 5]; + matrix_multiply_client.matrix_multiply(&matrix1, &matrix2, &mut result_matrix); + + println!("Result matrix:"); + print_matrix(&result_matrix); + let mut buffer = [0; 1]; + io::stdin().read_exact(&mut buffer).unwrap(); + } +} + +#[derive(Parser, Debug)] +#[clap(name = "eRPC Matrix Multiply example")] +pub struct Opts { + #[clap(short = 'c', long = "client", help = "Run client")] + client: bool, + + #[clap(short = 's', long = "server", help = "Run server")] + server: bool, + + #[clap( + short = 't', + long = "host", + default_value = "localhost", + help = "Host IP address (default value is localhost)" + )] + host: String, + + #[clap( + short = 'p', + long = "port", + default_value = "40", + help = "Port (default value is 40)" + )] + port: u16, +} + +fn main() { + let args = Opts::parse(); + + if !args.client && !args.server { + println!("Please specify either client or server mode"); + exit(1); + } + + let transport = TCPTransport::new(&args.host, args.port, args.server); + + if args.server { + run_server(transport); + } else { + run_client(transport); + } +} diff --git a/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/client.rs b/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/client.rs new file mode 100644 index 00000000..2521d349 --- /dev/null +++ b/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/client.rs @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +use crate::service::erpc_matrix_multiply::interface::{ + MatrixMultiplyService, MATRIX_MULTIPLY_SERVICE_ID, MATRIX_MULTIPLY_SERVICE_MATRIX_MULTIPLY_ID, +}; +use erpc_rust::client::ClientManager; +use erpc_rust::codec::{Codec, MsgInfo}; +use erpc_rust::message_type::MessageType; +use erpc_rust::transport::Transport; + +pub struct MatrixMultiplyClient { + client_manager: ClientManager, +} + +impl MatrixMultiplyService for MatrixMultiplyClient { + fn matrix_multiply( + &mut self, + matrix1: &[[u32; 5]; 5], + matrix2: &[[u32; 5]; 5], + result_matrix: &mut [[u32; 5]; 5], + ) { + let mut request = self.client_manager.create_request(false); + let sequence = request.sequence(); + + request.codec.start_write_message(MsgInfo { + msg_type: MessageType::Invocation, + service: MATRIX_MULTIPLY_SERVICE_ID, + request: MATRIX_MULTIPLY_SERVICE_MATRIX_MULTIPLY_ID, + sequence, + }); + + for _i0 in matrix1 { + for _i1 in _i0 { + request.codec.write_u32(*_i1); + } + } + for _i0 in matrix2 { + for _i1 in _i0 { + request.codec.write_u32(*_i1); + } + } + + self.client_manager.perform_request(&mut request).unwrap(); + + for _i0 in 0..5 { + for _i1 in 0..5 { + result_matrix[_i0][_i1] = request.codec.read_u32(); + } + } + } +} + +impl MatrixMultiplyClient { + pub fn new(client_manager: ClientManager) -> Self { + Self { client_manager } + } +} diff --git a/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/common.rs b/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/common.rs new file mode 100644 index 00000000..ac77a17e --- /dev/null +++ b/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/common.rs @@ -0,0 +1,8 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +const matrix_size: u32 = 5; diff --git a/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/interface.rs b/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/interface.rs new file mode 100644 index 00000000..8a7d9c62 --- /dev/null +++ b/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/interface.rs @@ -0,0 +1,15 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +pub trait MatrixMultiplyService { + fn matrix_multiply(&mut self, matrix1: &[[u32; 5]; 5], matrix2: &[[u32; 5]; 5], result_matrix: &mut [[u32; 5]; 5]); +} + +pub const MATRIX_MULTIPLY_SERVICE_ID: u8 = 1; + +pub const MATRIX_MULTIPLY_SERVICE_MATRIX_MULTIPLY_ID: u8 = 1; + diff --git a/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/mod.rs b/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/mod.rs new file mode 100644 index 00000000..e6869154 --- /dev/null +++ b/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/mod.rs @@ -0,0 +1,11 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +pub mod client; +pub mod common; +pub mod server; +pub mod interface; \ No newline at end of file diff --git a/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/server.rs b/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/server.rs new file mode 100644 index 00000000..85dced8f --- /dev/null +++ b/examples/rust_matrix_multiply/src/service/erpc_matrix_multiply/server.rs @@ -0,0 +1,85 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +use crate::service::erpc_matrix_multiply::interface::{ + MatrixMultiplyService, MATRIX_MULTIPLY_SERVICE_ID, MATRIX_MULTIPLY_SERVICE_MATRIX_MULTIPLY_ID, +}; +use erpc_rust::codec::{Codec, MsgInfo}; +use erpc_rust::message_type::MessageType; +use erpc_rust::server::Service; +use std::collections::HashMap; + +type HandlerFunction = fn(&mut T, &mut S, u32) -> Result<(), String>; + +pub struct MatrixMultiplyServiceService { + handler: T, + handlers: HashMap>, +} + +impl MatrixMultiplyServiceService { + pub fn new(handler: T) -> Self { + let mut handlers = HashMap::new(); + handlers.insert( + MATRIX_MULTIPLY_SERVICE_MATRIX_MULTIPLY_ID, + MatrixMultiplyServiceService::::matrix_multiply_handler as HandlerFunction, + ); + Self { handler, handlers } + } +} + +impl Service for MatrixMultiplyServiceService { + fn service_id(&self) -> u8 { + MATRIX_MULTIPLY_SERVICE_ID + } + + fn handle_invocation(&mut self, method_id: u8, sequence: u32, codec: &mut S) { + let handler = self.handlers.get(&method_id).unwrap(); + handler(&mut self.handler, codec, sequence).unwrap(); + } +} + +impl MatrixMultiplyServiceService { + fn matrix_multiply_handler( + handler: &mut T, + codec: &mut S, + sequence: u32, + ) -> Result<(), String> { + let mut matrix1 = [[u32::default(); 5]; 5]; + let mut matrix2 = [[u32::default(); 5]; 5]; + let mut result_matrix = [[u32::default(); 5]; 5]; + + for i0 in 0..5 { + for i1 in 0..5 { + matrix1[i0][i1] = codec.read_u32(); + } + } + for i0 in 0..5 { + for i1 in 0..5 { + matrix2[i0][i1] = codec.read_u32(); + } + } + + handler.matrix_multiply(&matrix1, &matrix2, &mut result_matrix); + + codec.reset(); + + codec.start_write_message(MsgInfo { + msg_type: MessageType::Reply, + service: MATRIX_MULTIPLY_SERVICE_ID, + request: MATRIX_MULTIPLY_SERVICE_MATRIX_MULTIPLY_ID, + sequence, + }); + + for i0 in 0..5 { + for i1 in 0..5 { + codec.write_u32(result_matrix[i0][i1]); + } + } + + Ok(()) + } +} diff --git a/examples/rust_matrix_multiply/src/service/mod.rs b/examples/rust_matrix_multiply/src/service/mod.rs new file mode 100644 index 00000000..ec72cf16 --- /dev/null +++ b/examples/rust_matrix_multiply/src/service/mod.rs @@ -0,0 +1,8 @@ +/* + * Copyright 2024 Marek Mišík(nxf76107) + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +pub mod erpc_matrix_multiply; \ No newline at end of file