Skip to content
This repository has been archived by the owner on May 18, 2022. It is now read-only.

Commit

Permalink
Initial Build
Browse files Browse the repository at this point in the history
  • Loading branch information
jonas-schievink committed Mar 25, 2019
1 parent 4a901dc commit 04cf1d1
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 44 deletions.
3 changes: 3 additions & 0 deletions src/ble/link/advertising.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,9 @@ impl Header {
Header(u8::from(ty) as u16)
}

/// Parses a header from raw bytes.
///
/// This will panic if `raw` contains less than 2 Bytes.
pub fn parse(raw: &[u8]) -> Self {
Header(LittleEndian::read_u16(&raw))
}
Expand Down
83 changes: 47 additions & 36 deletions src/ble/link/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ use {
time::{Duration, Instant, Timer},
utils::HexSlice,
},
core::marker::PhantomData,
core::{marker::PhantomData, mem},
};

/// Connection state.
pub struct Connection<L: Logger, T: Timer> {
pub struct Connection<L: Logger, T: Timer, R: Transmitter> {
access_address: u32,
crc_init: u32,
channel_map: ChannelMap,
Expand Down Expand Up @@ -44,12 +44,20 @@ pub struct Connection<L: Logger, T: Timer> {
last_header: data::Header,

/// Whether we have ever received a data packet in this connection.
///
/// If this is `true`, the connection is considered established, which changes the handling of
/// the supervision timeout.
received_packet: bool,

_p: PhantomData<(L, T)>,
next_packet: Pdu<'static>,
wants_to_send: bool,

master_md: bool,

_p: PhantomData<(L, T, R)>,
}

impl<L: Logger, T: Timer> Connection<L, T> {
impl<L: Logger, T: Timer, R: Transmitter> Connection<L, T, R> {
/// Initializes a connection state according to the `LLData` contained in the `CONNECT_REQ`
/// advertising PDU.
///
Expand Down Expand Up @@ -80,6 +88,9 @@ impl<L: Logger, T: Timer> Connection<L, T> {
next_expected_seq_num: SeqNum::ZERO,
last_header: Header::new(Llid::DataCont),
received_packet: false,
next_packet: Pdu::empty(),
wants_to_send: false,
master_md: false,

_p: PhantomData,
};
Expand All @@ -104,10 +115,9 @@ impl<L: Logger, T: Timer> Connection<L, T> {
/// Called by the `LinkLayer` when a data channel packet is received.
///
/// Returns `Err(())` when the connection is ended (not necessarily due to an error condition).
pub fn process_data_packet<R: Transmitter>(
pub fn process_data_packet(
&mut self,
rx_end: Instant,
tx: &mut R,
hw: &mut HwInterface<L, T>,
header: data::Header,
payload: &[u8],
Expand All @@ -126,25 +136,12 @@ impl<L: Logger, T: Timer> Connection<L, T> {
// If CRC is bad, this bit could be flipped, so we always retransmit in that case.
if self.received_packet {
self.last_header.set_nesn(self.next_expected_seq_num);
let d = hw.timer.now().duration_since(rx_end);
tx.transmit_data(
self.access_address,
self.crc_init,
self.last_header,
self.channel,
);
let before_log = hw.timer.now();
trace!(hw.logger, "<<RESEND {} after RX>>", d);
trace!(
hw.logger,
"<<That LOG took {}>>",
hw.timer.now().duration_since(before_log)
);
//hw.logger.write_str("<<RESEND>>\n").unwrap();
} else {
// We've never received (and thus sent) a data packet before, so we can't
// *re*transmit anything. Send empty PDU instead.
self.received_packet = true;
self.send(Pdu::empty(), tx, &mut hw.logger);
self.next_packet = Pdu::empty();
}
} else {
self.received_packet = true;
Expand All @@ -154,40 +151,54 @@ impl<L: Logger, T: Timer> Connection<L, T> {

self.transmit_seq_num += SeqNum::ONE;

// Send a new packet
self.send(Pdu::empty(), tx, &mut hw.logger);
// Prepare sending a new packet
self.next_packet = Pdu::empty();
}

let last_channel = self.channel;

// If both devices set MD to `false`, the connection event closes and we hop to the next
// channel.
// If the CRC is bad, we must hop anyways.
if !crc_ok || (!header.md() && !self.has_more_data()) {
self.hop_channel();
}
// If the CRC is bad, we hop channels, pretending that MD=false
self.master_md = crc_ok && header.md();

trace!(
/*trace!(
hw.logger,
"DATA({}->{})<- {}{:?}, {:?}",
last_channel.index(),
self.channel.index(),
if crc_ok { "" } else { "BADCRC, " },
header,
HexSlice(payload)
);

);*/

// After receiving a packet from the master, we *always* send one back. Set a timer that
// expires after the IFS is over.
self.wants_to_send = true;
let send_at = rx_end + Duration::T_IFS;
let d = send_at.duration_since(hw.timer.now());
trace!(hw.logger, "DATA<-; {}; sending in {}", self.master_md, d);
Ok(Cmd {
next_update: NextUpdate::At(hw.timer.now() + self.conn_event_timeout()),
radio: RadioCmd::ListenData {
next_update: NextUpdate::At(send_at),
radio: RadioCmd::PrepareTx {
channel: self.channel,
access_address: self.access_address,
crc_init: self.crc_init,
},
})
}

pub fn timer_update(&mut self, hw: &mut HwInterface<L, T>) -> Result<Cmd, ()> {
pub fn timer_update(&mut self, tx: &mut R, hw: &mut HwInterface<L, T>) -> Result<Cmd, ()> {
if self.wants_to_send {
self.wants_to_send = false;
// Send a response PDU to the master
let pdu = mem::replace(&mut self.next_packet, Pdu::empty());
self.send(pdu, tx, &mut hw.logger);

// Possibly hop channels here
if !self.master_md && !self.has_more_data() {
self.hop_channel();
}
}

if self.received_packet {
// No packet from master, skip this connection event and listen on the next channel

Expand Down Expand Up @@ -249,7 +260,7 @@ impl<L: Logger, T: Timer> Connection<L, T> {
}

/// Sends a new PDU to the connected device (ie. a non-retransmitted PDU).
fn send<R: Transmitter>(&mut self, pdu: Pdu<'_>, tx: &mut R, logger: &mut L) {
fn send(&mut self, pdu: Pdu<'_>, tx: &mut R, logger: &mut L) {
let mut payload_writer = ByteWriter::new(tx.tx_payload_buf());
// Serialize PDU. This should never fail, because the upper layers are supposed to fragment
// packets so they always fit.
Expand Down
17 changes: 11 additions & 6 deletions src/ble/link/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ pub struct HwInterface<L: Logger, T: Timer> {
}

/// Link-Layer state machine, according to the Bluetooth spec.
enum State<L: Logger, T: Timer> {
enum State<L: Logger, T: Timer, R: Transmitter> {
/// Radio silence: Not listening, not transmitting anything.
Standby,

Expand All @@ -198,15 +198,15 @@ enum State<L: Logger, T: Timer> {
},

/// Connected with another device.
Connection(Connection<L, T>),
Connection(Connection<L, T, R>),
}

/// Implementation of the BLE Link-Layer logic.
///
/// Users of this struct must provide a way to send and receive Link-Layer PDUs via a `Transmitter`.
pub struct LinkLayer<L: Logger, T: Timer, R: Transmitter> {
dev_addr: DeviceAddress,
state: State<L, T>,
state: State<L, T, R>,
hw: HwInterface<L, T>,
_p: PhantomData<R>,
}
Expand Down Expand Up @@ -334,13 +334,12 @@ impl<L: Logger, T: Timer, R: Transmitter> LinkLayer<L, T, R> {
pub fn process_data_packet(
&mut self,
rx_end: Instant,
tx: &mut R,
header: data::Header,
payload: &[u8],
crc_ok: bool,
) -> Cmd {
if let State::Connection(conn) = &mut self.state {
match conn.process_data_packet(rx_end, tx, &mut self.hw, header, payload, crc_ok) {
match conn.process_data_packet(rx_end, &mut self.hw, header, payload, crc_ok) {
Ok(cmd) => cmd,
Err(()) => {
debug!(self.logger(), "connection ended, standby");
Expand Down Expand Up @@ -390,7 +389,7 @@ impl<L: Logger, T: Timer, R: Transmitter> LinkLayer<L, T, R> {
next_update: NextUpdate::At(*next_adv),
}
}
State::Connection(conn) => match conn.timer_update(&mut self.hw) {
State::Connection(conn) => match conn.timer_update(tx, &mut self.hw) {
Ok(cmd) => cmd,
Err(()) => {
debug!(self.logger(), "connection ended (timer), standby");
Expand Down Expand Up @@ -479,6 +478,12 @@ pub enum RadioCmd {
/// Only the least significant 24 bits are relevant.
crc_init: u32,
},

PrepareTx {
channel: DataChannel,
access_address: u32,
crc_init: u32,
},
}

/// Trait for Link Layer packet transmission.
Expand Down
3 changes: 3 additions & 0 deletions src/ble/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ use core::{
pub struct Duration(u32);

impl Duration {
/// The interframe spacing used by BLE packets (`T_IFS`).
pub const T_IFS: Self = Duration(150);

/// Creates a `Duration` from a number of microseconds.
pub fn from_micros(micros: u32) -> Self {
Duration(micros)
Expand Down
4 changes: 2 additions & 2 deletions src/radio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl BleRadio {
self.radio.events_disabled.reset();

match cmd {
RadioCmd::Off => {}
RadioCmd::Off | RadioCmd::PrepareTx { .. } => {}
RadioCmd::ListenAdvertising { channel } => {
self.prepare_txrx_advertising(channel);

Expand Down Expand Up @@ -259,7 +259,7 @@ impl BleRadio {
return NextUpdate::Keep;
}
};
let cmd = ll.process_data_packet(timestamp, self, header, payload, crc_ok);
let cmd = ll.process_data_packet(timestamp, header, payload, crc_ok);
self.rx_buf = Some(rx_buf);
cmd
};
Expand Down

0 comments on commit 04cf1d1

Please sign in to comment.