#![no_std]
#![deny(unsafe_code)]
use defmt::Format;
use core::iter::Iterator;
use core::ops::Index;
use embedded_hal::Pwm;
#[derive(Copy, Clone, Debug)]
pub enum BitOrder {
BigEndian,
LittleEndian,
}
#[derive(Default, Copy, Clone, Debug)]
pub struct Datagram {
length_in_bit: u8,
buffer: u128,
}
#[derive(Debug)]
struct Error;
impl Datagram {
fn add_bit(&mut self, bit: bool, order: BitOrder) -> Result<(), Error> {
if self.length_in_bit == 127 {
Err(Error)
} else {
match order {
BitOrder::BigEndian => {
self.buffer <<= 1;
if bit {
self.buffer += 1;
};
}
BitOrder::LittleEndian => {
if bit {
self.buffer += 1 << self.length_in_bit;
}
}
}
self.length_in_bit += 1;
Ok(())
}
}
pub fn len(&self) -> u8 {
self.length_in_bit
}
pub fn is_empty(&self) -> bool {
0 == self.length_in_bit
}
pub fn extract_data(&self, min: u8, max: u8) -> u128 {
if max > self.length_in_bit {
panic!("Max index to big");
}
if min >= max {
panic!("Min index to greater than max index");
}
let mut value = 0_u128;
for index in min..max {
let mask: u128 = 1 << (max + min - index - 1);
let bit = if (mask & self.buffer) == 0 { &0 } else { &1 };
value <<= 1;
value += bit;
}
value
}
pub fn new(bit_repr: &str) -> Self {
let mut datagram = Datagram::default();
for bit in bit_repr.bytes() {
match bit {
b'0' => datagram.add_bit(false, BitOrder::BigEndian).unwrap(),
b'1' => datagram.add_bit(true, BitOrder::BigEndian).unwrap(),
_ => (),
}
}
datagram
}
fn into_big_endian_iter(self) -> DatagramBigEndianIterator {
DatagramBigEndianIterator {
datagram: self,
index: self.len(),
}
}
fn into_little_endian_iter(self) -> DatagramLittleEndianIterator {
DatagramLittleEndianIterator {
datagram: self,
index: 0,
}
}
}
impl Index<u8> for Datagram {
type Output = u128;
fn index(&self, index: u8) -> &Self::Output {
if index >= self.length_in_bit {
panic!("Wrong Index")
}
let mask: u128 = 1 << index;
if mask & self.buffer == 0 {
&0
} else {
&1
}
}
}
impl PartialEq for Datagram {
fn eq(&self, other: &Self) -> bool {
self.buffer == other.buffer && self.length_in_bit == other.length_in_bit
}
}
impl Eq for Datagram {}
impl Format for Datagram {
fn format(&self, f: defmt::Formatter) {
for index in 0..self.length_in_bit {
if 0 == index % 4 {
defmt::write!(f, "-");
}
if 1 == self[self.length_in_bit - 1 - index] {
defmt::write!(f, "1");
} else {
defmt::write!(f, "0");
}
}
}
}
#[derive(Debug)]
pub struct DatagramBigEndianIterator {
datagram: Datagram,
index: u8,
}
impl Iterator for DatagramBigEndianIterator {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
if 0 < self.index {
self.index -= 1;
Some(1 == self.datagram[self.index])
} else {
None
}
}
}
#[derive(Debug)]
pub struct DatagramLittleEndianIterator {
datagram: Datagram,
index: u8,
}
impl Iterator for DatagramLittleEndianIterator {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
if self.datagram.len() > self.index {
self.index += 1;
Some(1 == self.datagram[self.index - 1])
} else {
None
}
}
}
#[derive(Debug)]
pub struct Encoder<I> {
datagram_iter: I,
first_half_bit: bool,
last_value: Option<bool>,
}
impl Encoder<DatagramBigEndianIterator> {
pub fn new(d: Datagram) -> Self {
let mut datagram_iter = d.into_big_endian_iter();
let last_value = datagram_iter.next();
Encoder::<DatagramBigEndianIterator> {
datagram_iter,
first_half_bit: true,
last_value,
}
}
}
impl Encoder<DatagramLittleEndianIterator> {
pub fn new(d: Datagram) -> Self {
let mut datagram_iter = d.into_little_endian_iter();
let last_value = datagram_iter.next();
Encoder::<DatagramLittleEndianIterator> {
datagram_iter,
first_half_bit: true,
last_value,
}
}
}
impl<I: Iterator<Item = bool>> Iterator for Encoder<I> {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
match self.last_value {
Some(bit) => {
if self.first_half_bit {
self.first_half_bit = false;
Some(!bit)
} else {
self.first_half_bit = true;
self.last_value = self.datagram_iter.next();
Some(bit)
}
}
None => None,
}
}
}
#[derive(PartialEq)]
pub enum ActivityLevel {
High,
Low,
}
pub enum SyncOnTurningEdge {
First,
Second,
}
pub struct Decoder {
activity_level: ActivityLevel,
sync_on_turning_edge: SyncOnTurningEdge,
bit_order: BitOrder,
datagram: Datagram,
previous_sample: bool,
edge_distance: u8,
recording_distance: u8,
receiving_started: bool,
record_marker_reached: bool,
}
const SAMPLES_PER_HALF_BIT_PERIOD: u8 = 3;
const TOLERANCE: u8 = 1;
const LOWER_BARRIER: u8 = 2 * SAMPLES_PER_HALF_BIT_PERIOD - TOLERANCE;
const UPPER_BARRIER: u8 = 2 * SAMPLES_PER_HALF_BIT_PERIOD + TOLERANCE;
const NO_EDGE_EXIT_LIMIT: u8 = 3 * SAMPLES_PER_HALF_BIT_PERIOD;
impl Decoder {
pub const fn new(
activity_level: ActivityLevel,
sync_on_turning_edge: SyncOnTurningEdge,
bit_order: BitOrder,
) -> Self {
let previous_sample = match activity_level {
ActivityLevel::High => false,
ActivityLevel::Low => true,
};
Decoder {
datagram: Datagram {
buffer: 0,
length_in_bit: 0,
},
previous_sample,
edge_distance: NO_EDGE_EXIT_LIMIT,
recording_distance: NO_EDGE_EXIT_LIMIT,
receiving_started: false,
activity_level,
sync_on_turning_edge,
record_marker_reached: false,
bit_order,
}
}
pub fn next(&mut self, sample: bool) -> Option<Datagram> {
let mut return_value: Option<Datagram> = None;
if sample != self.previous_sample {
if !self.receiving_started {
match self.sync_on_turning_edge {
SyncOnTurningEdge::First => {
self.record_marker_reached = true;
self.receiving_started = true;
}
SyncOnTurningEdge::Second => {
if self.edge_distance <= SAMPLES_PER_HALF_BIT_PERIOD + TOLERANCE {
self.record_marker_reached = true;
self.receiving_started = true;
} else {
}
}
}
}
if self.recording_distance >= LOWER_BARRIER && self.recording_distance <= UPPER_BARRIER
{
self.record_marker_reached = true;
}
if self.record_marker_reached {
self.datagram
.add_bit(!sample, self.bit_order) .unwrap();
self.recording_distance = 1;
self.record_marker_reached = false;
}
self.previous_sample = sample;
self.edge_distance = 1;
} else {
self.edge_distance += 1;
self.recording_distance += 1;
}
if self.edge_distance > NO_EDGE_EXIT_LIMIT {
if !self.datagram.is_empty() && (sample ^ (self.activity_level == ActivityLevel::High))
{
return_value = Some(self.datagram);
self.receiving_started = false;
}
self.datagram = Datagram::default();
self.edge_distance -= 1; }
if self.recording_distance > NO_EDGE_EXIT_LIMIT {
self.recording_distance -= 1; }
return_value
}
}
#[derive(Debug)]
pub struct InfraredEmitter<P, C, I> {
encoder: Option<Encoder<I>>,
max_pause_cycles: u8,
current_pause_cycles: u8,
pwm: P,
channel: C,
}
impl<P, C, D, I> InfraredEmitter<P, C, I>
where
P: Pwm + Pwm<Channel = C> + Pwm<Duty = D>,
C: Copy,
D: core::ops::Mul<Output = D> + core::ops::Div<Output = D>,
I: Iterator<Item = bool>,
{
pub fn new(pause_cycles: u8, pwm: P, channel: C) -> Self {
InfraredEmitter {
encoder: None,
max_pause_cycles: pause_cycles,
current_pause_cycles: 0,
pwm,
channel,
}
}
pub fn send_half_bit(&mut self) {
match &mut self.encoder {
Some(encoder) => match encoder.next() {
Some(half_bit) => {
if half_bit {
self.pwm.enable(self.channel);
} else {
self.pwm.disable(self.channel);
}
}
None => {
self.pwm.disable(self.channel);
self.encoder = None;
self.current_pause_cycles = 0;
}
},
None => {
self.current_pause_cycles += 1;
}
}
}
}
impl<P, C, D> InfraredEmitter<P, C, DatagramBigEndianIterator>
where
P: Pwm + Pwm<Channel = C> + Pwm<Duty = D>,
C: Copy,
D: core::ops::Mul<Output = D> + core::ops::Div<Output = D>,
{
pub fn send_if_possible(&mut self, datagram: Datagram, sending_power: D) -> bool {
if self.current_pause_cycles < self.max_pause_cycles {
false
} else {
self.pwm.set_duty(self.channel, sending_power);
self.encoder = Some(Encoder::<DatagramBigEndianIterator>::new(datagram));
true
}
}
}
impl<P, C, D> InfraredEmitter<P, C, DatagramLittleEndianIterator>
where
P: Pwm + Pwm<Channel = C> + Pwm<Duty = D>,
C: Copy,
D: core::ops::Mul<Output = D> + core::ops::Div<Output = D>,
{
pub fn send_if_possible(&mut self, datagram: Datagram, sending_power: D) -> bool {
if self.current_pause_cycles < self.max_pause_cycles {
false
} else {
self.pwm.set_duty(self.channel, sending_power);
self.encoder = Some(Encoder::<DatagramLittleEndianIterator>::new(datagram));
true
}
}
}
#[cfg(test)]
mod tests;