feat: 使用 UDP 发送颜色。
This commit is contained in:
parent
9d11abfa6e
commit
7a87748cf1
@ -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();
|
||||||
|
|
||||||
|
// match Self::send_colors(colors).await {
|
||||||
|
// Ok(_) => {}
|
||||||
|
// Err(err) => {
|
||||||
|
// warn!("colors send failed: {}", err);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
let colors = rx.borrow().clone();
|
pub async fn send_colors(offset: u16, mut payload: Vec<u8>) -> anyhow::Result<()> {
|
||||||
|
// let mqtt = MqttRpc::global().await;
|
||||||
|
|
||||||
match Self::send_colors(colors).await {
|
// mqtt.publish_led_sub_pixels(payload).await;
|
||||||
Ok(_) => {
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
warn!("colors send failed: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send_colors(payload: Vec<u8>) -> anyhow::Result<()> {
|
let socket = UdpSocket::bind("0.0.0.0:8000").await?;
|
||||||
let mqtt = MqttRpc::global().await;
|
let mut buffer = vec![2];
|
||||||
|
buffer.push((offset >> 8) as u8);
|
||||||
mqtt.publish_led_sub_pixels(payload).await
|
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>,
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user