bt_rfcomm/frame/mux_commands/
remote_port_negotiation.rsuse bitfield::bitfield;
use packet_encoding::{Decodable, Encodable};
use crate::frame::FrameParseError;
use crate::DLCI;
const REMOTE_PORT_NEGOTIATION_SHORT_LENGTH: usize = 1;
const REMOTE_PORT_NEGOTIATION_LONG_LENGTH: usize = 8;
const REMOTE_PORT_NEGOTIATION_VALUES_LENGTH: usize = 7;
bitfield! {
struct RpnAddressField(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 RpnAddressField {
fn dlci(&self) -> Result<DLCI, FrameParseError> {
DLCI::try_from(self.dlci_raw())
}
}
const PORT_VALUES_UNANIMOUS_ACCEPT_MASK: u16 = 0b0011111101111111;
bitfield! {
pub struct PortValues([u8]);
impl Debug;
pub u8, baud_rate, set_baud_rate: 7, 0;
pub u8, data_bits, set_data_bits: 9, 8;
pub bool, stop_bit, set_stop_bit: 10;
pub bool, parity, set_parity: 11;
pub u8, parity_type, set_parity_type: 13, 12;
pub u8, flow_control, set_flow_control: 21, 16;
pub u8, xon_character, set_xon_character: 31, 24;
pub u8, xoff_character, set_xoff_character: 39, 32;
pub u16, mask, set_mask: 55, 40;
}
impl PartialEq for PortValues<[u8; REMOTE_PORT_NEGOTIATION_VALUES_LENGTH]> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Clone for PortValues<[u8; REMOTE_PORT_NEGOTIATION_VALUES_LENGTH]> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl Default for PortValues<[u8; REMOTE_PORT_NEGOTIATION_VALUES_LENGTH]> {
fn default() -> Self {
let mut values = PortValues([0; REMOTE_PORT_NEGOTIATION_VALUES_LENGTH]);
values.set_baud_rate(0x03);
values.set_data_bits(0b11);
values.set_stop_bit(false);
values.set_parity(false);
values.set_parity_type(0); values.set_flow_control(0x00);
values.set_xon_character(0x01);
values.set_xoff_character(0x03);
values.set_mask(0x00); values
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct RemotePortNegotiationParams {
pub dlci: DLCI,
pub port_values: Option<PortValues<[u8; REMOTE_PORT_NEGOTIATION_VALUES_LENGTH]>>,
}
impl RemotePortNegotiationParams {
pub fn response(&self) -> Self {
let port_values =
self.port_values.clone().map_or_else(PortValues::default, |mut values| {
values.set_mask(PORT_VALUES_UNANIMOUS_ACCEPT_MASK);
values
});
Self { dlci: self.dlci, port_values: Some(port_values) }
}
}
impl Decodable for RemotePortNegotiationParams {
type Error = FrameParseError;
fn decode(buf: &[u8]) -> Result<Self, FrameParseError> {
if buf.len() != REMOTE_PORT_NEGOTIATION_SHORT_LENGTH
&& buf.len() != REMOTE_PORT_NEGOTIATION_LONG_LENGTH
{
return Err(FrameParseError::InvalidBufferLength(
REMOTE_PORT_NEGOTIATION_SHORT_LENGTH,
buf.len(),
));
}
let address_field = RpnAddressField(buf[0]);
let dlci = address_field.dlci()?;
let port_values = if buf.len() == REMOTE_PORT_NEGOTIATION_SHORT_LENGTH {
None
} else {
let mut b = [0; REMOTE_PORT_NEGOTIATION_VALUES_LENGTH];
b.copy_from_slice(&buf[1..REMOTE_PORT_NEGOTIATION_LONG_LENGTH]);
Some(PortValues(b))
};
Ok(RemotePortNegotiationParams { dlci, port_values })
}
}
impl Encodable for RemotePortNegotiationParams {
type Error = FrameParseError;
fn encoded_len(&self) -> usize {
if self.port_values.is_some() {
REMOTE_PORT_NEGOTIATION_LONG_LENGTH
} else {
REMOTE_PORT_NEGOTIATION_SHORT_LENGTH
}
}
fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
if buf.len() < self.encoded_len() {
return Err(FrameParseError::BufferTooSmall);
}
let mut address_field = RpnAddressField(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;
if let Some(port_values) = &self.port_values {
buf[1..REMOTE_PORT_NEGOTIATION_LONG_LENGTH].copy_from_slice(&port_values.0);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
#[test]
fn test_decode_rpn_invalid_buf() {
let buf = [0x00, 0x01, 0x02]; assert_matches!(
RemotePortNegotiationParams::decode(&buf[..]),
Err(FrameParseError::InvalidBufferLength(REMOTE_PORT_NEGOTIATION_SHORT_LENGTH, 3))
);
}
#[test]
fn test_decode_rpn_invalid_dlci() {
let buf = [
0b00000111, ];
assert_matches!(
RemotePortNegotiationParams::decode(&buf[..]),
Err(FrameParseError::InvalidDLCI(1))
);
}
#[test]
fn test_decode_rpn_short_command() {
let buf = [
0b00011111, ];
let expected =
RemotePortNegotiationParams { dlci: DLCI::try_from(7).unwrap(), port_values: None };
assert_eq!(RemotePortNegotiationParams::decode(&buf[..]).unwrap(), expected);
}
#[test]
fn test_decode_rpn_long_command() {
let port_values_buf: [u8; REMOTE_PORT_NEGOTIATION_VALUES_LENGTH] = [
0b00000001, 0b00101011, 0b00011010, 0b00000001, 0b00000011, 0b10000001, 0b00000001, ];
let buf = vec![
0b00011111, ];
let buf = [buf, port_values_buf.to_vec()].concat();
let expected = RemotePortNegotiationParams {
dlci: DLCI::try_from(7).unwrap(),
port_values: Some(PortValues(port_values_buf)),
};
let decoded = RemotePortNegotiationParams::decode(&buf[..]).unwrap();
assert_eq!(decoded, expected);
let decoded_port_values = decoded.port_values.unwrap();
assert_eq!(decoded_port_values.baud_rate(), 1);
assert_eq!(decoded_port_values.data_bits(), 0b11);
assert_eq!(decoded_port_values.stop_bit(), false);
assert_eq!(decoded_port_values.parity(), true);
assert_eq!(decoded_port_values.parity_type(), 2);
assert_eq!(decoded_port_values.flow_control(), 26);
assert_eq!(decoded_port_values.xon_character(), 1);
assert_eq!(decoded_port_values.xoff_character(), 3);
assert_eq!(decoded_port_values.mask(), 385);
}
#[test]
fn test_encode_rpn_invalid_buf() {
let port_values_buf: [u8; REMOTE_PORT_NEGOTIATION_VALUES_LENGTH] =
[0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000];
let command = RemotePortNegotiationParams {
dlci: DLCI::try_from(7).unwrap(),
port_values: Some(PortValues(port_values_buf)),
};
let mut buf = [];
assert_matches!(command.encode(&mut buf), Err(FrameParseError::BufferTooSmall));
}
#[test]
fn test_encode_rpn_short_command() {
let command =
RemotePortNegotiationParams { dlci: DLCI::try_from(2).unwrap(), port_values: None };
let mut buf = vec![0; command.encoded_len()];
let expected = [0b00001011]; assert!(command.encode(&mut buf).is_ok());
assert_eq!(buf, expected);
}
#[test]
fn test_encode_rpn_long_command() {
let port_values_buf: [u8; REMOTE_PORT_NEGOTIATION_VALUES_LENGTH] = [
0b00010000, 0b00111100, 0b00000010, 0b00000001, 0b00000011, 0b00000000, 0b00000000, ];
let command = RemotePortNegotiationParams {
dlci: DLCI::try_from(9).unwrap(),
port_values: Some(PortValues(port_values_buf)),
};
let mut buf = vec![0; command.encoded_len()];
assert!(command.encode(&mut buf).is_ok());
let expected = vec![0b00100111]; let expected = [expected, port_values_buf.to_vec()].concat();
assert_eq!(buf, expected);
}
}