From 5f4c64fe3e7356e7c8b2ef78577e4cede0808ab9 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Mon, 26 Feb 2024 15:55:42 +0100 Subject: [PATCH 01/41] refactor(read_device_info_handler): change return type. --- rodbus/src/server/handler.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rodbus/src/server/handler.rs b/rodbus/src/server/handler.rs index 79f84048..adc8e9fd 100644 --- a/rodbus/src/server/handler.rs +++ b/rodbus/src/server/handler.rs @@ -56,7 +56,7 @@ pub trait RequestHandler: Send + 'static { _mei_code: MeiCode, _read_dev_id: ReadDeviceCode, _object_id: Option, - ) -> Result { + ) -> Result { Err(ExceptionCode::IllegalFunction) } From 9bf03e8f9787e9e977ba23c4aba942307d2b806a Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Mon, 26 Feb 2024 15:56:27 +0100 Subject: [PATCH 02/41] refactor(get_reply): store the data returned by the handler, add todo!() --- rodbus/src/server/request.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rodbus/src/server/request.rs b/rodbus/src/server/request.rs index 040d4ef3..156bc337 100644 --- a/rodbus/src/server/request.rs +++ b/rodbus/src/server/request.rs @@ -139,7 +139,8 @@ impl<'a> Request<'a> { // // And then write them AFTER writing the info objects let device_information = DeviceIdentificationResponse::new(|| { - handler.read_device_info(read.mei_code, read.dev_id, read.obj_id) + let object_data = handler.read_device_info(read.mei_code, read.dev_id, read.obj_id); + todo!() }); writer.format_reply(header, function, &device_information, level) } From 2324bde389dc9943e969cc2af9f4c533e9e6a73a Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 13:47:02 +0100 Subject: [PATCH 03/41] refactor(response): add option arg to callback, change return type. --- rodbus/src/server/response.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rodbus/src/server/response.rs b/rodbus/src/server/response.rs index 92b55373..e7203b95 100644 --- a/rodbus/src/server/response.rs +++ b/rodbus/src/server/response.rs @@ -1,6 +1,7 @@ use crate::exception::ExceptionCode; use crate::types::{ReadBitsRange, ReadRegistersRange}; use crate::DeviceInfo; +use crate::server::ServerDeviceInfo; pub(crate) struct BitWriter where @@ -37,16 +38,16 @@ where } #[derive(Debug, PartialEq)] -pub(crate) struct DeviceIdentificationResponse +pub(crate) struct DeviceIdentificationResponse<'a, T> where - T: Fn() -> Result, + T: Fn(Option) -> Result, ExceptionCode>, { pub(crate) getter: T, } -impl DeviceIdentificationResponse +impl<'a, T> DeviceIdentificationResponse<'a, T> where - T: Fn() -> Result, + T: Fn(Option) -> Result, ExceptionCode>, { pub(crate) fn new(getter: T) -> Self { Self { getter } From 232d8e28af33e9a28114fcdc9aed5b210888954f Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 13:47:57 +0100 Subject: [PATCH 04/41] refactor(ServerDeviceInfo): add derived traits to struct. --- rodbus/src/server/handler.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rodbus/src/server/handler.rs b/rodbus/src/server/handler.rs index adc8e9fd..b09e0b96 100644 --- a/rodbus/src/server/handler.rs +++ b/rodbus/src/server/handler.rs @@ -6,6 +6,7 @@ use crate::server::{WriteCoils, WriteRegisters}; use crate::types::*; /// Type that the server will return in response to a read_device_info +#[derive(Debug, PartialEq)] pub struct ServerDeviceInfo<'a> { /// Conformity level the the server is willing to grant pub conformity_level: DeviceConformityLevel, From a475ec94ea2989392f140a47d2d83e88a07715b1 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 13:48:31 +0100 Subject: [PATCH 05/41] refactor(response_message_count): comment out old code for now --- rodbus/src/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rodbus/src/types.rs b/rodbus/src/types.rs index 28566a89..b1f8bb84 100644 --- a/rodbus/src/types.rs +++ b/rodbus/src/types.rs @@ -300,7 +300,7 @@ impl DeviceInfo { self } - pub(crate) fn response_message_count(&self, max_msg_size: u8) -> Option { + /*pub(crate) fn response_message_count(&self, max_msg_size: u8) -> Option { const ADDITIONAL_BYTES: u8 = 0x02; //Two bytes get consumed by the object id and the length of the object itself. let mut max_length = max_msg_size; @@ -316,7 +316,7 @@ impl DeviceInfo { } None - } + }*/ ///Convert all Raw Modbus objects into ModbusObjects pub fn finalize_and_retrieve_objects(&self) -> Vec { From 38b8a8f7027af801d0af1837e0e6b14c4453191d Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 13:50:36 +0100 Subject: [PATCH 06/41] refactor(integration_tests): change response of integration tests. --- rodbus/tests/integration_test_read_device.rs | 53 ++++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/rodbus/tests/integration_test_read_device.rs b/rodbus/tests/integration_test_read_device.rs index 4a7d04d7..11310599 100644 --- a/rodbus/tests/integration_test_read_device.rs +++ b/rodbus/tests/integration_test_read_device.rs @@ -1,4 +1,5 @@ use std::net::SocketAddr; +use std::ptr::read; use std::str::FromStr; use std::time::Duration; @@ -7,6 +8,7 @@ use rodbus::server::*; use rodbus::*; use tokio::runtime::Runtime; +use rodbus::DeviceConformityLevel::ExtendedIdentificationIndividual; struct Handler { pub device_conformity_level: DeviceConformityLevel, @@ -78,7 +80,15 @@ impl Handler { mei_code: MeiCode, read_dev_id: ReadDeviceCode, object_id: u8, - ) -> Result { + ) -> Result { + + + let (min_range, max_range) = match read_dev_id { + ReadDeviceCode::BasicStreaming => (0x00, 0x03), + ReadDeviceCode::RegularStreaming => (0x04, 0x06), + ReadDeviceCode::ExtendedStreaming => (0x07, 0x7F), + ReadDeviceCode::Specific => (0x80, 0xFF), + }; let data = match read_dev_id { ReadDeviceCode::BasicStreaming => self.read_basic_device_info()?, ReadDeviceCode::RegularStreaming => self.read_regular_device_info()?, @@ -86,30 +96,35 @@ impl Handler { _ => unreachable!(), }; - let mut modbus_response: Vec = vec![]; - + /*let mut modbus_response: Vec = vec![]; for (idx, info_object) in data.iter().skip(object_id as usize).enumerate() { let modbus_object = match info_object { - Some(value) => RawModbusInfoObject::new( + Some(value) => value.as_bytes(), /*RawModbusInfoObject::new( read_dev_id, object_id + idx as u8, value.len() as u8, value.as_bytes(), - ), + ),*/ None => continue, }; - modbus_response.push(modbus_object); - } + modbus_response.extend_from_slice(modbus_object); + }*/ let length = Handler::message_count_from_area_slice(data) as u8; - let mut device_info_response = - DeviceInfo::new(mei_code, read_dev_id, self.device_conformity_level, length); + //let mut device_info_response = + // DeviceInfo::new(mei_code, read_dev_id, self.device_conformity_level, length); - device_info_response.storage = modbus_response; + let mut server = ServerDeviceInfo { + conformity_level: ExtendedIdentificationIndividual, + //TODO(Kay): This is not checking it's boundaries ! It could easily read data that is not part of basic streaming... + next_object_id: if data.get(object_id as usize + 1).is_some() && object_id >= min_range && object_id <= max_range { Some(object_id + 1) } else { None }, + //TODO(Kay): Remove the unwrap ? + object_data: data[object_id as usize].unwrap().as_bytes(), + }; - Ok(device_info_response) + Ok(server) } fn read_device_info_individual( @@ -117,8 +132,13 @@ impl Handler { mei_code: MeiCode, read_dev_id: ReadDeviceCode, object_id: u8, - ) -> Result { - let data = self.read_specific_device_info(object_id)?; + ) -> Result { + let server = ServerDeviceInfo { + conformity_level: ExtendedIdentificationIndividual, + next_object_id: None, + object_data: &[0x00,0x04,0x41,0x41,0x41,0x41], + }; + /*let data = self.read_specific_device_info(object_id)?; let string = RawModbusInfoObject::new( read_dev_id, object_id, @@ -128,9 +148,9 @@ impl Handler { let mut device_info = DeviceInfo::new(mei_code, read_dev_id, self.device_conformity_level, 1); - device_info.storage.push(string); + device_info.storage.push(string);*/ - Ok(device_info) + Ok(server) } } @@ -140,7 +160,7 @@ impl RequestHandler for Handler { mei_code: MeiCode, read_dev_id: ReadDeviceCode, object_id: Option, - ) -> Result { + ) -> Result { match (read_dev_id, object_id) { (ReadDeviceCode::BasicStreaming, None) => { self.read_device_info_streaming(mei_code, read_dev_id, 0) @@ -204,6 +224,7 @@ async fn test_read_device_info_request_response() { ) .await .unwrap(); + assert_eq!( result, DeviceInfo { From cbfb469defa9980615e9c0081ea5e3e38dc9cf7d Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 13:51:42 +0100 Subject: [PATCH 07/41] refactor(get_reply): do some calculations before passing the index on --- rodbus/src/server/request.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/rodbus/src/server/request.rs b/rodbus/src/server/request.rs index 156bc337..92165c54 100644 --- a/rodbus/src/server/request.rs +++ b/rodbus/src/server/request.rs @@ -133,15 +133,24 @@ impl<'a> Request<'a> { // Note: This will require some changes to the FrameWriter =( // // You'll have to save the locations to the following fields: + // You'll have to save the locations to the following fields: // - More Follows // - Next Object Id // - Number of Objects // // And then write them AFTER writing the info objects - let device_information = DeviceIdentificationResponse::new(|| { - let object_data = handler.read_device_info(read.mei_code, read.dev_id, read.obj_id); - todo!() + + //TODO(Kay): Remove the unwrap this is just for learning purposes ! + let device_information = DeviceIdentificationResponse::new(|object_id| { + let next_id = match (read.obj_id, object_id) { + (None, None) => Some(0), + (None, Some(x)) => Some(x), + (Some(x), None) => Some(x), + (Some(x), Some(y)) => Some(x + y), + }; + handler.read_device_info(read.mei_code, read.dev_id, next_id) }); + writer.format_reply(header, function, &device_information, level) } Request::WriteSingleCoil(request) => { From fedc5aad6f373f5bbc4fc27c7120bd45f4a3415f Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 13:52:45 +0100 Subject: [PATCH 08/41] refactor(server): testing how to pass slices from functions... --- rodbus/examples/server.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/rodbus/examples/server.rs b/rodbus/examples/server.rs index 963f51f4..01e90cff 100644 --- a/rodbus/examples/server.rs +++ b/rodbus/examples/server.rs @@ -138,8 +138,13 @@ impl RequestHandler for SimpleHandler { mei_code: MeiCode, read_dev_id: ReadDeviceCode, object_id: Option, - ) -> Result { - let mut device_info = DeviceInfo::new( + ) -> Result { + let server = ServerDeviceInfo { + conformity_level: ExtendedIdentificationIndividual, + next_object_id: None, + object_data: &[0x00,0x04,0x41,0x41,0x41,0x41], + }; + /*let mut device_info = DeviceInfo::new( mei_code, read_dev_id, DeviceConformityLevel::ExtendedIdentificationIndividual, @@ -170,7 +175,7 @@ impl RequestHandler for SimpleHandler { message.as_bytes(), )]; - return Ok(device_info); + return Ok(server); } else { device_info.number_objects = response_data.len() as u8; device_info.storage = vec![]; @@ -184,9 +189,9 @@ impl RequestHandler for SimpleHandler { ); device_info.storage.push(obj); } - } + }*/ - Ok(device_info) + Ok(server) } fn wrap(self) -> std::sync::Arc>> From 6d92494bc0f8d9e9046a3c04fa1e1cf418bbf952 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 13:54:13 +0100 Subject: [PATCH 09/41] refactor(trait serialize): change the serialization of read device info --- rodbus/src/common/serialize.rs | 87 ++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 19 deletions(-) diff --git a/rodbus/src/common/serialize.rs b/rodbus/src/common/serialize.rs index 66dd4a82..c0701d78 100644 --- a/rodbus/src/common/serialize.rs +++ b/rodbus/src/common/serialize.rs @@ -17,6 +17,7 @@ use crate::DeviceInfo; use crate::ReadDeviceRequest; use scursor::{ReadCursor, WriteCursor}; +use crate::server::ServerDeviceInfo; pub(crate) fn calc_bytes_for_bits(num_bits: usize) -> Result { let div_8 = num_bits / 8; @@ -310,44 +311,92 @@ impl Serialize for ReadDeviceRequest { } } -impl Serialize for DeviceIdentificationResponse +impl<'a, T> Serialize for DeviceIdentificationResponse<'a, T> where - T: Fn() -> Result, + T: Fn(Option) -> Result, crate::exception::ExceptionCode>, { fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { - let device_data: DeviceInfo = (self.getter)()?; + let mut device_data: ServerDeviceInfo = (self.getter)(None)?; - cursor.write_u8(device_data.mei_code as u8)?; - cursor.write_u8(device_data.read_device_id as u8)?; + //TODO(Kay): We need to rollback things a bit so these values are standin values for now ! + const MEI_CODE: u8 = 0x0E; + cursor.write_u8(MEI_CODE)?; + //TODO(Kay): We need to rollback things a bit so these values are standin values for now ! + cursor.write_u8(0x03); + + //cursor.write_u8(device_data.read_device_id as u8)?; cursor.write_u8(device_data.conformity_level as u8)?; + + //let max = device_data.response_message_count(MAX_ADU_LENGTH as u8 - SAFETY_MARGIN); + + //max.serialize(cursor)?; + + //let range: Range = Range { + // start: device_data.next_object_id.unwrap_or_default().into(), + // end: max.unwrap_or(device_data.object_data.len() as u8).into(), + //}; + + //TODO(Kay): We need to write out the right amount of objects we don't have that value + // currently but for now it's probably better to just write a zero value here + // but don't forget that it's there !!! + + //TODO(Kay): These fields need to be written after we know how much of the actual objects + // we have written out ! + cursor.write_u8(0x00); //MORE FOLLOWS INDICATOR + cursor.write_u8(0x00); //MORE FOLLOWS VALUE + cursor.write_u8(0)?; //OBJECT COUNT + + const SAFETY_MARGIN: u8 = 7; - let max = device_data.response_message_count(MAX_ADU_LENGTH as u8 - SAFETY_MARGIN); - max.serialize(cursor)?; + let mut position = 0; + let mut id = 0; //Start with the id at the position our read starts ! + while position < (MAX_ADU_LENGTH as u8 - SAFETY_MARGIN) { - let range: Range = Range { - start: device_data.continue_at.unwrap_or_default().into(), - end: max.unwrap_or(device_data.storage.len() as u8).into(), - }; + if device_data.object_data.len() >= ((MAX_ADU_LENGTH as u8 - SAFETY_MARGIN)).into() { + //TODO(Kay): We need to store that id and make the next read at that address ! + break; + } + cursor.write_u8(id)?; //ID + cursor.write_u8(device_data.object_data.len() as u8)?; + cursor.write_bytes(device_data.object_data)?; - cursor.write_u8(device_data.number_objects)?; + id +=1; + position += device_data.object_data.len() as u8; - for message in device_data.storage[range].iter() { - cursor.write_u8(message.index)?; + if device_data.next_object_id.is_none() { + break; + } - let data = message.get_data(); - cursor.write_u8(data.len() as u8)?; - cursor.write_bytes(data)?; + device_data = (self.getter)(device_data.next_object_id)?; } + /*for object in device_data.object_data { + let id = device_data.object_data[position]; + + cursor.write_u8(device_data.object_data.len() as u8)?; + cursor.write_bytes(device_data.object_data)?; + + }*/ + + + //for message in device_data.object_data[range].iter() { + //let [id, length, data @ ..] = message; + //cursor.write_u8(message.index)?; + + //let data = message.get_data(); + //cursor.write_u8(data.len() as u8)?; + //cursor.write_bytes(data)?; + //} + Ok(()) } } -impl Loggable for DeviceIdentificationResponse +impl<'a, T> Loggable for DeviceIdentificationResponse<'a, T> where - T: Fn() -> Result, + T: Fn(Option) -> Result, crate::exception::ExceptionCode>, { fn log( &self, From babd8beaf0ecd494fe93ffd56016f04c7c75e500 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 14:01:04 +0100 Subject: [PATCH 10/41] refactor(server): remove import and use the direct path of the enum. --- rodbus/examples/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rodbus/examples/server.rs b/rodbus/examples/server.rs index 01e90cff..a744b664 100644 --- a/rodbus/examples/server.rs +++ b/rodbus/examples/server.rs @@ -140,7 +140,7 @@ impl RequestHandler for SimpleHandler { object_id: Option, ) -> Result { let server = ServerDeviceInfo { - conformity_level: ExtendedIdentificationIndividual, + conformity_level: DeviceConformityLevel::ExtendedIdentificationIndividual, next_object_id: None, object_data: &[0x00,0x04,0x41,0x41,0x41,0x41], }; From 6f4e62debe2393198d6818d6882eda959b9d2cfd Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 14:01:31 +0100 Subject: [PATCH 11/41] chore(read device identification): rustfmt --- rodbus/src/client/requests/read_device_identification.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rodbus/src/client/requests/read_device_identification.rs b/rodbus/src/client/requests/read_device_identification.rs index baecf287..48c72d5c 100644 --- a/rodbus/src/client/requests/read_device_identification.rs +++ b/rodbus/src/client/requests/read_device_identification.rs @@ -2,8 +2,8 @@ use scursor::{ReadCursor, WriteCursor}; use crate::{ common::{function::FunctionCode, traits::Serialize}, - AppDecodeLevel, DeviceInfo, RawModbusInfoObject, ReadDeviceCode, ReadDeviceRequest, - RequestError, + AppDecodeLevel, DeviceInfo, RawModbusInfoObject, ReadDeviceCode, + ReadDeviceRequest, RequestError, }; pub(crate) struct ReadDevice { From 274399f80e30b71ba9b6fcb0788d5230ab9b6da8 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 15:11:21 +0100 Subject: [PATCH 12/41] refactor(frame): add FrameRecords struct and change serialize trait. --- rodbus/src/client/message.rs | 3 +- rodbus/src/common/frame.rs | 43 ++++++++++++++++++++++ rodbus/src/common/serialize.rs | 65 +++++++++++++++++++++++----------- rodbus/src/serial/frame.rs | 11 +++--- rodbus/src/tcp/frame.rs | 10 ++++-- 5 files changed, 104 insertions(+), 28 deletions(-) diff --git a/rodbus/src/client/message.rs b/rodbus/src/client/message.rs index 2858a995..626bb3ff 100644 --- a/rodbus/src/client/message.rs +++ b/rodbus/src/client/message.rs @@ -16,6 +16,7 @@ use crate::types::{Indexed, UnitId}; use scursor::{ReadCursor, WriteCursor}; use std::time::Duration; +use crate::common::frame::FrameRecords; pub(crate) enum Setting { DecodeLevel(DecodeLevel), @@ -174,7 +175,7 @@ impl RequestDetails { } impl Serialize for RequestDetails { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { match self { RequestDetails::ReadCoils(x) => x.serialize(cursor), RequestDetails::ReadDiscreteInputs(x) => x.serialize(cursor), diff --git a/rodbus/src/common/frame.rs b/rodbus/src/common/frame.rs index d6031aff..b9b93761 100644 --- a/rodbus/src/common/frame.rs +++ b/rodbus/src/common/frame.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use crate::common::phys::PhysLayer; use std::ops::Range; @@ -251,6 +252,10 @@ impl FormatType { } } +pub(crate) struct FrameRecords { + records: HashSet, +} + pub(crate) struct FrameWriter { format_type: FormatType, buffer: [u8; constants::MAX_FRAME_LENGTH], @@ -280,6 +285,44 @@ impl std::fmt::Display for FunctionField { } } +impl FrameRecords { + pub(crate) fn new() -> Self { + Self { + records: HashSet::new(), + } + } + + ///Record a offset to fill in the value at a later point, but before it's send. + /// NOTE: Currently only works with byte values. + pub(crate) fn record(&mut self, cursor: &mut WriteCursor) -> usize { + let offset = cursor.position(); + self.records.insert(offset); + cursor.skip(1).unwrap(); + + offset + } + + //TODO(Kay): Return an error here if things are looking wrong ! + ///Tries to fill in the value at the recorded offset, returns an error if there is no corresponding + /// record found + pub(crate) fn fill_record(&mut self, cursor: &mut WriteCursor, position: usize, value: u8) { + if self.records.contains(&position) { + let current_position = cursor.position(); + cursor.seek_to(position).unwrap(); + cursor.write_u8(value).unwrap(); + cursor.seek_to(current_position).unwrap(); + } + + //TODO(Kay): Error ! + } + + ///Return true if there are no recorded offsets in our store. + pub(crate) fn records_empty(&self) -> bool { + self.records.is_empty() + } + +} + impl FunctionField { pub(crate) fn unknown(fc: u8) -> Self { Self::UnknownFunction(fc) diff --git a/rodbus/src/common/serialize.rs b/rodbus/src/common/serialize.rs index c0701d78..c888e588 100644 --- a/rodbus/src/common/serialize.rs +++ b/rodbus/src/common/serialize.rs @@ -17,6 +17,7 @@ use crate::DeviceInfo; use crate::ReadDeviceRequest; use scursor::{ReadCursor, WriteCursor}; +use crate::common::frame::{Frame, FrameRecords}; use crate::server::ServerDeviceInfo; pub(crate) fn calc_bytes_for_bits(num_bits: usize) -> Result { @@ -33,7 +34,7 @@ pub(crate) fn calc_bytes_for_registers(num_registers: usize) -> Result Result<(), RequestError> { + fn serialize(&self, cur: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { cur.write_u16_be(self.start)?; cur.write_u16_be(self.count)?; Ok(()) @@ -60,14 +61,14 @@ impl Loggable for AddressRange { } impl Serialize for crate::exception::ExceptionCode { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { cursor.write_u8((*self).into())?; Ok(()) } } impl Serialize for Indexed { - fn serialize(&self, cur: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cur: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { cur.write_u16_be(self.index)?; cur.write_u16_be(coil_to_u16(self.value))?; Ok(()) @@ -106,7 +107,7 @@ impl Loggable for Indexed { } impl Serialize for Indexed { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { cursor.write_u16_be(self.index)?; cursor.write_u16_be(self.value)?; Ok(()) @@ -141,7 +142,7 @@ impl Loggable for Indexed { } impl Serialize for &[bool] { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { // how many bytes should we have? let num_bytes = calc_bytes_for_bits(self.len())?; @@ -165,7 +166,7 @@ impl Serialize for BitWriter where T: Fn(u16) -> Result, { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { let range = self.range.get(); // write the number of bytes that follow let num_bytes = calc_bytes_for_bits(range.count as usize)?; @@ -228,7 +229,7 @@ impl Serialize for RegisterWriter where T: Fn(u16) -> Result, { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { // write the number of bytes that follow let num_bytes = calc_bytes_for_registers(self.range.get().count as usize)?; cursor.write_u8(num_bytes)?; @@ -270,7 +271,7 @@ where } impl Serialize for &[u16] { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { let num_bytes = calc_bytes_for_registers(self.len())?; cursor.write_u8(num_bytes)?; @@ -283,21 +284,21 @@ impl Serialize for &[u16] { } impl Serialize for WriteMultiple { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { - self.range.serialize(cursor)?; - self.values.as_slice().serialize(cursor) + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + self.range.serialize(cursor, None)?; + self.values.as_slice().serialize(cursor, None) } } impl Serialize for WriteMultiple { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { - self.range.serialize(cursor)?; - self.values.as_slice().serialize(cursor) + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + self.range.serialize(cursor, None)?; + self.values.as_slice().serialize(cursor, None) } } impl Serialize for ReadDeviceRequest { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { cursor.write_u8(self.mei_code as u8)?; cursor.write_u8(self.dev_id as u8)?; @@ -315,7 +316,7 @@ impl<'a, T> Serialize for DeviceIdentificationResponse<'a, T> where T: Fn(Option) -> Result, crate::exception::ExceptionCode>, { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { let mut device_data: ServerDeviceInfo = (self.getter)(None)?; //TODO(Kay): We need to rollback things a bit so these values are standin values for now ! @@ -343,9 +344,20 @@ where //TODO(Kay): These fields need to be written after we know how much of the actual objects // we have written out ! - cursor.write_u8(0x00); //MORE FOLLOWS INDICATOR - cursor.write_u8(0x00); //MORE FOLLOWS VALUE - cursor.write_u8(0)?; //OBJECT COUNT + //NOTE(Kay): Again one of my great clunky APIs :) + let mut more_follows_indicator_offset = 0; + let mut more_follows_value_offset = 0; + let mut number_of_objects_offset = 0; + let mut records = records; + if let Some(recorder) = records.as_mut() { + //STORE: + // MORE_FOLLOWS_INDICATOR + // MORE_FOLLOWS_VALUE + // OBJECT_COUNT + more_follows_indicator_offset = recorder.record(cursor); + more_follows_value_offset = recorder.record(cursor); + number_of_objects_offset = recorder.record(cursor); + } const SAFETY_MARGIN: u8 = 7; @@ -372,6 +384,17 @@ where device_data = (self.getter)(device_data.next_object_id)?; } + if let Some(recorder) = records { + if device_data.next_object_id.is_some() { + recorder.fill_record(cursor, more_follows_indicator_offset, 0xFF); + } else { + recorder.fill_record(cursor, more_follows_value_offset, 0x00); + } + + recorder.fill_record(cursor, number_of_objects_offset, id); + } + + /*for object in device_data.object_data { let id = device_data.object_data[position]; @@ -448,7 +471,7 @@ where } impl Serialize for Option { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { const CONTINUE_MARKER: u8 = 0xFF; const END_MARKER: u8 = 0x00; match self { @@ -466,7 +489,7 @@ impl Serialize for Option { } impl Serialize for &str { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { cursor.write_u8(self.len() as u8)?; cursor.write_bytes(self.as_bytes())?; diff --git a/rodbus/src/serial/frame.rs b/rodbus/src/serial/frame.rs index e740e16e..045d90e0 100644 --- a/rodbus/src/serial/frame.rs +++ b/rodbus/src/serial/frame.rs @@ -1,7 +1,5 @@ use crate::common::buffer::ReadBuffer; -use crate::common::frame::{ - Frame, FrameDestination, FrameHeader, FrameInfo, FrameType, FunctionField, -}; +use crate::common::frame::{Frame, FrameDestination, FrameHeader, FrameInfo, FrameRecords, FrameType, FunctionField}; use crate::common::function::FunctionCode; use crate::common::traits::Serialize; use crate::decode::FrameDecodeLevel; @@ -219,7 +217,12 @@ pub(crate) fn format_rtu_pdu( cursor.write_u8(header.destination.value())?; cursor.write_u8(function.get_value())?; let start_pdu_body = cursor.position(); - msg.serialize(cursor)?; + let mut records = FrameRecords::new(); + msg.serialize(cursor, Some(&mut records))?; + + if !records.records_empty() { + //TODO(Kay): We need to inform the user about a forgotten empty lonely byte :( (NOTE: Only user of this API is probably me but whatever :) ) + } let end_pdu_body = cursor.position(); // Write the CRC let crc = CRC.checksum(cursor.get(start_frame..end_pdu_body).unwrap()); diff --git a/rodbus/src/tcp/frame.rs b/rodbus/src/tcp/frame.rs index 738574a6..95ed9727 100644 --- a/rodbus/src/tcp/frame.rs +++ b/rodbus/src/tcp/frame.rs @@ -1,5 +1,5 @@ use crate::common::buffer::ReadBuffer; -use crate::common::frame::{Frame, FrameHeader, FrameInfo, FrameType, FunctionField, TxId}; +use crate::common::frame::{Frame, FrameHeader, FrameInfo, FrameRecords, FrameType, FunctionField, TxId}; use crate::common::traits::Serialize; use crate::decode::FrameDecodeLevel; use crate::error::{FrameParseError, RequestError}; @@ -145,7 +145,13 @@ pub(crate) fn format_mbap( let start_pdu = cursor.position(); cursor.write_u8(function.get_value())?; let start_pdu_body = cursor.position(); - msg.serialize(cursor)?; + let mut records = FrameRecords::new(); + + msg.serialize(cursor, Some(&mut records))?; + + if !records.records_empty() { + //TODO(Kay): Again we need to pass this error up ! + } let end_pdu = cursor.position(); // the length field includes the unit identifier From 3c144b3e2312a1e435c64e4a882f792b3bbb407a Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 15:11:47 +0100 Subject: [PATCH 13/41] refactor(serialize trait): add recorder into serialize trait --- rodbus/src/common/traits.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rodbus/src/common/traits.rs b/rodbus/src/common/traits.rs index bc3cc5e8..c03ca172 100644 --- a/rodbus/src/common/traits.rs +++ b/rodbus/src/common/traits.rs @@ -3,9 +3,10 @@ use crate::error::*; use crate::ExceptionCode; use scursor::{ReadCursor, WriteCursor}; +use crate::common::frame::FrameRecords; pub(crate) trait Serialize { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError>; + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError>; } pub(crate) trait Loggable { From a5979ab31be0e517a1ae4d03db15de74d359b425 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 15:13:36 +0100 Subject: [PATCH 14/41] refactor(serialize): pass none where no recorder is necessary --- rodbus/src/client/requests/read_bits.rs | 2 +- rodbus/src/client/requests/read_device_identification.rs | 2 +- rodbus/src/client/requests/read_registers.rs | 2 +- rodbus/src/client/requests/write_multiple.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rodbus/src/client/requests/read_bits.rs b/rodbus/src/client/requests/read_bits.rs index 84b64575..ae4cff1d 100644 --- a/rodbus/src/client/requests/read_bits.rs +++ b/rodbus/src/client/requests/read_bits.rs @@ -72,7 +72,7 @@ impl ReadBits { } pub(crate) fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { - self.request.get().serialize(cursor) + self.request.get().serialize(cursor, None) } pub(crate) fn failure(&mut self, err: RequestError) { diff --git a/rodbus/src/client/requests/read_device_identification.rs b/rodbus/src/client/requests/read_device_identification.rs index 48c72d5c..26a5520d 100644 --- a/rodbus/src/client/requests/read_device_identification.rs +++ b/rodbus/src/client/requests/read_device_identification.rs @@ -62,7 +62,7 @@ impl ReadDevice { } pub(crate) fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { - self.request.serialize(cursor) + self.request.serialize(cursor, None) } pub(crate) fn channel( diff --git a/rodbus/src/client/requests/read_registers.rs b/rodbus/src/client/requests/read_registers.rs index 8ba7e7ff..fa2c9693 100644 --- a/rodbus/src/client/requests/read_registers.rs +++ b/rodbus/src/client/requests/read_registers.rs @@ -75,7 +75,7 @@ impl ReadRegisters { } pub(crate) fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { - self.request.get().serialize(cursor) + self.request.get().serialize(cursor, None) } pub(crate) fn failure(&mut self, err: RequestError) { diff --git a/rodbus/src/client/requests/write_multiple.rs b/rodbus/src/client/requests/write_multiple.rs index 29593daa..73ae8586 100644 --- a/rodbus/src/client/requests/write_multiple.rs +++ b/rodbus/src/client/requests/write_multiple.rs @@ -95,7 +95,7 @@ where } pub(crate) fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { - self.request.serialize(cursor) + self.request.serialize(cursor, None) } pub(crate) fn failure(&mut self, err: RequestError) { From 5d09fb2ec9bd8739c50f0f6c9ff54931c6d56e72 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Tue, 27 Feb 2024 15:14:07 +0100 Subject: [PATCH 15/41] chore(grammar): remove double "the" from doc comment --- rodbus/src/server/handler.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rodbus/src/server/handler.rs b/rodbus/src/server/handler.rs index b09e0b96..024bb31a 100644 --- a/rodbus/src/server/handler.rs +++ b/rodbus/src/server/handler.rs @@ -8,7 +8,7 @@ use crate::types::*; /// Type that the server will return in response to a read_device_info #[derive(Debug, PartialEq)] pub struct ServerDeviceInfo<'a> { - /// Conformity level the the server is willing to grant + /// Conformity level the server is willing to grant pub conformity_level: DeviceConformityLevel, /// The ID of the next object, if available This will pub next_object_id: Option, From 5011f281c5850861a9831ad8e7c9ac388a151bdd Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 28 Feb 2024 11:04:06 +0100 Subject: [PATCH 16/41] tests(frame): fix the frame tests by adding the now necessary frame rec. --- rodbus/src/common/serialize.rs | 8 ++++---- rodbus/src/serial/frame.rs | 2 +- rodbus/src/tcp/frame.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rodbus/src/common/serialize.rs b/rodbus/src/common/serialize.rs index c888e588..edbabcfc 100644 --- a/rodbus/src/common/serialize.rs +++ b/rodbus/src/common/serialize.rs @@ -506,7 +506,7 @@ mod tests { let range = AddressRange::try_from(3, 512).unwrap(); let mut buffer = [0u8; 4]; let mut cursor = WriteCursor::new(&mut buffer); - range.serialize(&mut cursor).unwrap(); + range.serialize(&mut cursor, None).unwrap(); assert_eq!(buffer, [0x00, 0x03, 0x02, 0x00]); } @@ -517,14 +517,14 @@ mod tests { let mut cursor = WriteCursor::new(&mut buffer); - next_position.serialize(&mut cursor).unwrap(); + next_position.serialize(&mut cursor, None).unwrap(); assert_eq!(buffer, [0xFF, 0x03]); let next_position = None; let mut buffer = [0u8; 2]; let mut cursor = WriteCursor::new(&mut buffer); - next_position.serialize(&mut cursor).unwrap(); + next_position.serialize(&mut cursor, None).unwrap(); assert_eq!(buffer, [0x00, 0x00]); } @@ -534,7 +534,7 @@ mod tests { let mut buffer = [0u8; 14]; let mut cursor = WriteCursor::new(&mut buffer); - test_str.as_str().serialize(&mut cursor).unwrap(); + test_str.as_str().serialize(&mut cursor, None).unwrap(); let expected: [u8; 14] = [ 0x0D, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, diff --git a/rodbus/src/serial/frame.rs b/rodbus/src/serial/frame.rs index 045d90e0..094703b0 100644 --- a/rodbus/src/serial/frame.rs +++ b/rodbus/src/serial/frame.rs @@ -748,7 +748,7 @@ mod tests { } impl<'a> Serialize for MockMessage<'a> { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { for byte in &self.frame[2..self.frame.len() - 2] { cursor.write_u8(*byte)?; } diff --git a/rodbus/src/tcp/frame.rs b/rodbus/src/tcp/frame.rs index 95ed9727..bb727cd7 100644 --- a/rodbus/src/tcp/frame.rs +++ b/rodbus/src/tcp/frame.rs @@ -225,7 +225,7 @@ mod tests { } impl Serialize for MockBody { - fn serialize(&self, cursor: &mut WriteCursor) -> Result<(), RequestError> { + fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { for b in self.body { cursor.write_u8(*b)?; } From 6fc31f54161a20cd74cd002684d99c0a29d92fad Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 28 Feb 2024 12:50:37 +0100 Subject: [PATCH 17/41] refactor(frame_recorder): Improve the API of the FrameRecorder. --- rodbus/src/common/frame.rs | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/rodbus/src/common/frame.rs b/rodbus/src/common/frame.rs index b9b93761..a0b9186f 100644 --- a/rodbus/src/common/frame.rs +++ b/rodbus/src/common/frame.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use crate::common::phys::PhysLayer; use std::ops::Range; @@ -8,7 +8,7 @@ use crate::common::traits::{Loggable, LoggableDisplay, Serialize}; use crate::error::RequestError; use crate::tcp::frame::{MbapDisplay, MbapHeader, MbapParser}; use crate::types::UnitId; -use crate::{DecodeLevel, ExceptionCode, FrameDecodeLevel}; +use crate::{DecodeLevel, ExceptionCode, FrameDecodeLevel, RecorderError}; use scursor::WriteCursor; @@ -252,8 +252,11 @@ impl FormatType { } } + + pub(crate) struct FrameRecords { - records: HashSet, + records: HashMap<&'static str, usize>, + //records: HashSet, } pub(crate) struct FrameWriter { @@ -288,32 +291,40 @@ impl std::fmt::Display for FunctionField { impl FrameRecords { pub(crate) fn new() -> Self { Self { - records: HashSet::new(), + records: HashMap::new(), + //records: HashSet::new(), } } ///Record a offset to fill in the value at a later point, but before it's send. /// NOTE: Currently only works with byte values. - pub(crate) fn record(&mut self, cursor: &mut WriteCursor) -> usize { - let offset = cursor.position(); - self.records.insert(offset); + pub(crate) fn record(&mut self, key: &'static str, cursor: &mut WriteCursor) -> Result<(), crate::InternalError> { + if self.records.contains_key(key) { + return Err(RecorderError::RecordKeyExists(key.clone()).into()); + } + + //Insert our new key and advance the cursor position to the next byte. + self.records.insert(key, cursor.position()); cursor.skip(1).unwrap(); - offset + Ok(()) } - //TODO(Kay): Return an error here if things are looking wrong ! ///Tries to fill in the value at the recorded offset, returns an error if there is no corresponding /// record found - pub(crate) fn fill_record(&mut self, cursor: &mut WriteCursor, position: usize, value: u8) { - if self.records.contains(&position) { + pub(crate) fn fill_record(&mut self, cursor: &mut WriteCursor, key: &'static str, value: u8) -> Result<(), crate::InternalError> { + if let Some(position) = self.records.remove(key) { let current_position = cursor.position(); + + //TODO(Kay): Handle possible errors of the cursor ! cursor.seek_to(position).unwrap(); cursor.write_u8(value).unwrap(); cursor.seek_to(current_position).unwrap(); + + return Ok(()); } - //TODO(Kay): Error ! + Err(RecorderError::RecordDoesNotExist(key).into()) } ///Return true if there are no recorded offsets in our store. From 8b085f27c6c306dee40a482228878836ba89f485 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 28 Feb 2024 12:51:25 +0100 Subject: [PATCH 18/41] feat(RecorderError): add a new error type for the frame recorder --- rodbus/src/error.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/rodbus/src/error.rs b/rodbus/src/error.rs index 21b33beb..84e9a8b8 100644 --- a/rodbus/src/error.rs +++ b/rodbus/src/error.rs @@ -1,4 +1,6 @@ use scursor::WriteError; +use tracing::span::Record; +use crate::InternalError::{RecordDoesNotExist, RecordKeyExists}; /// The task processing requests has terminated #[derive(Clone, Copy, Debug)] @@ -157,6 +159,15 @@ pub enum InvalidRange { CountTooLargeForType(u16, u16), // actual and limit } +/// Errors that can be produced when the Frame Recorder is used incorrectly +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum RecorderError { + ///Record Key already in use. + RecordKeyExists(&'static str), + ///Record Key not found. + RecordDoesNotExist(&'static str), +} + /// Errors that indicate faulty logic in the library itself if they occur #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum InternalError { @@ -170,6 +181,19 @@ pub enum InternalError { BadSeekOperation, /// Byte count would exceed maximum allowed size in the ADU of u8 BadByteCount(usize), + /// A position with that name was already recorded. + RecordKeyExists(&'static str), + /// The recorded position was not found under the specified key. + RecordDoesNotExist(&'static str), +} + +impl From for InternalError { + fn from(value: RecorderError) -> Self { + match value { + RecorderError::RecordKeyExists(key) => RecordKeyExists(key), + RecorderError::RecordDoesNotExist(key) => RecordDoesNotExist(key), + } + } } impl std::error::Error for InternalError {} @@ -195,6 +219,12 @@ impl std::fmt::Display for InternalError { InternalError::BadByteCount(size) => { write!(f, "Byte count of in ADU {size} exceeds maximum size of u8") } + RecordKeyExists(key) => { + write!(f, "The key \"{key}\" is already stored inside the recorder") + }, + RecordDoesNotExist(key) => { + write!(f, "The position with the key \"{key}\" was never recorded") + }, } } } From 5b6c4e0af87c0a0343273ce985c8c148ee2d50cc Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 28 Feb 2024 12:52:08 +0100 Subject: [PATCH 19/41] refactor(server_device_info): add read_device_code back into the struct --- rodbus/tests/integration_test_read_device.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rodbus/tests/integration_test_read_device.rs b/rodbus/tests/integration_test_read_device.rs index 11310599..39185d3f 100644 --- a/rodbus/tests/integration_test_read_device.rs +++ b/rodbus/tests/integration_test_read_device.rs @@ -117,6 +117,7 @@ impl Handler { // DeviceInfo::new(mei_code, read_dev_id, self.device_conformity_level, length); let mut server = ServerDeviceInfo { + read_device_code: read_dev_id, conformity_level: ExtendedIdentificationIndividual, //TODO(Kay): This is not checking it's boundaries ! It could easily read data that is not part of basic streaming... next_object_id: if data.get(object_id as usize + 1).is_some() && object_id >= min_range && object_id <= max_range { Some(object_id + 1) } else { None }, @@ -134,6 +135,7 @@ impl Handler { object_id: u8, ) -> Result { let server = ServerDeviceInfo { + read_device_code: read_dev_id, conformity_level: ExtendedIdentificationIndividual, next_object_id: None, object_data: &[0x00,0x04,0x41,0x41,0x41,0x41], From 69ea1b339d07598310dc527d9b3e7fe830eb9eee Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 28 Feb 2024 12:53:36 +0100 Subject: [PATCH 20/41] refactor(server_device_info): add read_device_code field. --- rodbus/src/server/handler.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rodbus/src/server/handler.rs b/rodbus/src/server/handler.rs index 024bb31a..27008fc6 100644 --- a/rodbus/src/server/handler.rs +++ b/rodbus/src/server/handler.rs @@ -8,6 +8,8 @@ use crate::types::*; /// Type that the server will return in response to a read_device_info #[derive(Debug, PartialEq)] pub struct ServerDeviceInfo<'a> { + /// Indicates the Area the Message came from (Basic, Regular, Extended)! + pub read_device_code: ReadDeviceCode, /// Conformity level the server is willing to grant pub conformity_level: DeviceConformityLevel, /// The ID of the next object, if available This will From 1b401bf036ae07be822f23e1b311a9457afe94fa Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 28 Feb 2024 12:54:14 +0100 Subject: [PATCH 21/41] refactor(serialize): change usage of FrameRecorder API --- rodbus/src/common/serialize.rs | 46 +++++++++++----------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/rodbus/src/common/serialize.rs b/rodbus/src/common/serialize.rs index edbabcfc..053c9912 100644 --- a/rodbus/src/common/serialize.rs +++ b/rodbus/src/common/serialize.rs @@ -13,7 +13,7 @@ use crate::types::{ coil_from_u16, coil_to_u16, AddressRange, BitIterator, BitIteratorDisplay, Indexed, RegisterIterator, RegisterIteratorDisplay, }; -use crate::DeviceInfo; +use crate::{DeviceInfo, MeiCode}; use crate::ReadDeviceRequest; use scursor::{ReadCursor, WriteCursor}; @@ -319,44 +319,26 @@ where fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { let mut device_data: ServerDeviceInfo = (self.getter)(None)?; - //TODO(Kay): We need to rollback things a bit so these values are standin values for now ! - const MEI_CODE: u8 = 0x0E; - cursor.write_u8(MEI_CODE)?; - //TODO(Kay): We need to rollback things a bit so these values are standin values for now ! - cursor.write_u8(0x03); - - //cursor.write_u8(device_data.read_device_id as u8)?; + //NOTE(Kay): The MEI Code is always 0x0E so we can write that directly and do not need to + // store this data on the ServerDeviceInfo struct ! + cursor.write_u8(MeiCode::ReadDeviceId as u8)?; + cursor.write_u8(device_data.read_device_code as u8)?; cursor.write_u8(device_data.conformity_level as u8)?; - //let max = device_data.response_message_count(MAX_ADU_LENGTH as u8 - SAFETY_MARGIN); - - //max.serialize(cursor)?; - - //let range: Range = Range { - // start: device_data.next_object_id.unwrap_or_default().into(), - // end: max.unwrap_or(device_data.object_data.len() as u8).into(), - //}; - - //TODO(Kay): We need to write out the right amount of objects we don't have that value - // currently but for now it's probably better to just write a zero value here - // but don't forget that it's there !!! - - //TODO(Kay): These fields need to be written after we know how much of the actual objects - // we have written out ! //NOTE(Kay): Again one of my great clunky APIs :) - let mut more_follows_indicator_offset = 0; - let mut more_follows_value_offset = 0; - let mut number_of_objects_offset = 0; + //TODO(Kay): Maybe we can do some dumb kind of hashmap: + // - We only can record at max 256 Bytes + // - std::Hash is implemented for &str let mut records = records; if let Some(recorder) = records.as_mut() { //STORE: // MORE_FOLLOWS_INDICATOR // MORE_FOLLOWS_VALUE // OBJECT_COUNT - more_follows_indicator_offset = recorder.record(cursor); - more_follows_value_offset = recorder.record(cursor); - number_of_objects_offset = recorder.record(cursor); + recorder.record("MORE_FOLLOWS_INDICATOR", cursor)?; + recorder.record("MORE_FOLLOWS_VALUE", cursor)?; + recorder.record("NUMBER_OF_OBJECTS", cursor)?; } @@ -386,12 +368,12 @@ where if let Some(recorder) = records { if device_data.next_object_id.is_some() { - recorder.fill_record(cursor, more_follows_indicator_offset, 0xFF); + recorder.fill_record(cursor, "MORE_FOLLOWS_INDICATOR", 0xFF)?; } else { - recorder.fill_record(cursor, more_follows_value_offset, 0x00); + recorder.fill_record(cursor, "MORE_FOLLOWS_VALUE", 0x00)?; } - recorder.fill_record(cursor, number_of_objects_offset, id); + recorder.fill_record(cursor, "NUMBER_OF_OBJECTS", id)?; } From 823cbffb62658f6de3c2ce6692420534aa7f5e5d Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 28 Feb 2024 12:55:00 +0100 Subject: [PATCH 22/41] refactor(server): temporary add field to returned dummy value. --- rodbus/examples/server.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rodbus/examples/server.rs b/rodbus/examples/server.rs index a744b664..28b85b57 100644 --- a/rodbus/examples/server.rs +++ b/rodbus/examples/server.rs @@ -140,6 +140,7 @@ impl RequestHandler for SimpleHandler { object_id: Option, ) -> Result { let server = ServerDeviceInfo { + read_device_code: read_dev_id, conformity_level: DeviceConformityLevel::ExtendedIdentificationIndividual, next_object_id: None, object_data: &[0x00,0x04,0x41,0x41,0x41,0x41], From 899355c2487f6b4ddec6abafe3108dade3f24f8c Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 11:12:48 +0200 Subject: [PATCH 23/41] refactor(handler): add current_object_id to ReadDeviceInfo struct --- rodbus/src/server/handler.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rodbus/src/server/handler.rs b/rodbus/src/server/handler.rs index 27008fc6..b22785c2 100644 --- a/rodbus/src/server/handler.rs +++ b/rodbus/src/server/handler.rs @@ -12,6 +12,9 @@ pub struct ServerDeviceInfo<'a> { pub read_device_code: ReadDeviceCode, /// Conformity level the server is willing to grant pub conformity_level: DeviceConformityLevel, + /// The ID of the current object, necessary to generate a valid response + /// but not part of the response! + pub current_object_id: u8, /// The ID of the next object, if available This will pub next_object_id: Option, /// The raw data for this object From 02ebb9a34e6197f326af7f98cfb8804b404f9fee Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 11:14:15 +0200 Subject: [PATCH 24/41] refactor(serialize): object by object serialization for FC43 --- rodbus/src/common/serialize.rs | 50 ++++++++++++++-------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/rodbus/src/common/serialize.rs b/rodbus/src/common/serialize.rs index 053c9912..febdba84 100644 --- a/rodbus/src/common/serialize.rs +++ b/rodbus/src/common/serialize.rs @@ -13,7 +13,7 @@ use crate::types::{ coil_from_u16, coil_to_u16, AddressRange, BitIterator, BitIteratorDisplay, Indexed, RegisterIterator, RegisterIteratorDisplay, }; -use crate::{DeviceInfo, MeiCode}; +use crate::{DeviceInfo, MeiCode, ReadDeviceCode}; use crate::ReadDeviceRequest; use scursor::{ReadCursor, WriteCursor}; @@ -334,67 +334,57 @@ where if let Some(recorder) = records.as_mut() { //STORE: // MORE_FOLLOWS_INDICATOR - // MORE_FOLLOWS_VALUE + // MORE_FOLLOWS_ID // OBJECT_COUNT recorder.record("MORE_FOLLOWS_INDICATOR", cursor)?; - recorder.record("MORE_FOLLOWS_VALUE", cursor)?; + recorder.record("MORE_FOLLOWS_ID", cursor)?; recorder.record("NUMBER_OF_OBJECTS", cursor)?; } const SAFETY_MARGIN: u8 = 7; - let mut position = 0; - let mut id = 0; //Start with the id at the position our read starts ! + let mut position = if device_data.next_object_id.is_some() { device_data.next_object_id.unwrap() } else { 0 }; + let mut id = device_data.current_object_id; //Start with the id at the position our read starts ! + while position < (MAX_ADU_LENGTH as u8 - SAFETY_MARGIN) { - if device_data.object_data.len() >= ((MAX_ADU_LENGTH as u8 - SAFETY_MARGIN)).into() { + if (position as usize) + device_data.object_data.len() >= ((MAX_ADU_LENGTH as u8 - SAFETY_MARGIN)).into() { //TODO(Kay): We need to store that id and make the next read at that address ! + device_data.next_object_id = Some(id); break; } cursor.write_u8(id)?; //ID cursor.write_u8(device_data.object_data.len() as u8)?; cursor.write_bytes(device_data.object_data)?; - id +=1; - position += device_data.object_data.len() as u8; - if device_data.next_object_id.is_none() { break; } + id +=1; + position += device_data.object_data.len() as u8; + device_data = (self.getter)(device_data.next_object_id)?; } if let Some(recorder) = records { if device_data.next_object_id.is_some() { recorder.fill_record(cursor, "MORE_FOLLOWS_INDICATOR", 0xFF)?; + recorder.fill_record(cursor, "MORE_FOLLOWS_ID", id)?; } else { - recorder.fill_record(cursor, "MORE_FOLLOWS_VALUE", 0x00)?; + recorder.fill_record(cursor, "MORE_FOLLOWS_INDICATOR", 0x00)?; + recorder.fill_record(cursor, "MORE_FOLLOWS_ID", 0x00)?; } + //TODO(Kay): This feels hacky...the whole example section in FC43 spec feels wrong... - recorder.fill_record(cursor, "NUMBER_OF_OBJECTS", id)?; + if device_data.read_device_code == ReadDeviceCode::Specific { + recorder.fill_record(cursor, "NUMBER_OF_OBJECTS", 0x01)?; + } else { + recorder.fill_record(cursor, "NUMBER_OF_OBJECTS", id + 1)?; + } } - - /*for object in device_data.object_data { - let id = device_data.object_data[position]; - - cursor.write_u8(device_data.object_data.len() as u8)?; - cursor.write_bytes(device_data.object_data)?; - - }*/ - - - //for message in device_data.object_data[range].iter() { - //let [id, length, data @ ..] = message; - //cursor.write_u8(message.index)?; - - //let data = message.get_data(); - //cursor.write_u8(data.len() as u8)?; - //cursor.write_bytes(data)?; - //} - Ok(()) } } From c097976cf20466c2338f6db1b16a4132b881cb48 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 11:34:24 +0200 Subject: [PATCH 25/41] feat(error): add frame record errors to the InternalError enum --- rodbus/src/error.rs | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/rodbus/src/error.rs b/rodbus/src/error.rs index 84e9a8b8..8438a9b2 100644 --- a/rodbus/src/error.rs +++ b/rodbus/src/error.rs @@ -1,6 +1,5 @@ use scursor::WriteError; use tracing::span::Record; -use crate::InternalError::{RecordDoesNotExist, RecordKeyExists}; /// The task processing requests has terminated #[derive(Clone, Copy, Debug)] @@ -37,6 +36,8 @@ pub enum RequestError { NoConnection, /// Task processing requests has been shutdown Shutdown, + /// Frame recorder was not in an empty state before trying to send the data! + FrameRecorderNotEmpty, } impl std::error::Error for RequestError {} @@ -53,6 +54,8 @@ impl std::fmt::Display for RequestError { RequestError::ResponseTimeout => f.write_str("response timeout"), RequestError::NoConnection => f.write_str("no connection to server"), RequestError::Shutdown => f.write_str("channel shutdown"), + //TODO(Kay): We could give the user more information where they forgot to write the necessary data! + RequestError::FrameRecorderNotEmpty => f.write_str("frame recorder needs to be empty in order to send the message.") } } } @@ -185,13 +188,30 @@ pub enum InternalError { RecordKeyExists(&'static str), /// The recorded position was not found under the specified key. RecordDoesNotExist(&'static str), + /// Attempted to write a value that would result in a Numeric overflow + RecordNumericOverflow, + /// Attempted to write a record beyond the range of the underlying buffer. + RecordWriteOverflow, + /// Attempted to seek to a Position larger than the length of the underlying buffer. + RecordBadSeek, + +} + +impl From for InternalError { + fn from(value: WriteError) -> Self { + match value { + WriteError::NumericOverflow => InternalError::RecordNumericOverflow, + WriteError::WriteOverflow { .. } => InternalError::RecordWriteOverflow, + WriteError::BadSeek { .. } => InternalError::RecordBadSeek, + } + } } impl From for InternalError { fn from(value: RecorderError) -> Self { match value { - RecorderError::RecordKeyExists(key) => RecordKeyExists(key), - RecorderError::RecordDoesNotExist(key) => RecordDoesNotExist(key), + RecorderError::RecordKeyExists(key) => InternalError::RecordKeyExists(key), + RecorderError::RecordDoesNotExist(key) => InternalError::RecordDoesNotExist(key), } } } @@ -219,12 +239,21 @@ impl std::fmt::Display for InternalError { InternalError::BadByteCount(size) => { write!(f, "Byte count of in ADU {size} exceeds maximum size of u8") } - RecordKeyExists(key) => { + InternalError::RecordKeyExists(key) => { write!(f, "The key \"{key}\" is already stored inside the recorder") }, - RecordDoesNotExist(key) => { + InternalError::RecordDoesNotExist(key) => { write!(f, "The position with the key \"{key}\" was never recorded") }, + InternalError::RecordNumericOverflow => { + write!(f, "Attempted to write a recorded value that would result in a Numeric overflow") + }, + InternalError::RecordWriteOverflow => { + write!(f, "Attempted to write a record beyond the range of the underlying buffer.") + }, + InternalError::RecordBadSeek => { + write!(f, "Attempted to seek to a Position larger than the length of the underlying buffer.") + } } } } From 3df08a3ce97c6166f0cc931a308fb4c5d591a993 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 11:35:16 +0200 Subject: [PATCH 26/41] refactor(frame): get rid of the unwraps in the fill_record method --- rodbus/src/common/frame.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rodbus/src/common/frame.rs b/rodbus/src/common/frame.rs index a0b9186f..32c9678d 100644 --- a/rodbus/src/common/frame.rs +++ b/rodbus/src/common/frame.rs @@ -317,9 +317,9 @@ impl FrameRecords { let current_position = cursor.position(); //TODO(Kay): Handle possible errors of the cursor ! - cursor.seek_to(position).unwrap(); - cursor.write_u8(value).unwrap(); - cursor.seek_to(current_position).unwrap(); + cursor.seek_to(position)?; + cursor.write_u8(value)?; + cursor.seek_to(current_position)?; return Ok(()); } From 488e085e4c978a88d7dd41b3320b030b5ec9bd86 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 11:35:56 +0200 Subject: [PATCH 27/41] feat(frame): add handling of non-empty frame recorders before sending --- rodbus/src/serial/frame.rs | 2 +- rodbus/src/tcp/frame.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rodbus/src/serial/frame.rs b/rodbus/src/serial/frame.rs index 094703b0..a0e68ae4 100644 --- a/rodbus/src/serial/frame.rs +++ b/rodbus/src/serial/frame.rs @@ -221,7 +221,7 @@ pub(crate) fn format_rtu_pdu( msg.serialize(cursor, Some(&mut records))?; if !records.records_empty() { - //TODO(Kay): We need to inform the user about a forgotten empty lonely byte :( (NOTE: Only user of this API is probably me but whatever :) ) + return Err(RequestError::FrameRecorderNotEmpty) } let end_pdu_body = cursor.position(); // Write the CRC diff --git a/rodbus/src/tcp/frame.rs b/rodbus/src/tcp/frame.rs index bb727cd7..4673d743 100644 --- a/rodbus/src/tcp/frame.rs +++ b/rodbus/src/tcp/frame.rs @@ -150,7 +150,7 @@ pub(crate) fn format_mbap( msg.serialize(cursor, Some(&mut records))?; if !records.records_empty() { - //TODO(Kay): Again we need to pass this error up ! + return Err(RequestError::FrameRecorderNotEmpty) } let end_pdu = cursor.position(); From 1cfe7b911922278aa79d9f833d9a208e1ba08a39 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 11:36:52 +0200 Subject: [PATCH 28/41] refactor(request): remove unnecessary stuff from the way fc43 is handled --- rodbus/src/server/request.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/rodbus/src/server/request.rs b/rodbus/src/server/request.rs index 92165c54..2b9c0e79 100644 --- a/rodbus/src/server/request.rs +++ b/rodbus/src/server/request.rs @@ -140,15 +140,10 @@ impl<'a> Request<'a> { // // And then write them AFTER writing the info objects - //TODO(Kay): Remove the unwrap this is just for learning purposes ! let device_information = DeviceIdentificationResponse::new(|object_id| { - let next_id = match (read.obj_id, object_id) { - (None, None) => Some(0), - (None, Some(x)) => Some(x), - (Some(x), None) => Some(x), - (Some(x), Some(y)) => Some(x + y), - }; - handler.read_device_info(read.mei_code, read.dev_id, next_id) + let base_id = if read.obj_id.is_some() { read.obj_id.unwrap() } else { 0 }; + let request_offset = if object_id.is_some() { object_id.unwrap() } else { 0 }; + handler.read_device_info(read.mei_code, read.dev_id, Some(base_id + request_offset)) }); writer.format_reply(header, function, &device_information, level) From 76e5e1d580fb56cdeacb9304562b18f4b985c940 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 11:37:47 +0200 Subject: [PATCH 29/41] test(integration_tests): change the code that generates the response --- rodbus/tests/integration_test_read_device.rs | 55 +++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/rodbus/tests/integration_test_read_device.rs b/rodbus/tests/integration_test_read_device.rs index 39185d3f..59a44ca2 100644 --- a/rodbus/tests/integration_test_read_device.rs +++ b/rodbus/tests/integration_test_read_device.rs @@ -85,9 +85,9 @@ impl Handler { let (min_range, max_range) = match read_dev_id { ReadDeviceCode::BasicStreaming => (0x00, 0x03), - ReadDeviceCode::RegularStreaming => (0x04, 0x06), - ReadDeviceCode::ExtendedStreaming => (0x07, 0x7F), - ReadDeviceCode::Specific => (0x80, 0xFF), + ReadDeviceCode::RegularStreaming => (0x03, 0x7F), + ReadDeviceCode::ExtendedStreaming => (0x80, 0xFF), + ReadDeviceCode::Specific => (0x00, 0xFF), }; let data = match read_dev_id { ReadDeviceCode::BasicStreaming => self.read_basic_device_info()?, @@ -113,16 +113,27 @@ impl Handler { let length = Handler::message_count_from_area_slice(data) as u8; + let next_object_id = if (object_id + 1) >= max_range { + None + } else { + if data[(object_id + 1) as usize].is_some() { + Some(object_id + 1) + } else { + None + } + }; + //let mut device_info_response = // DeviceInfo::new(mei_code, read_dev_id, self.device_conformity_level, length); let mut server = ServerDeviceInfo { read_device_code: read_dev_id, conformity_level: ExtendedIdentificationIndividual, + current_object_id: object_id, //TODO(Kay): This is not checking it's boundaries ! It could easily read data that is not part of basic streaming... - next_object_id: if data.get(object_id as usize + 1).is_some() && object_id >= min_range && object_id <= max_range { Some(object_id + 1) } else { None }, + next_object_id, //TODO(Kay): Remove the unwrap ? - object_data: data[object_id as usize].unwrap().as_bytes(), + object_data: data[(object_id as usize)].unwrap().as_bytes(), }; Ok(server) @@ -134,25 +145,19 @@ impl Handler { read_dev_id: ReadDeviceCode, object_id: u8, ) -> Result { - let server = ServerDeviceInfo { - read_device_code: read_dev_id, - conformity_level: ExtendedIdentificationIndividual, - next_object_id: None, - object_data: &[0x00,0x04,0x41,0x41,0x41,0x41], - }; - /*let data = self.read_specific_device_info(object_id)?; - let string = RawModbusInfoObject::new( - read_dev_id, - object_id, - data[0].unwrap().len() as u8, - data[0].unwrap().as_bytes(), - ); - - let mut device_info = - DeviceInfo::new(mei_code, read_dev_id, self.device_conformity_level, 1); - device_info.storage.push(string);*/ - - Ok(server) + if self.device_info[object_id as usize].is_some() { + let data = self.device_info[object_id as usize].unwrap().as_bytes(); + + Ok(ServerDeviceInfo { + read_device_code: read_dev_id, + conformity_level: ExtendedIdentificationIndividual, + current_object_id: object_id, + next_object_id: None, + object_data: data, + }) + } else { + return Err(ExceptionCode::IllegalDataAddress) + } } } @@ -216,7 +221,7 @@ async fn test_read_device_info_request_response() { ); channel.enable().await.unwrap(); - let params = RequestParam::new(UnitId::new(0x01), Duration::from_secs(5)); + let params = RequestParam::new(UnitId::new(0x01), Duration::from_secs(3600)); //TEST Basic Device Reading Information let result = channel From 049e7eae764a356b00559a384f5867d980bce3b5 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:04:18 +0200 Subject: [PATCH 30/41] feat(ffi): add FrameRecorderNotEmpty conversion into InternalError --- ffi/rodbus-ffi/src/helpers/conversions.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ffi/rodbus-ffi/src/helpers/conversions.rs b/ffi/rodbus-ffi/src/helpers/conversions.rs index 77ba8b55..7df18b4a 100644 --- a/ffi/rodbus-ffi/src/helpers/conversions.rs +++ b/ffi/rodbus-ffi/src/helpers/conversions.rs @@ -40,6 +40,7 @@ impl From for ffi::RequestError { rodbus::RequestError::Exception(ex) => ex.into(), rodbus::RequestError::Io(_) => ffi::RequestError::IoError, rodbus::RequestError::BadResponse(_) => ffi::RequestError::BadResponse, + rodbus::RequestError::FrameRecorderNotEmpty => ffi::RequestError::InternalError, } } } From d33856134768e7de31c7509e29bc9972cc31ebf3 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:07:57 +0200 Subject: [PATCH 31/41] refactor(message): make the FrameRecorder argument invisible. --- rodbus/src/client/message.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rodbus/src/client/message.rs b/rodbus/src/client/message.rs index 626bb3ff..03b76b3f 100644 --- a/rodbus/src/client/message.rs +++ b/rodbus/src/client/message.rs @@ -14,9 +14,9 @@ use crate::client::requests::write_single::SingleWrite; use crate::common::traits::Serialize; use crate::types::{Indexed, UnitId}; +use crate::common::frame::FrameRecords; use scursor::{ReadCursor, WriteCursor}; use std::time::Duration; -use crate::common::frame::FrameRecords; pub(crate) enum Setting { DecodeLevel(DecodeLevel), @@ -175,7 +175,11 @@ impl RequestDetails { } impl Serialize for RequestDetails { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { match self { RequestDetails::ReadCoils(x) => x.serialize(cursor), RequestDetails::ReadDiscreteInputs(x) => x.serialize(cursor), From e6a817ccbe7334f9aebf14dcdff4bf9fa8f57d29 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:08:29 +0200 Subject: [PATCH 32/41] chore(read_device_ident): cargo fmt improvements --- rodbus/src/client/requests/read_device_identification.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rodbus/src/client/requests/read_device_identification.rs b/rodbus/src/client/requests/read_device_identification.rs index 26a5520d..c68980a7 100644 --- a/rodbus/src/client/requests/read_device_identification.rs +++ b/rodbus/src/client/requests/read_device_identification.rs @@ -2,8 +2,8 @@ use scursor::{ReadCursor, WriteCursor}; use crate::{ common::{function::FunctionCode, traits::Serialize}, - AppDecodeLevel, DeviceInfo, RawModbusInfoObject, ReadDeviceCode, - ReadDeviceRequest, RequestError, + AppDecodeLevel, DeviceInfo, RawModbusInfoObject, ReadDeviceCode, ReadDeviceRequest, + RequestError, }; pub(crate) struct ReadDevice { From 9c7b75f80532efb945b7f8a5e49192703c90aa61 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:09:56 +0200 Subject: [PATCH 33/41] refactor(frame): remove unnecessary imports, unnecessary clone, run fmt --- rodbus/src/common/frame.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/rodbus/src/common/frame.rs b/rodbus/src/common/frame.rs index 32c9678d..02090a9e 100644 --- a/rodbus/src/common/frame.rs +++ b/rodbus/src/common/frame.rs @@ -1,5 +1,5 @@ -use std::collections::{HashMap, HashSet}; use crate::common::phys::PhysLayer; +use std::collections::HashMap; use std::ops::Range; use crate::common::buffer::ReadBuffer; @@ -252,8 +252,6 @@ impl FormatType { } } - - pub(crate) struct FrameRecords { records: HashMap<&'static str, usize>, //records: HashSet, @@ -298,9 +296,13 @@ impl FrameRecords { ///Record a offset to fill in the value at a later point, but before it's send. /// NOTE: Currently only works with byte values. - pub(crate) fn record(&mut self, key: &'static str, cursor: &mut WriteCursor) -> Result<(), crate::InternalError> { + pub(crate) fn record( + &mut self, + key: &'static str, + cursor: &mut WriteCursor, + ) -> Result<(), crate::InternalError> { if self.records.contains_key(key) { - return Err(RecorderError::RecordKeyExists(key.clone()).into()); + return Err(RecorderError::RecordKeyExists(key).into()); } //Insert our new key and advance the cursor position to the next byte. @@ -312,7 +314,12 @@ impl FrameRecords { ///Tries to fill in the value at the recorded offset, returns an error if there is no corresponding /// record found - pub(crate) fn fill_record(&mut self, cursor: &mut WriteCursor, key: &'static str, value: u8) -> Result<(), crate::InternalError> { + pub(crate) fn fill_record( + &mut self, + cursor: &mut WriteCursor, + key: &'static str, + value: u8, + ) -> Result<(), crate::InternalError> { if let Some(position) = self.records.remove(key) { let current_position = cursor.position(); @@ -331,7 +338,6 @@ impl FrameRecords { pub(crate) fn records_empty(&self) -> bool { self.records.is_empty() } - } impl FunctionField { From 084197c614a3734ad2d1536ad4d87b0c094a231d Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:10:36 +0200 Subject: [PATCH 34/41] refactor(serialize): remove unnecessary imports, make records invisible --- rodbus/src/common/serialize.rs | 105 +++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 23 deletions(-) diff --git a/rodbus/src/common/serialize.rs b/rodbus/src/common/serialize.rs index febdba84..c922a232 100644 --- a/rodbus/src/common/serialize.rs +++ b/rodbus/src/common/serialize.rs @@ -13,12 +13,12 @@ use crate::types::{ coil_from_u16, coil_to_u16, AddressRange, BitIterator, BitIteratorDisplay, Indexed, RegisterIterator, RegisterIteratorDisplay, }; -use crate::{DeviceInfo, MeiCode, ReadDeviceCode}; use crate::ReadDeviceRequest; +use crate::{MeiCode, ReadDeviceCode}; -use scursor::{ReadCursor, WriteCursor}; -use crate::common::frame::{Frame, FrameRecords}; +use crate::common::frame::FrameRecords; use crate::server::ServerDeviceInfo; +use scursor::{ReadCursor, WriteCursor}; pub(crate) fn calc_bytes_for_bits(num_bits: usize) -> Result { let div_8 = num_bits / 8; @@ -34,7 +34,11 @@ pub(crate) fn calc_bytes_for_registers(num_registers: usize) -> Result) -> Result<(), RequestError> { + fn serialize( + &self, + cur: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { cur.write_u16_be(self.start)?; cur.write_u16_be(self.count)?; Ok(()) @@ -61,14 +65,22 @@ impl Loggable for AddressRange { } impl Serialize for crate::exception::ExceptionCode { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { cursor.write_u8((*self).into())?; Ok(()) } } impl Serialize for Indexed { - fn serialize(&self, cur: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cur: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { cur.write_u16_be(self.index)?; cur.write_u16_be(coil_to_u16(self.value))?; Ok(()) @@ -107,7 +119,11 @@ impl Loggable for Indexed { } impl Serialize for Indexed { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { cursor.write_u16_be(self.index)?; cursor.write_u16_be(self.value)?; Ok(()) @@ -142,7 +158,11 @@ impl Loggable for Indexed { } impl Serialize for &[bool] { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { // how many bytes should we have? let num_bytes = calc_bytes_for_bits(self.len())?; @@ -166,7 +186,11 @@ impl Serialize for BitWriter where T: Fn(u16) -> Result, { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { let range = self.range.get(); // write the number of bytes that follow let num_bytes = calc_bytes_for_bits(range.count as usize)?; @@ -229,7 +253,11 @@ impl Serialize for RegisterWriter where T: Fn(u16) -> Result, { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { // write the number of bytes that follow let num_bytes = calc_bytes_for_registers(self.range.get().count as usize)?; cursor.write_u8(num_bytes)?; @@ -271,7 +299,11 @@ where } impl Serialize for &[u16] { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { let num_bytes = calc_bytes_for_registers(self.len())?; cursor.write_u8(num_bytes)?; @@ -284,21 +316,33 @@ impl Serialize for &[u16] { } impl Serialize for WriteMultiple { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { self.range.serialize(cursor, None)?; self.values.as_slice().serialize(cursor, None) } } impl Serialize for WriteMultiple { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { self.range.serialize(cursor, None)?; self.values.as_slice().serialize(cursor, None) } } impl Serialize for ReadDeviceRequest { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { cursor.write_u8(self.mei_code as u8)?; cursor.write_u8(self.dev_id as u8)?; @@ -316,7 +360,11 @@ impl<'a, T> Serialize for DeviceIdentificationResponse<'a, T> where T: Fn(Option) -> Result, crate::exception::ExceptionCode>, { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + records: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { let mut device_data: ServerDeviceInfo = (self.getter)(None)?; //NOTE(Kay): The MEI Code is always 0x0E so we can write that directly and do not need to @@ -325,7 +373,6 @@ where cursor.write_u8(device_data.read_device_code as u8)?; cursor.write_u8(device_data.conformity_level as u8)?; - //NOTE(Kay): Again one of my great clunky APIs :) //TODO(Kay): Maybe we can do some dumb kind of hashmap: // - We only can record at max 256 Bytes @@ -341,15 +388,19 @@ where recorder.record("NUMBER_OF_OBJECTS", cursor)?; } - const SAFETY_MARGIN: u8 = 7; - let mut position = if device_data.next_object_id.is_some() { device_data.next_object_id.unwrap() } else { 0 }; + let mut position = if device_data.next_object_id.is_some() { + device_data.next_object_id.unwrap() + } else { + 0 + }; let mut id = device_data.current_object_id; //Start with the id at the position our read starts ! while position < (MAX_ADU_LENGTH as u8 - SAFETY_MARGIN) { - - if (position as usize) + device_data.object_data.len() >= ((MAX_ADU_LENGTH as u8 - SAFETY_MARGIN)).into() { + if (position as usize) + device_data.object_data.len() + >= (MAX_ADU_LENGTH as u8 - SAFETY_MARGIN).into() + { //TODO(Kay): We need to store that id and make the next read at that address ! device_data.next_object_id = Some(id); break; @@ -362,7 +413,7 @@ where break; } - id +=1; + id += 1; position += device_data.object_data.len() as u8; device_data = (self.getter)(device_data.next_object_id)?; @@ -443,7 +494,11 @@ where } impl Serialize for Option { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { const CONTINUE_MARKER: u8 = 0xFF; const END_MARKER: u8 = 0x00; match self { @@ -461,7 +516,11 @@ impl Serialize for Option { } impl Serialize for &str { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + _: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { cursor.write_u8(self.len() as u8)?; cursor.write_bytes(self.as_bytes())?; From 7e355c6e48ee2fb8235bf939a94a19794d89c05c Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:11:26 +0200 Subject: [PATCH 35/41] chore(traits): cargo fmt formatting applied --- rodbus/src/common/traits.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rodbus/src/common/traits.rs b/rodbus/src/common/traits.rs index c03ca172..0f047954 100644 --- a/rodbus/src/common/traits.rs +++ b/rodbus/src/common/traits.rs @@ -2,11 +2,15 @@ use crate::decode::AppDecodeLevel; use crate::error::*; use crate::ExceptionCode; -use scursor::{ReadCursor, WriteCursor}; use crate::common::frame::FrameRecords; +use scursor::{ReadCursor, WriteCursor}; pub(crate) trait Serialize { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError>; + fn serialize( + &self, + cursor: &mut WriteCursor, + records: Option<&mut FrameRecords>, + ) -> Result<(), RequestError>; } pub(crate) trait Loggable { From b26e1a484713354420c6c5081d3c8594bcd6f728 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:11:57 +0200 Subject: [PATCH 36/41] chore(frame): cargo fmt formatting applied --- rodbus/src/serial/frame.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/rodbus/src/serial/frame.rs b/rodbus/src/serial/frame.rs index a0e68ae4..37f24e33 100644 --- a/rodbus/src/serial/frame.rs +++ b/rodbus/src/serial/frame.rs @@ -1,5 +1,7 @@ use crate::common::buffer::ReadBuffer; -use crate::common::frame::{Frame, FrameDestination, FrameHeader, FrameInfo, FrameRecords, FrameType, FunctionField}; +use crate::common::frame::{ + Frame, FrameDestination, FrameHeader, FrameInfo, FrameRecords, FrameType, FunctionField, +}; use crate::common::function::FunctionCode; use crate::common::traits::Serialize; use crate::decode::FrameDecodeLevel; @@ -221,7 +223,7 @@ pub(crate) fn format_rtu_pdu( msg.serialize(cursor, Some(&mut records))?; if !records.records_empty() { - return Err(RequestError::FrameRecorderNotEmpty) + return Err(RequestError::FrameRecorderNotEmpty); } let end_pdu_body = cursor.position(); // Write the CRC @@ -748,7 +750,11 @@ mod tests { } impl<'a> Serialize for MockMessage<'a> { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + records: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { for byte in &self.frame[2..self.frame.len() - 2] { cursor.write_u8(*byte)?; } From edcfc09426e0a89bba5000f6116547d3435f64a4 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:12:53 +0200 Subject: [PATCH 37/41] refactor(error): remove unnecessary import, apply cargo formatting --- rodbus/src/error.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/rodbus/src/error.rs b/rodbus/src/error.rs index 8438a9b2..315ea112 100644 --- a/rodbus/src/error.rs +++ b/rodbus/src/error.rs @@ -1,5 +1,4 @@ use scursor::WriteError; -use tracing::span::Record; /// The task processing requests has terminated #[derive(Clone, Copy, Debug)] @@ -55,7 +54,9 @@ impl std::fmt::Display for RequestError { RequestError::NoConnection => f.write_str("no connection to server"), RequestError::Shutdown => f.write_str("channel shutdown"), //TODO(Kay): We could give the user more information where they forgot to write the necessary data! - RequestError::FrameRecorderNotEmpty => f.write_str("frame recorder needs to be empty in order to send the message.") + RequestError::FrameRecorderNotEmpty => { + f.write_str("frame recorder needs to be empty in order to send the message.") + } } } } @@ -194,7 +195,6 @@ pub enum InternalError { RecordWriteOverflow, /// Attempted to seek to a Position larger than the length of the underlying buffer. RecordBadSeek, - } impl From for InternalError { @@ -241,16 +241,22 @@ impl std::fmt::Display for InternalError { } InternalError::RecordKeyExists(key) => { write!(f, "The key \"{key}\" is already stored inside the recorder") - }, + } InternalError::RecordDoesNotExist(key) => { write!(f, "The position with the key \"{key}\" was never recorded") - }, + } InternalError::RecordNumericOverflow => { - write!(f, "Attempted to write a recorded value that would result in a Numeric overflow") - }, + write!( + f, + "Attempted to write a recorded value that would result in a Numeric overflow" + ) + } InternalError::RecordWriteOverflow => { - write!(f, "Attempted to write a record beyond the range of the underlying buffer.") - }, + write!( + f, + "Attempted to write a record beyond the range of the underlying buffer." + ) + } InternalError::RecordBadSeek => { write!(f, "Attempted to seek to a Position larger than the length of the underlying buffer.") } From 01196a8eb3749f23aa35d6236b8681c810d240d5 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:13:24 +0200 Subject: [PATCH 38/41] chore(request): apply cargo formatting --- rodbus/src/server/request.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/rodbus/src/server/request.rs b/rodbus/src/server/request.rs index 2b9c0e79..f8542ae6 100644 --- a/rodbus/src/server/request.rs +++ b/rodbus/src/server/request.rs @@ -141,9 +141,21 @@ impl<'a> Request<'a> { // And then write them AFTER writing the info objects let device_information = DeviceIdentificationResponse::new(|object_id| { - let base_id = if read.obj_id.is_some() { read.obj_id.unwrap() } else { 0 }; - let request_offset = if object_id.is_some() { object_id.unwrap() } else { 0 }; - handler.read_device_info(read.mei_code, read.dev_id, Some(base_id + request_offset)) + let base_id = if let Some(base_id) = read.obj_id { + base_id + } else { + 0 + }; + let request_offset = if let Some(object_id) = object_id { + object_id + } else { + 0 + }; + handler.read_device_info( + read.mei_code, + read.dev_id, + Some(base_id + request_offset), + ) }); writer.format_reply(header, function, &device_information, level) From 342edb4e64fac5fa4e56777eaab73142345c6ba2 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:14:18 +0200 Subject: [PATCH 39/41] refactor(response): remove unnecessary imports, apply cargo formatting --- rodbus/src/server/response.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rodbus/src/server/response.rs b/rodbus/src/server/response.rs index e7203b95..e2eb301c 100644 --- a/rodbus/src/server/response.rs +++ b/rodbus/src/server/response.rs @@ -1,7 +1,6 @@ use crate::exception::ExceptionCode; -use crate::types::{ReadBitsRange, ReadRegistersRange}; -use crate::DeviceInfo; use crate::server::ServerDeviceInfo; +use crate::types::{ReadBitsRange, ReadRegistersRange}; pub(crate) struct BitWriter where From b032c00d9eb524a627d39108c0e188c919b56cf7 Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:15:14 +0200 Subject: [PATCH 40/41] chore(frame): apply cargo formatting --- rodbus/src/tcp/frame.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/rodbus/src/tcp/frame.rs b/rodbus/src/tcp/frame.rs index 4673d743..47892822 100644 --- a/rodbus/src/tcp/frame.rs +++ b/rodbus/src/tcp/frame.rs @@ -1,5 +1,7 @@ use crate::common::buffer::ReadBuffer; -use crate::common::frame::{Frame, FrameHeader, FrameInfo, FrameRecords, FrameType, FunctionField, TxId}; +use crate::common::frame::{ + Frame, FrameHeader, FrameInfo, FrameRecords, FrameType, FunctionField, TxId, +}; use crate::common::traits::Serialize; use crate::decode::FrameDecodeLevel; use crate::error::{FrameParseError, RequestError}; @@ -150,7 +152,7 @@ pub(crate) fn format_mbap( msg.serialize(cursor, Some(&mut records))?; if !records.records_empty() { - return Err(RequestError::FrameRecorderNotEmpty) + return Err(RequestError::FrameRecorderNotEmpty); } let end_pdu = cursor.position(); @@ -225,7 +227,11 @@ mod tests { } impl Serialize for MockBody { - fn serialize(&self, cursor: &mut WriteCursor, records: Option<&mut FrameRecords>) -> Result<(), RequestError> { + fn serialize( + &self, + cursor: &mut WriteCursor, + records: Option<&mut FrameRecords>, + ) -> Result<(), RequestError> { for b in self.body { cursor.write_u8(*b)?; } From 0ec01f4a7b18af5e9bcc7e86102ab069a3ef9f8d Mon Sep 17 00:00:00 2001 From: Kay Grewe Date: Wed, 22 May 2024 12:16:13 +0200 Subject: [PATCH 41/41] chore(e2e_read_device): remove commented code, apply cargo formatting --- rodbus/tests/integration_test_read_device.rs | 30 +++----------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/rodbus/tests/integration_test_read_device.rs b/rodbus/tests/integration_test_read_device.rs index 59a44ca2..e8c8cc09 100644 --- a/rodbus/tests/integration_test_read_device.rs +++ b/rodbus/tests/integration_test_read_device.rs @@ -7,8 +7,8 @@ use rodbus::client::*; use rodbus::server::*; use rodbus::*; -use tokio::runtime::Runtime; use rodbus::DeviceConformityLevel::ExtendedIdentificationIndividual; +use tokio::runtime::Runtime; struct Handler { pub device_conformity_level: DeviceConformityLevel, @@ -81,9 +81,7 @@ impl Handler { read_dev_id: ReadDeviceCode, object_id: u8, ) -> Result { - - - let (min_range, max_range) = match read_dev_id { + let (_, max_range) = match read_dev_id { ReadDeviceCode::BasicStreaming => (0x00, 0x03), ReadDeviceCode::RegularStreaming => (0x03, 0x7F), ReadDeviceCode::ExtendedStreaming => (0x80, 0xFF), @@ -96,23 +94,6 @@ impl Handler { _ => unreachable!(), }; - /*let mut modbus_response: Vec = vec![]; - for (idx, info_object) in data.iter().skip(object_id as usize).enumerate() { - let modbus_object = match info_object { - Some(value) => value.as_bytes(), /*RawModbusInfoObject::new( - read_dev_id, - object_id + idx as u8, - value.len() as u8, - value.as_bytes(), - ),*/ - None => continue, - }; - - modbus_response.extend_from_slice(modbus_object); - }*/ - - let length = Handler::message_count_from_area_slice(data) as u8; - let next_object_id = if (object_id + 1) >= max_range { None } else { @@ -123,10 +104,7 @@ impl Handler { } }; - //let mut device_info_response = - // DeviceInfo::new(mei_code, read_dev_id, self.device_conformity_level, length); - - let mut server = ServerDeviceInfo { + let server = ServerDeviceInfo { read_device_code: read_dev_id, conformity_level: ExtendedIdentificationIndividual, current_object_id: object_id, @@ -156,7 +134,7 @@ impl Handler { object_data: data, }) } else { - return Err(ExceptionCode::IllegalDataAddress) + return Err(ExceptionCode::IllegalDataAddress); } } }