bt_rfcomm/frame/mux_commands/
remote_line_status.rsuse bitfield::bitfield;
use packet_encoding::{decodable_enum, Decodable, Encodable};
use crate::frame::FrameParseError;
use crate::DLCI;
const REMOTE_LINE_STATUS_COMMAND_LENGTH: usize = 2;
bitfield! {
struct RlsAddressField(u8);
impl Debug;
pub bool, ea_bit, set_ea_bit: 0;
pub bool, cr_bit, set_cr_bit: 1;
pub u8, dlci_raw, set_dlci: 7, 2;
}
impl RlsAddressField {
fn dlci(&self) -> Result<DLCI, FrameParseError> {
DLCI::try_from(self.dlci_raw())
}
}
decodable_enum! {
pub enum RlsError<u8, FrameParseError, OutOfRange> {
Overrun = 0b001,
Parity = 0b010,
Framing = 0b100,
}
}
bitfield! {
pub struct RlsErrorField(u8);
impl Debug;
pub bool, error_occurred, set_error_occurred: 0;
pub u8, error, set_error: 3,1;
}
impl RlsErrorField {
fn from_error(error: RlsError) -> Self {
let mut field = Self(0);
field.set_error_occurred(true);
field.set_error(u8::from(&error));
field
}
const fn no_error() -> Self {
Self(0)
}
}
impl PartialEq for RlsErrorField {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Clone for RlsErrorField {
fn clone(&self) -> Self {
Self(self.0)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct RemoteLineStatusParams {
pub dlci: DLCI,
pub status: RlsErrorField,
}
impl RemoteLineStatusParams {
pub fn new(dlci: DLCI, status: Option<RlsError>) -> Self {
let status = if let Some(e) = status {
RlsErrorField::from_error(e)
} else {
RlsErrorField::no_error()
};
Self { dlci, status }
}
}
impl Decodable for RemoteLineStatusParams {
type Error = FrameParseError;
fn decode(buf: &[u8]) -> Result<Self, FrameParseError> {
if buf.len() != REMOTE_LINE_STATUS_COMMAND_LENGTH {
return Err(FrameParseError::InvalidBufferLength(
REMOTE_LINE_STATUS_COMMAND_LENGTH,
buf.len(),
));
}
let address_field = RlsAddressField(buf[0]);
let dlci = address_field.dlci()?;
let status = RlsErrorField(buf[1]);
Ok(RemoteLineStatusParams { dlci, status })
}
}
impl Encodable for RemoteLineStatusParams {
type Error = FrameParseError;
fn encoded_len(&self) -> usize {
REMOTE_LINE_STATUS_COMMAND_LENGTH
}
fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
if buf.len() < self.encoded_len() {
return Err(FrameParseError::BufferTooSmall);
}
let mut address_field = RlsAddressField(0);
address_field.set_ea_bit(true);
address_field.set_cr_bit(true);
address_field.set_dlci(u8::from(self.dlci));
buf[0] = address_field.0;
buf[1] = self.status.0;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
#[test]
fn test_decode_rls_invalid_buf() {
let buf = [0x00, 0x01, 0x02]; assert_matches!(
RemoteLineStatusParams::decode(&buf[..]),
Err(FrameParseError::InvalidBufferLength(REMOTE_LINE_STATUS_COMMAND_LENGTH, 3))
);
}
#[test]
fn test_decode_rls_invalid_dlci() {
let buf = [
0b00000111, 0b00000000, ];
assert_matches!(
RemoteLineStatusParams::decode(&buf[..]),
Err(FrameParseError::InvalidDLCI(1))
);
}
#[test]
fn test_decode_rls_no_status() {
let buf = [
0b00001011, 0b00000000, ];
let expected =
RemoteLineStatusParams { dlci: DLCI::try_from(2).unwrap(), status: RlsErrorField(0) };
let res = RemoteLineStatusParams::decode(&buf[..]).unwrap();
assert_eq!(res, expected);
assert_eq!(res.status.error_occurred(), false);
}
#[test]
fn test_decode_rls_with_status() {
let buf = [
0b00001011, 0b00000101, ];
let expected =
RemoteLineStatusParams { dlci: DLCI::try_from(2).unwrap(), status: RlsErrorField(5) };
let res = RemoteLineStatusParams::decode(&buf[..]).unwrap();
assert_eq!(res, expected);
assert_eq!(res.status.error_occurred(), true);
assert_eq!(res.status.error(), 0b010);
}
#[test]
fn test_encode_rls_invalid_buf() {
let command = RemoteLineStatusParams::new(DLCI::try_from(7).unwrap(), None);
let mut buf = [0x01]; assert_matches!(command.encode(&mut buf), Err(FrameParseError::BufferTooSmall));
}
#[test]
fn test_encode_rls_with_no_status() {
let command = RemoteLineStatusParams::new(DLCI::try_from(7).unwrap(), None);
let mut buf = vec![0; command.encoded_len()];
assert!(command.encode(&mut buf).is_ok());
let expected = [
0b00011111, 0b00000000, ];
assert_eq!(buf, expected);
}
#[test]
fn test_encode_rls_with_error_status() {
let errors = vec![RlsError::Overrun, RlsError::Parity, RlsError::Framing];
let expected_error_bits = vec![0b00000011, 0b00000101, 0b00001001];
for (error_status, expected_bits) in errors.into_iter().zip(expected_error_bits.into_iter())
{
let command =
RemoteLineStatusParams::new(DLCI::try_from(7).unwrap(), Some(error_status));
let mut buf = vec![0; command.encoded_len()];
assert!(command.encode(&mut buf).is_ok());
let mut expected = vec![
0b00011111, ];
expected.push(expected_bits);
assert_eq!(buf, expected);
}
}
}