Skip to content

Commit

Permalink
refactor(frame): add FrameRecords struct and change serialize trait.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kay Grewe authored and Kay Grewe committed Feb 27, 2024
1 parent 6f4e62d commit 274399f
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 28 deletions.
3 changes: 2 additions & 1 deletion rodbus/src/client/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand Down
43 changes: 43 additions & 0 deletions rodbus/src/common/frame.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashSet;
use crate::common::phys::PhysLayer;
use std::ops::Range;

Expand Down Expand Up @@ -251,6 +252,10 @@ impl FormatType {
}
}

pub(crate) struct FrameRecords {
records: HashSet<usize>,
}

pub(crate) struct FrameWriter {
format_type: FormatType,
buffer: [u8; constants::MAX_FRAME_LENGTH],
Expand Down Expand Up @@ -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)
Expand Down
65 changes: 44 additions & 21 deletions rodbus/src/common/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8, InternalError> {
Expand All @@ -33,7 +34,7 @@ pub(crate) fn calc_bytes_for_registers(num_registers: usize) -> Result<u8, Inter
}

impl Serialize for AddressRange {
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.start)?;
cur.write_u16_be(self.count)?;
Ok(())
Expand All @@ -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<bool> {
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(())
Expand Down Expand Up @@ -106,7 +107,7 @@ impl Loggable for Indexed<bool> {
}

impl Serialize for Indexed<u16> {
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(())
Expand Down Expand Up @@ -141,7 +142,7 @@ impl Loggable for Indexed<u16> {
}

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())?;

Expand All @@ -165,7 +166,7 @@ impl<T> Serialize for BitWriter<T>
where
T: Fn(u16) -> Result<bool, crate::exception::ExceptionCode>,
{
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)?;
Expand Down Expand Up @@ -228,7 +229,7 @@ impl<T> Serialize for RegisterWriter<T>
where
T: Fn(u16) -> Result<u16, crate::exception::ExceptionCode>,
{
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)?;
Expand Down Expand Up @@ -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)?;

Expand All @@ -283,21 +284,21 @@ impl Serialize for &[u16] {
}

impl Serialize for WriteMultiple<bool> {
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<u16> {
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)?;

Expand All @@ -315,7 +316,7 @@ impl<'a, T> Serialize for DeviceIdentificationResponse<'a, T>
where
T: Fn(Option<u8>) -> Result<ServerDeviceInfo<'a>, 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 !
Expand Down Expand Up @@ -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;
Expand All @@ -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];
Expand Down Expand Up @@ -448,7 +471,7 @@ where
}

impl Serialize for Option<u8> {
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 {
Expand All @@ -466,7 +489,7 @@ impl Serialize for Option<u8> {
}

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())?;

Expand Down
11 changes: 7 additions & 4 deletions rodbus/src/serial/frame.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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());
Expand Down
10 changes: 8 additions & 2 deletions rodbus/src/tcp/frame.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 274399f

Please sign in to comment.