Skip to content

Commit 704f1bf

Browse files
committed
add initial version of the implementation
1 parent 86f0b4e commit 704f1bf

File tree

12 files changed

+564
-12
lines changed

12 files changed

+564
-12
lines changed

.github/workflows/CI.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ jobs:
2222
- uses: actions-rs/cargo@v1
2323
with:
2424
command: build
25-
- uses: actions-rs/cargo@v1
26-
with:
27-
command: test
25+
# no tests at the moment as the crate currently targets the stm32f4xx-hal and thus can't run on x86
2826
- uses: actions-rs/cargo@v1
2927
with:
3028
command: fmt

Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,14 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9+
cortex-m = { version = "0.7", features = ["critical-section-single-core"]}
10+
cortex-m-rtic = "1.1.3"
11+
12+
stm32f4xx-hal = { version = "0.13.2", features = ["stm32f401"] }
13+
14+
fugit = "0.3"
15+
16+
defmt = "0.3.2"
17+
defmt-rtt = "0.4"
18+
19+
heapless = { version = "0.7", features = ["defmt-impl"] }

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Adafruit Bluefruit LE UART Friend Rust Driver
2+
Currently written directly against the stm32f4xx-hal but hopefully this can be rewritten against the embedded-hal traits.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use super::{try_f32_from_le_bytes, ProtocolParseError};
2+
3+
/// Represents an accelerometer event from the protocol.
4+
#[derive(Debug, defmt::Format)]
5+
pub struct AccelerometerEvent {
6+
x: f32,
7+
y: f32,
8+
z: f32,
9+
}
10+
11+
impl TryFrom<&[u8]> for AccelerometerEvent {
12+
type Error = ProtocolParseError;
13+
14+
/// Parse the data section of an accelerometer event.
15+
///
16+
/// The full command is not validated here, identifying the command as an accelerometer event and CRC validation is the responsibility of the caller!
17+
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
18+
let expected_len = 3 * super::BYTES_PER_FLOAT;
19+
if input.len() != expected_len {
20+
Err(ProtocolParseError::InvalidLength(expected_len, input.len()))
21+
} else {
22+
Ok(AccelerometerEvent {
23+
x: try_f32_from_le_bytes(&input[0..4])?,
24+
y: try_f32_from_le_bytes(&input[4..8])?,
25+
z: try_f32_from_le_bytes(&input[8..12])?,
26+
})
27+
}
28+
}
29+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use super::ProtocolParseError;
2+
3+
/// Errors which can be raised while parsing a button event.
4+
#[derive(Debug, defmt::Format)]
5+
pub enum ButtonParseError {
6+
UnknownButton(u8),
7+
UnknownButtonState(u8),
8+
}
9+
10+
/// Lists all possible buttons which can be sent in the event.
11+
#[derive(Debug, defmt::Format)]
12+
pub enum Button {
13+
Button1,
14+
Button2,
15+
Button3,
16+
Button4,
17+
Up,
18+
Down,
19+
Left,
20+
Right,
21+
}
22+
23+
impl Button {
24+
/// Maps the ID in the protocol to the [`Button`].
25+
pub fn from_id(input: &u8) -> Result<Button, ButtonParseError> {
26+
match input {
27+
b'1' => Ok(Button::Button1),
28+
b'2' => Ok(Button::Button2),
29+
b'3' => Ok(Button::Button3),
30+
b'4' => Ok(Button::Button4),
31+
b'5' => Ok(Button::Up),
32+
b'6' => Ok(Button::Down),
33+
b'7' => Ok(Button::Left),
34+
b'8' => Ok(Button::Right),
35+
_ => Err(ButtonParseError::UnknownButton(input.clone())),
36+
}
37+
}
38+
}
39+
40+
/// The state of the button.
41+
#[derive(Debug, defmt::Format)]
42+
pub enum ButtonState {
43+
Released,
44+
Pressed,
45+
}
46+
47+
impl ButtonState {
48+
/// Maps the ID in the protocol to the [`ButtonState`].
49+
pub fn from_id(input: &u8) -> Result<ButtonState, ButtonParseError> {
50+
match input {
51+
b'0' => Ok(ButtonState::Released),
52+
b'1' => Ok(ButtonState::Pressed),
53+
_ => Err(ButtonParseError::UnknownButtonState(input.clone())),
54+
}
55+
}
56+
}
57+
58+
/// Represents a button event from the protocol.
59+
#[derive(Debug, defmt::Format)]
60+
pub struct ButtonEvent {
61+
button: Button,
62+
state: ButtonState,
63+
}
64+
65+
impl TryFrom<&[u8]> for ButtonEvent {
66+
type Error = ProtocolParseError;
67+
68+
/// Parse the data section of a button command.
69+
///
70+
/// The full command is not validated here, identifying the command as a button command and CRC validation is the responsibility of the caller!
71+
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
72+
let expected_len = 2;
73+
if input.len() != expected_len {
74+
Err(ProtocolParseError::InvalidLength(expected_len, input.len()))
75+
} else {
76+
Ok(ButtonEvent {
77+
button: Button::from_id(&input[0])
78+
.map_err(|e| ProtocolParseError::ButtonParseError(e))?,
79+
state: ButtonState::from_id(&input[1])
80+
.map_err(|e| ProtocolParseError::ButtonParseError(e))?,
81+
})
82+
}
83+
}
84+
}

