Skip to content

Commit

Permalink
feat: Add support for custom exception codes (#279)
Browse files Browse the repository at this point in the history
  • Loading branch information
CosminPerRam authored Sep 11, 2024
1 parent 903951a commit a5eb819
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 35 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@

# Changelog

## v0.15.0 (Unreleased)

- Added `Exception::Custom` and `Exception::new`.

### Breaking Changes

- Removed `TryFrom<u8>` and `#[repr(u8)]` for Exception.

## v0.14.1 (2024-09-10)

- Implement `Report Server ID` (function code 17).
Expand Down
25 changes: 1 addition & 24 deletions src/codec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,37 +385,14 @@ impl TryFrom<Bytes> for ExceptionResponse {
));
}
let function = fn_err_code - 0x80;
let exception = Exception::try_from(rdr.read_u8()?)?;
let exception = Exception::new(rdr.read_u8()?);
Ok(ExceptionResponse {
function: FunctionCode::new(function),
exception,
})
}
}

impl TryFrom<u8> for Exception {
type Error = Error;

fn try_from(code: u8) -> Result<Self, Self::Error> {
use crate::frame::Exception::*;
let ex = match code {
0x01 => IllegalFunction,
0x02 => IllegalDataAddress,
0x03 => IllegalDataValue,
0x04 => ServerDeviceFailure,
0x05 => Acknowledge,
0x06 => ServerDeviceBusy,
0x08 => MemoryParityError,
0x0A => GatewayPathUnavailable,
0x0B => GatewayTargetDevice,
_ => {
return Err(Error::new(ErrorKind::InvalidData, "Invalid exception code"));
}
};
Ok(ex)
}
}

impl TryFrom<Bytes> for ResponsePdu {
type Error = Error;

Expand Down
67 changes: 56 additions & 11 deletions src/frame/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,26 +387,70 @@ impl Response {

/// A server (slave) exception.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Exception {
IllegalFunction = 0x01,
IllegalDataAddress = 0x02,
IllegalDataValue = 0x03,
ServerDeviceFailure = 0x04,
Acknowledge = 0x05,
ServerDeviceBusy = 0x06,
MemoryParityError = 0x08,
GatewayPathUnavailable = 0x0A,
GatewayTargetDevice = 0x0B,
/// 0x01
IllegalFunction,
/// 0x02
IllegalDataAddress,
/// 0x03
IllegalDataValue,
/// 0x04
ServerDeviceFailure,
/// 0x05
Acknowledge,
/// 0x06
ServerDeviceBusy,
/// 0x08
MemoryParityError,
/// 0x0A
GatewayPathUnavailable,
/// 0x0B
GatewayTargetDevice,
/// None of the above.
///
/// Although encoding one of the predefined values as this is possible, it is not recommended.
/// Instead, prefer to use [`Self::new()`] to prevent such ambiguities.
Custom(u8),
}

impl From<Exception> for u8 {
fn from(from: Exception) -> Self {
from as u8
use crate::frame::Exception::*;
match from {
IllegalFunction => 0x01,
IllegalDataAddress => 0x02,
IllegalDataValue => 0x03,
ServerDeviceFailure => 0x04,
Acknowledge => 0x05,
ServerDeviceBusy => 0x06,
MemoryParityError => 0x08,
GatewayPathUnavailable => 0x0A,
GatewayTargetDevice => 0x0B,
Custom(code) => code,
}
}
}

impl Exception {
/// Create a new [`Exception`] with `value`.
#[must_use]
pub const fn new(value: u8) -> Self {
use crate::frame::Exception::*;

match value {
0x01 => IllegalFunction,
0x02 => IllegalDataAddress,
0x03 => IllegalDataValue,
0x04 => ServerDeviceFailure,
0x05 => Acknowledge,
0x06 => ServerDeviceBusy,
0x08 => MemoryParityError,
0x0A => GatewayPathUnavailable,
0x0B => GatewayTargetDevice,
other => Custom(other),
}
}

pub(crate) fn description(&self) -> &str {
use crate::frame::Exception::*;

Expand All @@ -420,6 +464,7 @@ impl Exception {
MemoryParityError => "Memory parity error",
GatewayPathUnavailable => "Gateway path unavailable",
GatewayTargetDevice => "Gateway target device failed to respond",
Custom(_) => "Custom",
}
}
}
Expand Down

0 comments on commit a5eb819

Please sign in to comment.