Skip to content

Commit

Permalink
WIP: Adalight
Browse files Browse the repository at this point in the history
  • Loading branch information
tuxuser committed Jan 23, 2022
1 parent b62437b commit 29f21df
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 3 deletions.
110 changes: 109 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ strum = "0.21"
strum_macros = "0.21"
thiserror = "1.0"
tokio = { version = "1.8", features = ["macros", "net", "process", "rt-multi-thread", "signal", "sync", "time"] }
tokio-serial = "5.4.1"
tokio-stream = { version = "0.1", features = ["net"] }
tokio-util = { version = "0.6", features = ["codec"] }
toml = "0.5"
Expand Down
7 changes: 7 additions & 0 deletions config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[instances.0.instance]
friendlyName = 'LGTV'
enabled = true

[instances.0.device]
type = 'adalight'
hardwareLedCount = 224
4 changes: 3 additions & 1 deletion src/api/json/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,8 @@ pub enum LedDeviceClass {
PhilipsHue,
#[serde(rename = "Ws2812SPI")]
Ws2812Spi,
#[serde(rename = "Adalight")]
Adalight,
}

#[derive(Debug, Serialize)]
Expand All @@ -438,7 +440,7 @@ impl LedDevicesInfo {
use LedDeviceClass::*;

Self {
available: vec![Dummy, PhilipsHue, Ws2812Spi],
available: vec![Dummy, PhilipsHue, Ws2812Spi, Adalight],
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion src/instance/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ mod common;

mod dummy;
mod ws2812spi;
mod adalight;

#[derive(Debug, Error)]
pub enum DeviceError {
#[error("device not supported: {0}")]
NotSupported(&'static str),
#[error("i/o error: {0}")]
FuturesIo(#[from] futures_io::Error),
#[error("Failed to open device: {0}")]
FailedOpen(String),
#[error("Serial error: {0}")]
SerialError(String),
}

#[async_trait]
Expand Down Expand Up @@ -50,7 +55,10 @@ impl Device {
}
models::Device::Ws2812Spi(ws2812spi) => {
inner = Box::new(ws2812spi::Ws2812SpiDevice::new(ws2812spi)?);
}
},
models::Device::Adalight(adalight) => {
inner = Box::new(adalight::AdalightDevice::new(adalight)?);
},
other => {
return Err(DeviceError::NotSupported(other.into()));
}
Expand Down
84 changes: 84 additions & 0 deletions src/instance/device/adalight.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use async_trait::async_trait;
use tokio::io::AsyncWriteExt;
use tokio_serial::{self, SerialPort, SerialPortBuilderExt, SerialStream};
use palette::{Pixel, rgb::Rgb};

use crate::{color::AnsiDisplayExt, models};

use super::{common::*, DeviceError};

pub type AdalightDevice = Rewriter<AdalightDeviceImpl>;

const HEADER_SIZE: usize = 6;

pub struct AdalightDeviceImpl {
/// Handle to UART character device
dev_handle: SerialStream,
// Data buffer containing whole UART message
adalight_data: Vec<u8>,
}

#[async_trait]
impl WritingDevice for AdalightDeviceImpl {
type Config = models::Adalight;

fn new(config: &Self::Config) -> Result<Self, DeviceError> {
let handle = tokio_serial::new(
&config.device_name,
config.baudrate
)
.open_native_async()
.map_err(|_| DeviceError::FailedOpen(config.device_name.clone()))?;


// Used for header assembly only
let total_led_count = config.hardware_led_count - 1;

let buffer_size: usize = HEADER_SIZE + (config.hardware_led_count as usize * 3);
let mut buffer = vec![0x00; buffer_size];
buffer[0] = 'a' as u8;
buffer[1] = 'd' as u8;
buffer[2] = 'a' as u8;
buffer[3] = ((total_led_count & 0xFF00) >> 8) as u8;
buffer[4] = ((total_led_count & 0xFF)) as u8;
// checksum
buffer[5] = buffer[3] ^ buffer[4] ^ 0x55;

debug!("Adalight header for {} leds: {}{}{} hi={:#02x} lo={:#02x} chk={:#02x}",
config.hardware_led_count,
buffer[0] as char, buffer[1] as char, buffer[2] as char,
buffer[3], buffer[4], buffer[5]
);

Ok(Self {
dev_handle: handle,
adalight_data: buffer,
})
}

async fn set_let_data(
&mut self,
_config: &Self::Config,
led_data: &[models::Color],
) -> Result<(), DeviceError> {
trace!("Adalight: {} LEDs were set", led_data.len());
for (index, &led) in led_data.into_iter().enumerate() {
let raw: [u8; 3] = Rgb::into_raw(led);
let start_offset = HEADER_SIZE + (index * 3);
self.adalight_data[start_offset..start_offset + 3].copy_from_slice(&raw);
}

Ok(())
}

async fn write(&mut self) -> Result<(), DeviceError> {
trace!("Adalight: About to write out LED data over serial");
self.dev_handle.write(&self.adalight_data).await
.map(|_| DeviceError::SerialError("Failed writing LED data".to_string()))?;

self.dev_handle.flush().await
.map(|_| DeviceError::SerialError("Failed flushing serial".to_string()))?;

Ok(())
}
}
27 changes: 27 additions & 0 deletions src/models/devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,39 @@ impl DeviceConfig for PhilipsHue {
}
}

fn default_adalight_uart_device() -> String {
"/dev/ttyACM0".to_string()
}

fn default_adalight_uart_baudrate() -> u32 {
115200
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct Adalight {
#[validate(range(min = 1))]
pub hardware_led_count: u32,
#[serde(default = "default_adalight_uart_device")]
pub device_name: String,
#[serde(default = "default_adalight_uart_baudrate")]
pub baudrate: u32,
}

impl DeviceConfig for Adalight {
fn hardware_led_count(&self) -> usize {
self.hardware_led_count as _
}
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, IntoStaticStr, Delegate, From)]
#[serde(rename_all = "lowercase", tag = "type", deny_unknown_fields)]
#[delegate(DeviceConfig)]
pub enum Device {
Dummy(Dummy),
Ws2812Spi(Ws2812Spi),
PhilipsHue(PhilipsHue),
Adalight(Adalight),
}

impl Default for Device {
Expand All @@ -165,6 +191,7 @@ impl Validate for Device {
Device::Dummy(device) => device.validate(),
Device::Ws2812Spi(device) => device.validate(),
Device::PhilipsHue(device) => device.validate(),
Device::Adalight(device) => device.validate(),
}
}
}

0 comments on commit 29f21df

Please sign in to comment.