src/bluefruit_protocol/color_event.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use super::ProtocolParseError;
2+
3+
/// Represents a color event from the protocol.
4+
#[derive(Debug, defmt::Format)]
5+
pub struct ColorEvent {
6+
red: u8,
7+
green: u8,
8+
blue: u8,
9+
}
10+
11+
impl TryFrom<&[u8]> for ColorEvent {
12+
type Error = ProtocolParseError;
13+
14+
/// Parse the data section of a color event.
15+
///
16+
/// The full command is not validated here, identifying the command as a color event and CRC validation is the responsibility of the caller!
17+
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
18+
let expected_len = 3;
19+
if input.len() != expected_len {
20+
Err(ProtocolParseError::InvalidLength(expected_len, input.len()))
21+
} else {
22+
Ok(ColorEvent {
23+
red: input[0],
24+
green: input[1],
25+
blue: input[2],
26+
})
27+
}
28+
}
29+
}

src/bluefruit_protocol/gyro_event.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use super::{try_f32_from_le_bytes, ProtocolParseError};
2+
3+
/// Represents a gyro event from the protocol.
4+
#[derive(Debug, defmt::Format)]
5+
pub struct GyroEvent {
6+
x: f32,
7+
y: f32,
8+
z: f32,
9+
}
10+
11+
impl TryFrom<&[u8]> for GyroEvent {
12+
type Error = ProtocolParseError;
13+
14+
/// Parse the data section of a gyro event.
15+
///
16+
/// The full command is not validated here, identifying the command as a gyro event and CRC validation is the responsibility of the caller!
17+
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
18+
let expected_len = 3 * super::BYTES_PER_FLOAT;
19+
if input.len() != expected_len {
20+
Err(ProtocolParseError::InvalidLength(expected_len, input.len()))
21+
} else {
22+
Ok(GyroEvent {
23+
x: try_f32_from_le_bytes(&input[0..4])?,
24+
y: try_f32_from_le_bytes(&input[4..8])?,
25+
z: try_f32_from_le_bytes(&input[8..12])?,
26+
})
27+
}
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use super::{try_f32_from_le_bytes, ProtocolParseError};
2+
3+
/// Represents a location event from the protocol.
4+
#[derive(Debug, defmt::Format)]
5+
pub struct LocationEvent {
6+
latitude: f32,
7+
longitude: f32,
8+
altitude: f32,
9+
}
10+
11+
impl TryFrom<&[u8]> for LocationEvent {
12+
type Error = ProtocolParseError;
13+
14+
/// Parse the data section of a location event.
15+
///
16+
/// The full command is not validated here, identifying the command as a location event and CRC validation is the responsibility of the caller!
17+
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
18+
let expected_len = 3 * super::BYTES_PER_FLOAT;
19+
if input.len() != expected_len {
20+
Err(ProtocolParseError::InvalidLength(expected_len, input.len()))
21+
} else {
22+
Ok(LocationEvent {
23+
latitude: try_f32_from_le_bytes(&input[0..4])?,
24+
longitude: try_f32_from_le_bytes(&input[4..8])?,
25+
altitude: try_f32_from_le_bytes(&input[8..12])?,
26+
})
27+
}
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use super::{try_f32_from_le_bytes, ProtocolParseError};
2+
3+
/// Represents a magnetometer event from the protocol.
4+
#[derive(Debug, defmt::Format)]
5+
pub struct MagnetometerEvent {
6+
x: f32,
7+
y: f32,
8+
z: f32,
9+
}
10+
11+
impl TryFrom<&[u8]> for MagnetometerEvent {
12+
type Error = ProtocolParseError;
13+
14+
/// Parse the data section of a magnetometer event.
15+
///
16+
/// The full command is not validated here, identifying the command as a magnetometer event and CRC validation is the responsibility of the caller!
17+
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
18+
let expected_len = 3 * super::BYTES_PER_FLOAT;
19+
if input.len() != expected_len {
20+
Err(ProtocolParseError::InvalidLength(expected_len, input.len()))
21+
} else {
22+
Ok(MagnetometerEvent {
23+
x: try_f32_from_le_bytes(&input[0..4])?,
24+
y: try_f32_from_le_bytes(&input[4..8])?,
25+
z: try_f32_from_le_bytes(&input[8..12])?,
26+
})
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)