bt_rfcomm/frame/mux_commands/
modem_status.rsuse bitfield::bitfield;
use packet_encoding::{Decodable, Encodable};
use crate::frame::FrameParseError;
use crate::DLCI;
const MODEM_STATUS_COMMAND_WITHOUT_BREAK_LENGTH: usize = 2;
const MODEM_STATUS_COMMAND_WITH_BREAK_LENGTH: usize = 3;
bitfield! {
struct ModemStatusAddressField(u8);
impl Debug;
bool;
pub ea_bit, set_ea_bit: 0;
pub cr_bit, set_cr_bit: 1;
pub u8, dlci_raw, set_dlci: 7,2;
}
impl ModemStatusAddressField {
fn dlci(&self) -> Result<DLCI, FrameParseError> {
DLCI::try_from(self.dlci_raw())
}
}
bitfield! {
pub struct ModemStatusSignals(u8);
impl Debug;
bool;
pub ea_bit, set_ea_bit: 0;
pub flow_control, set_flow_control: 1;
pub ready_to_communicate, set_ready_to_communicate: 2;
pub ready_to_receive, set_ready_to_receive: 3;
pub incoming_call, set_incoming_call: 6;
pub data_valid, set_data_valid: 7;
}
impl Clone for ModemStatusSignals {
fn clone(&self) -> Self {
Self(self.0)
}
}
impl Default for ModemStatusSignals {
fn default() -> Self {
let mut signals = Self(0);
signals.set_ea_bit(true); signals.set_flow_control(false); signals.set_ready_to_communicate(true); signals.set_ready_to_receive(true); signals.set_incoming_call(false); signals.set_data_valid(true); signals
}
}
bitfield! {
struct ModemStatusBreakField(u8);
impl Debug;
bool;
pub ea_bit, set_ea_bit: 0;
pub contains_break_value, set_contains_break_value: 1;
pub u8, break_value, set_break_value: 7,4;
}
impl PartialEq for ModemStatusSignals {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ModemStatusParams {
pub dlci: DLCI,
pub signals: ModemStatusSignals,
pub break_value: Option<u8>,
}
impl ModemStatusParams {
pub fn default(dlci: DLCI) -> Self {
Self { dlci, signals: ModemStatusSignals::default(), break_value: None }
}
}
impl Decodable for ModemStatusParams {
type Error = FrameParseError;
fn decode(buf: &[u8]) -> Result<Self, FrameParseError> {
if buf.len() != MODEM_STATUS_COMMAND_WITH_BREAK_LENGTH
&& buf.len() != MODEM_STATUS_COMMAND_WITHOUT_BREAK_LENGTH
{
return Err(FrameParseError::InvalidBufferLength(
MODEM_STATUS_COMMAND_WITH_BREAK_LENGTH,
buf.len(),
));
}
let address_field = ModemStatusAddressField(buf[0]);
let dlci = address_field.dlci()?;
let signals = ModemStatusSignals(buf[1]);
let mut break_value = None;
if buf.len() == MODEM_STATUS_COMMAND_WITH_BREAK_LENGTH {
let value = ModemStatusBreakField(buf[2]);
if value.contains_break_value() {
break_value = Some(value.break_value());
}
}
Ok(Self { dlci, signals, break_value })
}
}
impl Encodable for ModemStatusParams {
type Error = FrameParseError;
fn encoded_len(&self) -> usize {
if self.break_value.is_some() {
MODEM_STATUS_COMMAND_WITH_BREAK_LENGTH
} else {
MODEM_STATUS_COMMAND_WITHOUT_BREAK_LENGTH
}
}
fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
if buf.len() < self.encoded_len() {
return Err(FrameParseError::BufferTooSmall);
}
let mut address_field = ModemStatusAddressField(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;
let mut status_signals_field = ModemStatusSignals(self.signals.0);
let ea_bit = self.break_value.is_none();
status_signals_field.set_ea_bit(ea_bit);
buf[1] = status_signals_field.0;
if self.break_value.is_some() {
let mut break_value_field = ModemStatusBreakField(0);
break_value_field.set_ea_bit(true);
break_value_field.set_contains_break_value(true);
break_value_field.set_break_value(self.break_value.unwrap());
buf[2] = break_value_field.0;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
#[test]
fn test_decode_modem_status_invalid_buf() {
let buf = [];
assert_matches!(
ModemStatusParams::decode(&buf[..]),
Err(FrameParseError::InvalidBufferLength(MODEM_STATUS_COMMAND_WITH_BREAK_LENGTH, 0))
);
}
#[test]
fn test_decode_modem_status_invalid_dlci() {
let buf = [
0b00000111, 0b00000001, ];
assert_matches!(ModemStatusParams::decode(&buf[..]), Err(FrameParseError::InvalidDLCI(1)));
}
#[test]
fn test_decode_modem_status_without_break_value() {
let buf = [
0b00001111, 0b00000001, ];
let expected = ModemStatusParams {
dlci: DLCI::try_from(3).unwrap(),
signals: ModemStatusSignals(1),
break_value: None,
};
assert_eq!(ModemStatusParams::decode(&buf[..]).unwrap(), expected);
}
#[test]
fn test_decode_modem_status_with_empty_break_value() {
let buf = [
0b00001111, 0b00000000, 0b00000001, ];
let expected = ModemStatusParams {
dlci: DLCI::try_from(3).unwrap(),
signals: ModemStatusSignals(0),
break_value: None,
};
assert_eq!(ModemStatusParams::decode(&buf[..]).unwrap(), expected);
}
#[test]
fn test_decode_modem_status_with_break_value() {
let buf = [
0b00011111, 0b11000011, 0b10100011, ];
let expected = ModemStatusParams {
dlci: DLCI::try_from(7).unwrap(),
signals: ModemStatusSignals(195),
break_value: Some(10),
};
assert_eq!(ModemStatusParams::decode(&buf[..]).unwrap(), expected);
}
#[test]
fn test_encode_modem_status_invalid_buf() {
let mut buf = [];
let command = ModemStatusParams {
dlci: DLCI::try_from(5).unwrap(),
signals: ModemStatusSignals(100),
break_value: Some(11),
};
assert_matches!(command.encode(&mut buf[..]), Err(FrameParseError::BufferTooSmall));
}
#[test]
fn test_encode_modem_status_no_break_signal() {
let mut buf = [0; 2];
let command = ModemStatusParams {
dlci: DLCI::try_from(5).unwrap(),
signals: ModemStatusSignals(1),
break_value: None,
};
let expected = [
0b00010111, 0b00000001, ];
assert!(command.encode(&mut buf[..]).is_ok());
assert_eq!(buf, expected);
}
#[test]
fn test_encode_modem_status_with_break_signal() {
let mut buf = [0; 3];
let command = ModemStatusParams {
dlci: DLCI::try_from(6).unwrap(),
signals: ModemStatusSignals(201),
break_value: Some(3),
};
let expected = [
0b00011011, 0b11001000, 0b00110011, ];
assert!(command.encode(&mut buf[..]).is_ok());
assert_eq!(buf, expected);
}
}