use error::Error;
use log::debug;
use std::marker::PhantomData;
use std::str;
pub mod error {
use failure::Fail;
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "invalid group identifier: {}", _0)]
InvalidGroup(String),
#[fail(display = "invalid device identifier: {}", _0)]
InvalidDevice(String),
#[fail(display = "invalid state: {}. Try on, off, 1, 0, true, false", _0)]
InvalidState(String),
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Device {
A,
B,
C,
D,
E,
}
impl From<Device> for u8 {
fn from(d: Device) -> u8 {
match d {
Device::A => 1,
Device::B => 2,
Device::C => 3,
Device::D => 4,
Device::E => 5,
}
}
}
impl str::FromStr for Device {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"0" | "a" | "A" | "10000" => Ok(Device::A),
"1" | "b" | "B" | "01000" => Ok(Device::B),
"2" | "c" | "C" | "00100" => Ok(Device::C),
"3" | "d" | "D" | "00010" => Ok(Device::D),
"4" | "e" | "E" | "00001" => Ok(Device::E),
_ => Err(Error::InvalidDevice(s.into())),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum State {
On,
Off,
}
impl str::FromStr for State {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"On" | "on" | "1" | "true" => Ok(State::On),
"Off" | "off" | "0" | "false" => Ok(State::Off),
_ => Err(Error::InvalidState(s.into())),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Low,
High,
}
pub trait Encoding {
fn encode(group: &str, device: &Device, state: &State) -> Result<Vec<u8>, Error>;
}
pub struct EncodingA;
impl Encoding for EncodingA {
fn encode(group: &str, device: &Device, state: &State) -> Result<Vec<u8>, Error> {
if group.len() != 5 || group.chars().any(|c| c != '0' && c != '1') {
return Err(Error::InvalidGroup(group.into()));
}
let chars = group.chars();
let device = match device {
Device::A => "10000",
Device::B => "01000",
Device::C => "00100",
Device::D => "00010",
Device::E => "00001",
};
let chars = chars.chain(device.chars());
let chars = match *state {
State::On => chars.chain("10".chars()),
State::Off => chars.chain("01".chars()),
};
Ok(chars
.map(|c| match c {
'0' => b'F',
_ => b'0',
})
.collect())
}
}
pub struct EncodingB;
impl Encoding for EncodingB {
fn encode(_group: &str, _device: &Device, _state: &State) -> Result<Vec<u8>, Error> {
unimplemented!()
}
}
pub struct EncodingC;
impl Encoding for EncodingC {
fn encode(_group: &str, _device: &Device, _state: &State) -> Result<Vec<u8>, Error> {
unimplemented!()
}
}
pub trait Pin {
fn set(&self, value: &Value) -> Result<(), Error>;
}
#[derive(Debug)]
pub struct Funksteckdose<T: Pin, E: Encoding, P: Protocol> {
pin: T,
repeat_transmit: usize,
protocol: PhantomData<P>,
encoding: PhantomData<E>,
}
impl<T: Pin, E: Encoding, P: Protocol> Funksteckdose<T, E, P> {
pub fn new(pin: T) -> Funksteckdose<T, E, P> {
Self::with_repeat_transmit(pin, 10)
}
pub fn with_repeat_transmit(pin: T, repeat_transmit: usize) -> Funksteckdose<T, E, P> {
Funksteckdose {
pin,
repeat_transmit,
protocol: PhantomData,
encoding: PhantomData,
}
}
pub fn send(&self, group: &str, device: &Device, state: &State) -> Result<(), Error> {
let code_word = E::encode(group, device, state)?;
self.send_tri_state(&code_word)
}
fn send_tri_state(&self, code_word: &[u8]) -> Result<(), Error> {
let code = code_word.iter().fold(0u64, |mut code, c| {
code <<= 2u64;
match c {
b'0' => (),
b'F' => code |= 1u64,
b'1' => code |= 3u64,
_ => unreachable!(),
}
code
});
let (first, second) = if P::values().inverted_signal {
(Value::Low, Value::High)
} else {
(Value::High, Value::Low)
};
let length = code_word.len() * 2;
for _ in 0..self.repeat_transmit {
debug!("Sending code: {:#X} length: {}", code, length);
let one = P::values().one;
let zero = P::values().zero;
for i in (0..length).rev() {
let s = if code & (1 << i) != 0 { &one } else { &zero };
self.transmit(s, &first, &second)?;
}
self.transmit(&P::values().sync_factor, &first, &second)?;
}
self.pin.set(&Value::Low)?;
Ok(())
}
fn transmit(&self, pulses: &HighLow, first: &Value, second: &Value) -> Result<(), Error> {
self.pin.set(first)?;
Self::delay((P::values().pulse_length * pulses.high) as u32);
self.pin.set(second)?;
Self::delay((P::values().pulse_length * pulses.low) as u32);
Ok(())
}
fn delay(micros: u32) {
if micros > 0 {
let now = std::time::Instant::now();
let micros = u128::from(micros);
while now.elapsed().as_micros() < micros {}
}
}
}
#[derive(Clone, Debug)]
pub struct HighLow {
pub high: u64,
pub low: u64,
}
impl HighLow {
fn new(high: u64, low: u64) -> HighLow {
HighLow { high, low }
}
}
#[derive(Clone, Debug)]
pub struct ProtocolValues {
pulse_length: u64,
sync_factor: HighLow,
zero: HighLow,
one: HighLow,
inverted_signal: bool,
}
pub trait Protocol {
fn values() -> ProtocolValues;
}
pub struct Protocol1;
impl Protocol for Protocol1 {
fn values() -> ProtocolValues {
ProtocolValues {
pulse_length: 350,
sync_factor: HighLow::new(1, 31),
zero: HighLow::new(1, 3),
one: HighLow::new(3, 1),
inverted_signal: false,
}
}
}
pub struct Protocol2;
impl Protocol for Protocol2 {
fn values() -> ProtocolValues {
ProtocolValues {
pulse_length: 650,
sync_factor: HighLow::new(1, 10),
zero: HighLow::new(1, 2),
one: HighLow::new(2, 1),
inverted_signal: false,
}
}
}
pub struct Protocol3;
impl Protocol for Protocol3 {
fn values() -> ProtocolValues {
ProtocolValues {
pulse_length: 100,
sync_factor: HighLow::new(30, 71),
zero: HighLow::new(4, 11),
one: HighLow::new(9, 6),
inverted_signal: false,
}
}
}
pub struct Protocol4;
impl Protocol for Protocol4 {
fn values() -> ProtocolValues {
ProtocolValues {
pulse_length: 380,
sync_factor: HighLow::new(1, 6),
zero: HighLow::new(1, 3),
one: HighLow::new(3, 1),
inverted_signal: false,
}
}
}
pub struct Protocol5;
impl Protocol for Protocol5 {
fn values() -> ProtocolValues {
ProtocolValues {
pulse_length: 500,
sync_factor: HighLow::new(6, 14),
zero: HighLow::new(1, 2),
one: HighLow::new(2, 1),
inverted_signal: false,
}
}
}
pub struct ProtocolHT6P20B;
impl Protocol for ProtocolHT6P20B {
fn values() -> ProtocolValues {
ProtocolValues {
pulse_length: 450,
sync_factor: HighLow::new(23, 1),
zero: HighLow::new(1, 2),
one: HighLow::new(2, 1),
inverted_signal: true,
}
}
}
pub struct ProtocolHS2303;
impl Protocol for ProtocolHS2303 {
fn values() -> ProtocolValues {
ProtocolValues {
pulse_length: 150,
sync_factor: HighLow::new(2, 62),
zero: HighLow::new(1, 6),
one: HighLow::new(6, 1),
inverted_signal: false,
}
}
}
#[cfg(feature = "wiringpi")]
pub mod wiringpi {
use super::{Error, Pin, Value};
pub struct WiringPiPin {
pin: wiringpi::pin::OutputPin<wiringpi::pin::WiringPi>,
}
impl WiringPiPin {
pub fn new(pin: u16) -> WiringPiPin {
let pi = wiringpi::setup();
WiringPiPin {
pin: pi.output_pin(pin),
}
}
}
impl Pin for WiringPiPin {
fn set(&self, value: &Value) -> Result<(), Error> {
match value {
Value::High => self.pin.digital_write(wiringpi::pin::Value::High),
Value::Low => self.pin.digital_write(wiringpi::pin::Value::Low),
}
Ok(())
}
}
}