feat: Simple client/server implementation to control lights
This commit is contained in:
parent
6202f86265
commit
797ab60b8b
8 changed files with 620 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
286
Cargo.lock
generated
Normal file
286
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rppal"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b37e992f3222e304708025de77c9e395068a347449d0d7164f52d3beccdbd8d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.208"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.208"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "zwote_sonne"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"clap",
|
||||
"clap_derive",
|
||||
"rppal",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
21
Cargo.toml
Normal file
21
Cargo.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
name = "zwote_sonne"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
default-run = "client"
|
||||
|
||||
[[bin]]
|
||||
name = "server"
|
||||
path = "src/server.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "client"
|
||||
path = "src/client.rs"
|
||||
|
||||
[dependencies]
|
||||
bincode = "1.3.3"
|
||||
clap = { version = "4.5.16", features = ["derive"] }
|
||||
clap_derive = "4.5.13"
|
||||
rppal = "0.19.0"
|
||||
serde = "1.0.208"
|
||||
serde_derive = "1.0.208"
|
||||
13
rustfmt.toml
Normal file
13
rustfmt.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
brace_style = "AlwaysNextLine"
|
||||
condense_wildcard_suffixes = true
|
||||
control_brace_style = "ClosingNextLine"
|
||||
fn_single_line = true
|
||||
format_strings = true
|
||||
hard_tabs = true # Please don't cancel me
|
||||
hex_literal_case = "Lower"
|
||||
imports_granularity = "Module"
|
||||
match_block_trailing_comma = true
|
||||
newline_style = "Unix"
|
||||
group_imports = "StdExternalCrate"
|
||||
struct_field_align_threshold = 15
|
||||
wrap_comments = true
|
||||
65
src/client.rs
Normal file
65
src/client.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
use std::net::{SocketAddr, TcpStream};
|
||||
|
||||
use clap::Parser;
|
||||
use clap_derive::Subcommand;
|
||||
use packet::Packet;
|
||||
|
||||
mod packet;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about)]
|
||||
struct Args
|
||||
{
|
||||
#[arg(short, long)]
|
||||
connect: SocketAddr,
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Command
|
||||
{
|
||||
/// Set a constant brightness in Range 0.0..=1.0
|
||||
Constant
|
||||
{
|
||||
brightness: f64
|
||||
},
|
||||
/// Sinusoidal curve with a period of 0.0.. seconds
|
||||
Sine
|
||||
{
|
||||
period: f64
|
||||
},
|
||||
/// Triangle curve with a period of 0.0.. seconds
|
||||
Triangle
|
||||
{
|
||||
period: f64
|
||||
},
|
||||
/// Sawtooth curve with a period of 0.0.. seconds
|
||||
Sawtooth
|
||||
{
|
||||
period: f64
|
||||
},
|
||||
/// Square curve witha period of 0.0.. seconds and a duty cycle of 0.0..1.0
|
||||
Square
|
||||
{
|
||||
period: f64, duty: f64
|
||||
},
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
let args = Args::parse();
|
||||
let mut stream = TcpStream::connect(args.connect).expect("Unable to connect to server");
|
||||
|
||||
let packet = match args.command {
|
||||
Command::Constant { brightness } => Packet::Constant(brightness),
|
||||
Command::Sine { period } => Packet::Sine(period),
|
||||
Command::Triangle { period } => Packet::Triangle(period),
|
||||
Command::Sawtooth { period } => Packet::Sawtooth(period),
|
||||
Command::Square { period, duty } => Packet::Square { period, duty },
|
||||
};
|
||||
|
||||
packet
|
||||
.write_to_stream(&mut stream)
|
||||
.expect("Unable to send packet");
|
||||
}
|
||||
39
src/main.rs
Normal file
39
src/main.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
use core::f64;
|
||||
use std::f64::consts::TAU;
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use rppal::pwm::{Channel, Polarity, Pwm};
|
||||
|
||||
/// 1 kHz PWM frequency
|
||||
const PWM_FREQUENCY: f64 = 1000.;
|
||||
|
||||
fn triangle_wave(t: f64) -> f64 { (t - (t + 0.5).floor()).abs() * 2. }
|
||||
fn sine_wave(t: f64) -> f64 { (f64::sin(TAU * t) + 1.) * 0.5 }
|
||||
fn square_wave(t: f64, high_time: f64) -> f64
|
||||
{
|
||||
if t - t.floor() < high_time {
|
||||
1.
|
||||
}
|
||||
else {
|
||||
0.
|
||||
}
|
||||
}
|
||||
fn sawtooth_wave(t: f64) -> f64 { t - t.floor() }
|
||||
|
||||
fn main()
|
||||
{
|
||||
println!("Starting light control");
|
||||
|
||||
let pwm = Pwm::with_frequency(Channel::Pwm0, PWM_FREQUENCY, 0.5, Polarity::Normal, true)
|
||||
.expect("Unable to initialise PWM");
|
||||
|
||||
let start = Instant::now();
|
||||
loop {
|
||||
let time = start.elapsed().as_secs_f64();
|
||||
let brightness = sawtooth_wave(time * 0.5);
|
||||
|
||||
pwm.set_duty_cycle(brightness).unwrap();
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
}
|
||||
42
src/packet.rs
Normal file
42
src/packet.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use std::net::TcpStream;
|
||||
|
||||
use bincode::config::{Bounded, WithOtherLimit};
|
||||
use bincode::{DefaultOptions, Options};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
const MAX_PACKET_SIZE_BYTES: u64 = 1024;
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum Packet
|
||||
{
|
||||
/// Constant brightness in range 0.0..1.0
|
||||
Constant(f64),
|
||||
/// Sinusoidal curve with a period of 0.0.. seconds
|
||||
Sine(f64),
|
||||
/// Triangle curve with a period of 0.0.. seconds
|
||||
Triangle(f64),
|
||||
/// Sawtooth curve with a period of 0.0.. seconds
|
||||
Sawtooth(f64),
|
||||
/// Square curve witha period of 0.0.. seconds and a duty cycle of 0.0..1.0
|
||||
Square
|
||||
{
|
||||
period: f64, duty: f64
|
||||
},
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ser_options() -> WithOtherLimit<DefaultOptions, Bounded>
|
||||
{
|
||||
DefaultOptions::new().with_limit(MAX_PACKET_SIZE_BYTES)
|
||||
}
|
||||
impl Packet
|
||||
{
|
||||
pub fn write_to_stream(&self, stream: &mut TcpStream) -> Result<(), Box<bincode::ErrorKind>>
|
||||
{
|
||||
ser_options().serialize_into(stream, &self)
|
||||
}
|
||||
|
||||
pub fn read_from_stream(stream: &mut TcpStream) -> Result<Self, Box<bincode::ErrorKind>>
|
||||
{
|
||||
ser_options().deserialize_from(stream)
|
||||
}
|
||||
}
|
||||
153
src/server.rs
Normal file
153
src/server.rs
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
use core::f64;
|
||||
use std::f64::consts::TAU;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, TcpListener, TcpStream};
|
||||
use std::sync::mpsc::{self, Receiver, Sender};
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use rppal::pwm::{Channel, Polarity, Pwm};
|
||||
|
||||
mod packet;
|
||||
use packet::Packet;
|
||||
|
||||
const ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
const PORT: u16 = 6969;
|
||||
const CLIENT_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
||||
/// 1 kHz PWM frequency
|
||||
const PWM_FREQUENCY: f64 = 1000.;
|
||||
|
||||
fn triangle_wave(t: f64) -> f64 { (t - (t + 0.5).floor()).abs() * 2. }
|
||||
fn sine_wave(t: f64) -> f64 { (f64::sin(TAU * t) + 1.) * 0.5 }
|
||||
fn square_wave(t: f64, high_time: f64) -> f64
|
||||
{
|
||||
if t - t.floor() < high_time {
|
||||
1.
|
||||
}
|
||||
else {
|
||||
0.
|
||||
}
|
||||
}
|
||||
fn sawtooth_wave(t: f64) -> f64 { t - t.floor() }
|
||||
|
||||
enum LightMode
|
||||
{
|
||||
Constant(f64),
|
||||
Sine(f64),
|
||||
Triangle(f64),
|
||||
Sawtooth(f64),
|
||||
Square(f64, f64),
|
||||
}
|
||||
impl LightMode
|
||||
{
|
||||
/// The brightness that the LEDs should have at the given instant
|
||||
pub fn brightness(&self, time: Duration) -> f64
|
||||
{
|
||||
let t = time.as_secs_f64();
|
||||
match self {
|
||||
Self::Constant(b) => *b,
|
||||
Self::Sine(p) => sine_wave(t / p),
|
||||
Self::Triangle(p) => triangle_wave(t / p),
|
||||
Self::Sawtooth(p) => sawtooth_wave(t / p),
|
||||
Self::Square(period, duty) => square_wave(t / period, *duty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ArgumentOutOfRange;
|
||||
impl TryFrom<Packet> for LightMode
|
||||
{
|
||||
type Error = ArgumentOutOfRange;
|
||||
|
||||
fn try_from(p: Packet) -> Result<Self, Self::Error>
|
||||
{
|
||||
match p {
|
||||
Packet::Constant(b @ 0.0..=1.0) => Ok(Self::Constant(b)),
|
||||
Packet::Sine(0.0) => Err(ArgumentOutOfRange),
|
||||
Packet::Sine(p @ 0.0..) => Ok(Self::Sine(p)),
|
||||
Packet::Triangle(0.0) => Err(ArgumentOutOfRange),
|
||||
Packet::Triangle(p @ 0.0..) => Ok(Self::Triangle(p)),
|
||||
Packet::Sawtooth(0.0) => Err(ArgumentOutOfRange),
|
||||
Packet::Sawtooth(p @ 0.0..) => Ok(Self::Sawtooth(p)),
|
||||
Packet::Square { period: 0.0, .. } => Err(ArgumentOutOfRange),
|
||||
Packet::Square {
|
||||
period: p @ 0.0..,
|
||||
duty: d @ 0.0..=1.0,
|
||||
} => Ok(Self::Square(p, d)),
|
||||
_ => Err(ArgumentOutOfRange),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Thread to run the light control, meaning the actual PWM signal. Through the
|
||||
/// packet receiver it can be influenced to change the light mode.
|
||||
fn light_control(rx: Receiver<Packet>)
|
||||
{
|
||||
thread::spawn(move || {
|
||||
let pwm = Pwm::with_frequency(Channel::Pwm0, PWM_FREQUENCY, 0.5, Polarity::Normal, true)
|
||||
.expect("Unable to initialise PWM");
|
||||
|
||||
let mut mode = LightMode::Constant(0.0);
|
||||
let mut out_of_sync = true;
|
||||
let start = Instant::now();
|
||||
loop {
|
||||
if let Ok(p) = rx.try_recv() {
|
||||
match LightMode::try_from(p) {
|
||||
Ok(lm) => {
|
||||
mode = lm;
|
||||
out_of_sync = true;
|
||||
},
|
||||
Err(_) => eprintln!("Rejecting invalid light mode"),
|
||||
}
|
||||
}
|
||||
|
||||
if out_of_sync {
|
||||
pwm.set_duty_cycle(mode.brightness(start.elapsed()))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
println!("Starting light control");
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
light_control(rx);
|
||||
listen(tx);
|
||||
}
|
||||
|
||||
fn listen(tx: Sender<Packet>)
|
||||
{
|
||||
let listener =
|
||||
TcpListener::bind(SocketAddrV6::new(ADDRESS, PORT, 0, 0)).expect("Unable to open server");
|
||||
|
||||
for stream in listener.incoming() {
|
||||
if let Ok(stream) = stream {
|
||||
handle_client(stream, tx.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_client(mut stream: TcpStream, tx: Sender<Packet>)
|
||||
{
|
||||
thread::spawn(move || {
|
||||
if let Err(e) = stream.set_read_timeout(Some(CLIENT_TIMEOUT)) {
|
||||
eprintln!(
|
||||
"Unable to set client stream timeout. Dropping client. {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
match Packet::read_from_stream(&mut stream) {
|
||||
Ok(p) => tx.send(p).unwrap(),
|
||||
Err(e) => eprintln!(
|
||||
"Unable to read command packet from stream. Dropping client. {}",
|
||||
e
|
||||
),
|
||||
}
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue