#![no_std]
#[cfg(feature = "std")]
extern crate std;
#[cfg(all(feature = "async", feature = "blocking"))]
compile_error!("Can't have both async and blocking enabled");
pub use error::*;
pub use packet::*;
pub use parser::*;
pub use streaming::*;
mod error;
mod packet;
mod parser;
mod streaming;
#[inline(always)]
pub const fn channels_parsing(buffer: &[u8; SBUS_FRAME_LENGTH]) -> [u16; CHANNEL_COUNT] {
[
((buffer[1] as u16) | ((buffer[2] as u16) << 8)) & CHANNEL_MAX,
(((buffer[2] as u16) >> 3) | ((buffer[3] as u16) << 5)) & CHANNEL_MAX,
(((buffer[3] as u16) >> 6) | ((buffer[4] as u16) << 2) | ((buffer[5] as u16) << 10))
& CHANNEL_MAX,
(((buffer[5] as u16) >> 1) | ((buffer[6] as u16) << 7)) & CHANNEL_MAX,
(((buffer[6] as u16) >> 4) | ((buffer[7] as u16) << 4)) & CHANNEL_MAX,
(((buffer[7] as u16) >> 7) | ((buffer[8] as u16) << 1) | ((buffer[9] as u16) << 9))
& CHANNEL_MAX,
(((buffer[9] as u16) >> 2) | ((buffer[10] as u16) << 6)) & CHANNEL_MAX,
(((buffer[10] as u16) >> 5) | ((buffer[11] as u16) << 3)) & CHANNEL_MAX,
((buffer[12] as u16) | ((buffer[13] as u16) << 8)) & CHANNEL_MAX,
(((buffer[13] as u16) >> 3) | ((buffer[14] as u16) << 5)) & CHANNEL_MAX,
(((buffer[14] as u16) >> 6) | ((buffer[15] as u16) << 2) | ((buffer[16] as u16) << 10))
& CHANNEL_MAX,
(((buffer[16] as u16) >> 1) | ((buffer[17] as u16) << 7)) & CHANNEL_MAX,
(((buffer[17] as u16) >> 4) | ((buffer[18] as u16) << 4)) & CHANNEL_MAX,
(((buffer[18] as u16) >> 7) | ((buffer[19] as u16) << 1) | ((buffer[20] as u16) << 9))
& CHANNEL_MAX,
(((buffer[20] as u16) >> 2) | ((buffer[21] as u16) << 6)) & CHANNEL_MAX,
(((buffer[21] as u16) >> 5) | ((buffer[22] as u16) << 3)) & CHANNEL_MAX,
]
}
#[inline(always)]
pub fn pack_channels(buffer: &mut [u8; SBUS_FRAME_LENGTH], channels: &[u16; CHANNEL_COUNT]) {
let mut i = 1;
while i < SBUS_FRAME_LENGTH - 1 {
buffer[i] = 0;
i += 1;
}
let ch = channels;
buffer[1] = (ch[0] & 0xFF) as u8;
buffer[2] = ((ch[0] >> 8) & 0x07) as u8;
buffer[2] |= ((ch[1] & 0x1F) << 3) as u8;
buffer[3] = ((ch[1] >> 5) & 0x3F) as u8;
buffer[3] |= ((ch[2] & 0x03) << 6) as u8;
buffer[4] = ((ch[2] >> 2) & 0xFF) as u8;
buffer[5] = ((ch[2] >> 10) & 0x01) as u8;
buffer[5] |= ((ch[3] & 0x7F) << 1) as u8;
buffer[6] = ((ch[3] >> 7) & 0x0F) as u8;
buffer[6] |= ((ch[4] & 0x0F) << 4) as u8;
buffer[7] = ((ch[4] >> 4) & 0x7F) as u8;
buffer[7] |= ((ch[5] & 0x01) << 7) as u8;
buffer[8] = ((ch[5] >> 1) & 0xFF) as u8;
buffer[9] = ((ch[5] >> 9) & 0x03) as u8;
buffer[9] |= ((ch[6] & 0x3F) << 2) as u8;
buffer[10] = ((ch[6] >> 6) & 0x1F) as u8;
buffer[10] |= ((ch[7] & 0x07) << 5) as u8;
buffer[11] = ((ch[7] >> 3) & 0xFF) as u8;
buffer[12] = (ch[8] & 0xFF) as u8;
buffer[13] = ((ch[8] >> 8) & 0x07) as u8;
buffer[13] |= ((ch[9] & 0x1F) << 3) as u8;
buffer[14] = ((ch[9] >> 5) & 0x3F) as u8;
buffer[14] |= ((ch[10] & 0x03) << 6) as u8;
buffer[15] = ((ch[10] >> 2) & 0xFF) as u8;
buffer[16] = ((ch[10] >> 10) & 0x01) as u8;
buffer[16] |= ((ch[11] & 0x7F) << 1) as u8;
buffer[17] = ((ch[11] >> 7) & 0x0F) as u8;
buffer[17] |= ((ch[12] & 0x0F) << 4) as u8;
buffer[18] = ((ch[12] >> 4) & 0x7F) as u8;
buffer[18] |= ((ch[13] & 0x01) << 7) as u8;
buffer[19] = ((ch[13] >> 1) & 0xFF) as u8;
buffer[20] = ((ch[13] >> 9) & 0x03) as u8;
buffer[20] |= ((ch[14] & 0x3F) << 2) as u8;
buffer[21] = ((ch[14] >> 6) & 0x1F) as u8;
buffer[21] |= ((ch[15] & 0x07) << 5) as u8;
buffer[22] = ((ch[15] >> 3) & 0xFF) as u8;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_individual_channel_isolation() {
for channel in 0..CHANNEL_COUNT {
let mut channels = [0u16; CHANNEL_COUNT];
let test_value = CHANNEL_MAX; channels[channel] = test_value;
let mut buffer = [0u8; SBUS_FRAME_LENGTH];
buffer[0] = SBUS_HEADER;
buffer[SBUS_FRAME_LENGTH - 1] = SBUS_FOOTER;
pack_channels(&mut buffer, &channels);
let decoded = channels_parsing(&buffer);
assert_eq!(
decoded[channel], test_value,
"Channel {} failed to preserve max value",
channel
);
for (i, &value) in decoded.iter().enumerate() {
if i != channel {
assert_eq!(
value, 0,
"Channel {} was affected while packing channel {}",
i, channel
);
}
}
}
}
#[test]
fn test_parse_pack_inverse_property() {
let test_patterns = [
{
let mut arr = [0u16; CHANNEL_COUNT];
arr.iter_mut()
.enumerate()
.for_each(|(i, val)| *val = if i % 2 == 0 { 0 } else { CHANNEL_MAX });
arr
},
{
let mut arr = [0u16; CHANNEL_COUNT];
arr.iter_mut()
.enumerate()
.for_each(|(i, val)| *val = ((i as u16 * CHANNEL_MAX) / 15).min(CHANNEL_MAX));
arr
},
];
for pattern in &test_patterns {
let mut buffer = [0u8; SBUS_FRAME_LENGTH];
buffer[0] = SBUS_HEADER;
buffer[SBUS_FRAME_LENGTH - 1] = SBUS_FOOTER;
pack_channels(&mut buffer, pattern);
let decoded = channels_parsing(&buffer);
assert_eq!(
&decoded, pattern,
"Pattern was not preserved through pack/parse cycle"
);
}
}
#[test]
fn test_adjacent_channel_isolation() {
for i in 0..15 {
let mut channels = [0u16; CHANNEL_COUNT];
channels[i] = CHANNEL_MAX; channels[i + 1] = CHANNEL_MAX;
let mut buffer = [0u8; SBUS_FRAME_LENGTH];
buffer[0] = SBUS_HEADER;
buffer[SBUS_FRAME_LENGTH - 1] = SBUS_FOOTER;
pack_channels(&mut buffer, &channels);
let decoded = channels_parsing(&buffer);
assert_eq!(
decoded[i], CHANNEL_MAX,
"Channel {} lost max value when adjacent to max value",
i
);
assert_eq!(
decoded[i + 1],
CHANNEL_MAX,
"Channel {} lost max value when adjacent to max value",
i + 1
);
decoded
.iter()
.enumerate()
.filter(|(j, _)| *j != i && *j != i + 1)
.for_each(|(j, &val)| {
assert_eq!(
val,
0,
"Channel {} was affected while testing adjacent channels {},{}",
j,
i,
i + 1
);
});
}
}
}