feat: 使用 UDP 发送颜色。

This commit is contained in:
Ivan Li 2023-04-28 00:26:49 +08:00
parent 9d11abfa6e
commit 7a87748cf1
3 changed files with 114 additions and 51 deletions

View File

@ -1,8 +1,9 @@
use std::{collections::HashMap, sync::Arc, time::Duration}; use std::{borrow::Borrow, collections::HashMap, io::Read, sync::Arc, time::Duration};
use paris::warn; use paris::warn;
use tauri::async_runtime::RwLock; use tauri::async_runtime::RwLock;
use tokio::{ use tokio::{
net::UdpSocket,
sync::{broadcast, watch}, sync::{broadcast, watch},
time::sleep, time::sleep,
}; };
@ -52,6 +53,7 @@ impl LedColorsPublisher {
display_id: u32, display_id: u32,
sample_points: Vec<Vec<LedSamplePoints>>, sample_points: Vec<Vec<LedSamplePoints>>,
bound_scale_factor: f32, bound_scale_factor: f32,
mappers: Vec<SamplePointMapper>,
display_colors_tx: broadcast::Sender<(u32, Vec<u8>)>, display_colors_tx: broadcast::Sender<(u32, Vec<u8>)>,
) { ) {
let internal_tasks_version = self.inner_tasks_version.clone(); let internal_tasks_version = self.inner_tasks_version.clone();
@ -99,9 +101,50 @@ impl LedColorsPublisher {
continue; continue;
} }
let colors = colors.unwrap(); let colors: Vec<crate::led_color::LedColor> = colors.unwrap();
// let color_len = colors.len(); // let color_len = colors.len();
let display_led_offset = mappers
.clone()
.iter()
.flat_map(|mapper| [mapper.start, mapper.end])
.min()
.unwrap();
for group in mappers.clone() {
if (group.start.abs_diff(group.end)) > colors.len() {
warn!(
"get_sorted_colors: color_index out of range. color_index: {}, strip len: {}, colors.len(): {}",
group.pos,
group.start.abs_diff(group.end),
colors.len()
);
return;
}
let group_size = group.start.abs_diff(group.end);
let mut buffer = Vec::<u8>::with_capacity(group_size * 3);
if group.end > group.start {
for i in group.pos-display_led_offset..group_size + group.pos-display_led_offset {
let bytes = colors[i].as_bytes();
buffer.append(&mut bytes.to_vec());
}
} else {
for i in (group.pos-display_led_offset..group_size + group.pos-display_led_offset).rev() {
let bytes = colors[i].as_bytes();
buffer.append(&mut bytes.to_vec());
}
}
match Self::send_colors((group.start.min(group.end)) as u16, buffer).await {
Ok(_) => {}
Err(err) => {
warn!("Failed to send colors: {}", err);
}
};
}
log::info!("sent colors: #{: >15} {:?}", display_id, colors.len());
match display_colors_tx.send(( match display_colors_tx.send((
display_id, display_id,
@ -232,11 +275,11 @@ impl LedColorsPublisher {
let display_id = sample_point_group.display_id; let display_id = sample_point_group.display_id;
let sample_points = sample_point_group.points; let sample_points = sample_point_group.points;
let bound_scale_factor = sample_point_group.bound_scale_factor; let bound_scale_factor = sample_point_group.bound_scale_factor;
publisher.start_one_display_colors_fetcher( publisher.start_one_display_colors_fetcher(
display_id, display_id,
sample_points, sample_points,
bound_scale_factor, bound_scale_factor,
sample_point_group.mappers,
display_colors_tx.clone(), display_colors_tx.clone(),
); );
} }
@ -250,33 +293,40 @@ impl LedColorsPublisher {
} }
}); });
let rx = self.sorted_colors_rx.clone(); // let rx = self.sorted_colors_rx.clone();
tokio::spawn(async move { // tokio::spawn(async move {
let mut rx = rx.read().await.clone(); // let mut rx = rx.read().await.clone();
loop { // loop {
if let Err(err) = rx.changed().await { // if let Err(err) = rx.changed().await {
warn!("rx changed error: {}", err); // warn!("rx changed error: {}", err);
sleep(Duration::from_millis(1000)).await; // sleep(Duration::from_millis(1000)).await;
continue; // continue;
} // }
let colors = rx.borrow().clone(); // let colors = rx.borrow().clone();
match Self::send_colors(colors).await { // match Self::send_colors(colors).await {
Ok(_) => { // Ok(_) => {}
} // Err(err) => {
Err(err) => { // warn!("colors send failed: {}", err);
warn!("colors send failed: {}", err); // }
} // }
} // }
} // });
});
} }
pub async fn send_colors(payload: Vec<u8>) -> anyhow::Result<()> { pub async fn send_colors(offset: u16, mut payload: Vec<u8>) -> anyhow::Result<()> {
let mqtt = MqttRpc::global().await; // let mqtt = MqttRpc::global().await;
mqtt.publish_led_sub_pixels(payload).await // mqtt.publish_led_sub_pixels(payload).await;
let socket = UdpSocket::bind("0.0.0.0:8000").await?;
let mut buffer = vec![2];
buffer.push((offset >> 8) as u8);
buffer.push((offset & 0xff) as u8);
buffer.append(&mut payload);
socket.send_to(&buffer, "192.168.31.206:23042").await?;
Ok(())
} }
pub async fn clone_sorted_colors_receiver(&self) -> watch::Receiver<Vec<u8>> { pub async fn clone_sorted_colors_receiver(&self) -> watch::Receiver<Vec<u8>> {
@ -326,35 +376,43 @@ impl LedColorsPublisher {
screenshots.insert(screenshot.display_id, screenshot); screenshots.insert(screenshot.display_id, screenshot);
if screenshots.len() == display_ids.len() { if screenshots.len() == display_ids.len() {
let mut led_start = 0;
for display_id in display_ids { for display_id in display_ids {
let led_strip_configs: Vec<_> = configs let led_strip_configs = configs
.strips .strips
.iter() .iter()
.filter(|c| c.display_id == display_id) .enumerate()
.collect(); .filter(|(_, c)| c.display_id == display_id);
if led_strip_configs.len() == 0 {
warn!("no led strip config for display_id: {}", display_id);
continue;
}
let screenshot = screenshots.get(&display_id).unwrap(); let screenshot = screenshots.get(&display_id).unwrap();
log::debug!("screenshot updated: {:?}", display_id); log::debug!("screenshot updated: {:?}", display_id);
let points: Vec<_> = led_strip_configs let points: Vec<_> = led_strip_configs
.iter() .clone()
.map(|config| screenshot.get_sample_points(&config)) .map(|(_, config)| screenshot.get_sample_points(&config))
.collect(); .collect();
if points.len() == 0 {
warn!("no led strip config for display_id: {}", display_id);
continue;
}
let bound_scale_factor = screenshot.bound_scale_factor; let bound_scale_factor = screenshot.bound_scale_factor;
let led_end = led_start + points.iter().map(|p| p.len()).sum::<usize>();
let mappers = led_strip_configs.map(|(i, _)| mappers[i].clone()).collect();
let colors_config = DisplaySamplePointGroup { let colors_config = DisplaySamplePointGroup {
display_id, display_id,
points, points,
bound_scale_factor, bound_scale_factor,
mappers,
}; };
colors_configs.push(colors_config); colors_configs.push(colors_config);
led_start = led_end;
} }
log::debug!("got all colors configs: {:?}", colors_configs.len()); log::debug!("got all colors configs: {:?}", colors_configs.len());
@ -384,4 +442,5 @@ pub struct DisplaySamplePointGroup {
pub display_id: u32, pub display_id: u32,
pub points: Vec<Vec<LedSamplePoints>>, pub points: Vec<Vec<LedSamplePoints>>,
pub bound_scale_factor: f32, pub bound_scale_factor: f32,
pub mappers: Vec<config::SamplePointMapper>,
} }

View File

@ -1,46 +1,50 @@
use std::ops::Index;
use color_space::{Hsv, Rgb}; use color_space::{Hsv, Rgb};
use serde::Serialize; use serde::Serialize;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct LedColor { pub struct LedColor([u8; 3]);
bits: [u8; 3],
}
impl LedColor { impl LedColor {
pub fn default() -> Self { pub fn default() -> Self {
Self { bits: [0, 0, 0] } Self ([0, 0, 0] )
} }
pub fn new(r: u8, g: u8, b: u8) -> Self { pub fn new(r: u8, g: u8, b: u8) -> Self {
Self { bits: [r, g, b] } Self ([r, g, b])
} }
pub fn from_hsv(h: f64, s: f64, v: f64) -> Self { pub fn from_hsv(h: f64, s: f64, v: f64) -> Self {
let rgb = Rgb::from(Hsv::new(h, s, v)); let rgb = Rgb::from(Hsv::new(h, s, v));
Self { bits: [rgb.r as u8, rgb.g as u8, rgb.b as u8] } Self ([rgb.r as u8, rgb.g as u8, rgb.b as u8])
} }
pub fn get_rgb(&self) -> [u8; 3] { pub fn get_rgb(&self) -> [u8; 3] {
self.bits self.0
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.bits.iter().any(|bit| *bit == 0) self.0.iter().any(|bit| *bit == 0)
} }
pub fn set_rgb(&mut self, r: u8, g: u8, b: u8) -> &Self { pub fn set_rgb(&mut self, r: u8, g: u8, b: u8) -> &Self {
self.bits = [r, g, b]; self.0 = [r, g, b];
self self
} }
pub fn merge(&mut self, r: u8, g: u8, b: u8) -> &Self { pub fn merge(&mut self, r: u8, g: u8, b: u8) -> &Self {
self.bits = [ self.0 = [
(self.bits[0] / 2 + r / 2), (self.0[0] / 2 + r / 2),
(self.bits[1] / 2 + g / 2), (self.0[1] / 2 + g / 2),
(self.bits[2] / 2 + b / 2), (self.0[2] / 2 + b / 2),
]; ];
self self
} }
pub fn as_bytes (&self) -> [u8; 3] {
self.0
}
} }
impl Serialize for LedColor { impl Serialize for LedColor {
@ -48,7 +52,7 @@ impl Serialize for LedColor {
where where
S: serde::Serializer, S: serde::Serializer,
{ {
let hex = format!("#{}", hex::encode(self.bits)); let hex = format!("#{}", hex::encode(self.0));
serializer.serialize_str(hex.as_str()) serializer.serialize_str(hex.as_str())
} }
} }

View File

@ -132,8 +132,8 @@ async fn patch_led_strip_len(display_id: u32, border: Border, delta_len: i8) ->
} }
#[tauri::command] #[tauri::command]
async fn send_colors(buffer: Vec<u8>) -> Result<(), String> { async fn send_colors(offset: u16, buffer: Vec<u8>) -> Result<(), String> {
ambient_light::LedColorsPublisher::send_colors(buffer) ambient_light::LedColorsPublisher::send_colors(offset, buffer)
.await .await
.map_err(|e| { .map_err(|e| {
error!("can not send colors: {}", e); error!("can not send colors: {}", e);