refactor patterns

This commit is contained in:
Tobias Ollive 2022-03-11 12:40:12 +01:00
parent c2b2517661
commit b718334392
11 changed files with 417 additions and 401 deletions

View File

@ -7,83 +7,55 @@
fade:
current_iteration: 10
nbr_iterations: 20
begin_color:
begin_color: &black
red: 0
green: 0
blue: 0
end_color:
end_color: &purple
red: 255
green: 0
blue: 255
current_iteration: 0
max_iteration: 10
period:
secs: 0
nanos: 50000000
period: 50
- pattern:
type: Fade
current_iteration: 0
nbr_iterations: 20
begin_color:
begin_color: &red
red: 255
green: 0
blue: 0
end_color:
end_color: &blue
red: 0
green: 0
blue: 255
period:
secs: 0
nanos: 200000000
period: 200
- pattern:
type: ColorWipe
max_iteration: 25
current_iteration: 0
color:
color: &green
red: 0
green: 255
blue: 0
background_color:
red: 255
green: 0
blue: 255
period:
secs: 0
nanos: 100000000
background_color: *purple
period: 100
- pattern:
type: FillRandom
color:
red: 0
green: 0
blue: 255
color: *blue
stability: 40
period:
secs: 0
nanos: 800000000
period: 80
- name: titi
sequence:
- pattern:
type: Blink
fade :
current_iteration: 0
nbr_iterations: 20
begin_color:
red: 0
green: 0
blue: 0
end_color:
begin_color: *black
end_color: &cyan
red: 0
green: 255
blue: 255
current_iteration: 0
max_iteration : 10
period:
secs: 0
nanos: 100000000
period: 50
- pattern:
type: Rainbow
current_iteration: 0
period:
secs: 0
nanos: 100000000
period: 100

View File

@ -19,7 +19,6 @@ use std::sync::{Arc, Mutex};
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::sync::watch;
use tokio::sync::Notify;
const SERVICE_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0900c33242a893bd25e905756cb8);
const PIXEL_DATA_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0903c33242a893bd25e905756cb8);
@ -35,8 +34,6 @@ async fn main() -> bluer::Result<()> {
let spectacle = Spectacle::from(config);
let spectacle = Arc::new(Mutex::new(spectacle));
let musique_file = command_line.musique_file;
let musique = tokio::task::spawn_blocking(move || play_sound(Path::new(&musique_file)));
let adapter = bluetooth::create_session().await?;
let (tx_scan, rx_scan) = mpsc::channel(3);
@ -49,9 +46,9 @@ async fn main() -> bluer::Result<()> {
tokio::spawn(connect_device(spectacle.clone(), rx_scan));
tokio::time::sleep(Duration::from_secs(5)).await;
println!("starting");
let musique_file = command_line.musique_file;
let musique = tokio::task::spawn_blocking(move || play_sound(Path::new(&musique_file)));
let futures;
{
let mut spectacle = spectacle.lock().unwrap();

View File

@ -1,7 +1,21 @@
use rand::Rng;
mod scanner;
mod fade;
mod color_wipe;
mod rainbow;
mod fill_random;
mod fill_unstable;
mod blink;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
use std::ops::{Div, Index, IndexMut, SubAssign};
use crate::patterns::blink::Blink;
use crate::patterns::color_wipe::ColorWipe;
use crate::patterns::fade::Fade;
use crate::patterns::fill_random::FillRandom;
use crate::patterns::fill_unstable::FillUnstable;
use crate::patterns::rainbow::Rainbow;
use crate::patterns::scanner::Scanner;
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
#[serde(tag = "type")]
@ -110,353 +124,4 @@ impl<const N: usize> Strip<N> {
pub fn fill(&mut self, color: PixelColor) {
self.0.fill(color);
}
}
/// # Rainbow pattern
///
/// every pattern implement the iterator trait
///
/// This pattern display a moving rainbow over the strip
///
/// ### Note
///
/// If max iteration is let to None, it's an infinite pattern.
///
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Rainbow<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) max_iteration: Option<usize>,
pub(crate) step: Option<usize>,
}
impl<const N: usize> Iterator for Rainbow<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(nbr_iteration) = self.max_iteration {
if nbr_iteration == self.current_iteration {
return None;
}
}
let mut strip = Strip::default();
let step = self.step.unwrap_or(255 / N);
for i in 0..N {
let pos = (i * step + self.current_iteration) as u8;
strip[i] = wheel(pos)
}
self.current_iteration += 1;
Some(strip)
}
}
/// compute **rgb** pixel color according to the **hsv** wheel
///
/// # Arguments
///
/// * `index`: position in the hsv wheel
///
/// returns: PixelColor
///
fn wheel(index: u8) -> PixelColor {
let pos = 255 - index;
match pos {
0..=85 => PixelColor {
red: 255 - (pos * 3),
green: 0,
blue: pos * 3,
},
86..=170 => {
let pos = pos - 85;
PixelColor {
red: 0,
green: pos * 3,
blue: 255 - (pos * 3),
}
}
_ => {
let pos = pos - 170;
PixelColor {
red: pos * 3,
green: 255 - (pos * 3),
blue: 0,
}
}
}
}
/// # Colorwipe pattern
/// every pattern implement the iterator trait
///
/// This pattern fill the strip with a specific color, one by one.
///
/// ### Note
///
/// setting max_iteration to None lead the pattern to loop infinitely
///
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct ColorWipe<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) max_iteration: Option<usize>,
pub(crate) color: PixelColor,
pub(crate) background_color: Option<PixelColor>,
}
impl<const N: usize> Iterator for ColorWipe<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
let mut strip = Strip::default();
if let Some(c) = self.background_color {
strip.fill(c);
}
let iteration = self.current_iteration % N;
if let Some(max_iteration) = self.max_iteration {
if self.current_iteration >= max_iteration {
return None;
}
}
for i in 0..iteration {
strip[i] = self.color;
}
self.current_iteration += 1;
Some(strip)
}
}
/// # fade pattern
/// fade from one color to an other
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Fade<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) nbr_iterations: usize,
pub(crate) begin_color: PixelColor,
pub(crate) end_color: PixelColor,
}
fn fade_value(value_start: u8, value_end: u8, index: usize, nbr_iter: usize) -> u8 {
((value_start as usize * (nbr_iter - index) + value_end as usize * index) / nbr_iter) as u8
}
impl<const N: usize> Iterator for Fade<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
let mut strip = Strip::default();
if self.current_iteration >= self.nbr_iterations {
return None;
}
let red = fade_value(
self.begin_color.red,
self.end_color.red,
self.current_iteration,
self.nbr_iterations,
);
let green = fade_value(
self.begin_color.green,
self.end_color.green,
self.current_iteration,
self.nbr_iterations,
);
let blue = fade_value(
self.begin_color.blue,
self.end_color.blue,
self.current_iteration,
self.nbr_iterations,
);
let current_color = PixelColor { red, green, blue };
strip.fill(current_color);
self.current_iteration += 1;
Some(strip)
}
}
/// # scanner pattern
/// color one pixel with a color and leave a train of this color fading to black
///
/// # note
///
/// background_color work only for color not set by scanner pattern
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Scanner<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) color: PixelColor,
pub(crate) background_color: Option<PixelColor>,
}
impl<const N: usize> Iterator for Scanner<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
let mut strip = Strip::<N>::default();
if let Some(c) = self.background_color {
strip.fill(c);
} else {
strip.fill(PixelColor::default());
}
let current_led = self.current_iteration % N;
let min_led;
if current_led < 8 {
min_led = 0;
} else {
min_led = current_led - 8;
}
let mut c = self.color;
for i in min_led..current_led {
strip[i] = c;
c = c / 2;
}
self.current_iteration += 1;
Some(strip)
}
}
/// # FillRandom
///
/// fill strip with color then apply random variation to each pixel
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct FillRandom<const N: usize> {
pub(crate) color: PixelColor,
pub(crate) stability: usize,
pub(crate) max_iteration: Option<usize>,
}
impl<const N: usize> Iterator for FillRandom<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(iteration) = self.max_iteration {
if iteration == 0 {
return None;
} else {
self.max_iteration = Some(iteration - 1);
}
}
let mut strip = Strip::<N>::default();
let mut rng = rand::thread_rng();
for i in 0..N {
let red_delta = rng.gen_range(0..self.stability) as u8;
let green_delta = rng.gen_range(0..self.stability) as u8;
let blue_delta = rng.gen_range(0..self.stability) as u8;
let operation = rng.gen_bool(0.5);
let red;
let green;
let blue;
if operation {
red = self.color.red.saturating_add(red_delta);
green = self.color.green.saturating_add(green_delta);
blue = self.color.blue.saturating_add(blue_delta);
} else {
red = self.color.red.saturating_sub(red_delta);
green = self.color.green.saturating_sub(green_delta);
blue = self.color.blue.saturating_sub(blue_delta);
}
let c = PixelColor { red, green, blue };
strip[i] = c;
}
Some(strip)
}
}
/// # FillUnstable
///
/// fill strip with color then apply same random variation to all pixel
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct FillUnstable<const N: usize> {
pub(crate) color: PixelColor,
pub(crate) stability: usize,
pub(crate) max_iteration: Option<usize>,
}
impl<const N: usize> Iterator for FillUnstable<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(iteration) = self.max_iteration {
if iteration == 0 {
return None;
} else {
self.max_iteration = Some(iteration - 1);
}
}
let mut strip = Strip::<N>::default();
let mut rng = rand::thread_rng();
let red_delta = rng.gen_range(0..self.stability) as u8;
let green_delta = rng.gen_range(0..self.stability) as u8;
let blue_delta = rng.gen_range(0..self.stability) as u8;
let operation = rng.gen_bool(0.5);
let red;
let green;
let blue;
if operation {
red = self.color.red.saturating_add(red_delta);
green = self.color.green.saturating_add(green_delta);
blue = self.color.blue.saturating_add(blue_delta);
} else {
red = self.color.red.saturating_sub(red_delta);
green = self.color.green.saturating_sub(green_delta);
blue = self.color.blue.saturating_sub(blue_delta);
}
strip.fill(PixelColor { red, green, blue });
Some(strip)
}
}
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
enum Direction {
there,
back,
}
impl Default for Direction {
fn default() -> Self {
Direction::there
}
}
/// # Blink
///
/// fade from one color to an other then go back several times
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Blink<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) max_iteration: Option<usize>,
fade: Fade<N>,
#[serde(default)]
direction: Direction,
}
impl<const N: usize> Iterator for Blink<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
let value = self.fade.next();
match value {
None => {
if let Some(iter_max) = self.max_iteration {
if self.current_iteration >= iter_max {
return None;
}
self.current_iteration += 1;
}
self.fade.current_iteration = 0;
std::mem::swap(&mut self.fade.begin_color, &mut self.fade.end_color);
self.fade.next()
}
Some(value) => Some(value),
}
}
}
}

36
src/patterns/blink.rs Normal file
View File

@ -0,0 +1,36 @@
use crate::patterns::fade::Fade;
use crate::Strip;
use serde::{Serialize, Deserialize};
/// # Blink
///
/// fade from one color to an other then go back several times
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Blink<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) max_iteration: Option<usize>,
fade: Fade<N>,
}
impl<const N: usize> Iterator for Blink<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
let value = self.fade.next();
match value {
None => {
if let Some(iter_max) = self.max_iteration {
if self.current_iteration >= iter_max {
return None;
}
self.current_iteration += 1;
}
self.fade.current_iteration = 0;
std::mem::swap(&mut self.fade.begin_color, &mut self.fade.end_color);
self.fade.next()
}
Some(value) => Some(value),
}
}
}

View File

@ -0,0 +1,44 @@
use crate::patterns::PixelColor;
use crate::Strip;
use serde::{Serialize, Deserialize};
/// # Colorwipe pattern
/// every pattern implement the iterator trait
///
/// This pattern fill the strip with a specific color, one by one.
///
/// ### Note
///
/// setting max_iteration to None lead the pattern to loop infinitely
///
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct ColorWipe<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) max_iteration: Option<usize>,
pub(crate) color: PixelColor,
pub(crate) background_color: Option<PixelColor>,
}
impl<const N: usize> Iterator for ColorWipe<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
let mut strip = Strip::default();
if let Some(c) = self.background_color {
strip.fill(c);
}
let iteration = self.current_iteration % N;
if let Some(max_iteration) = self.max_iteration {
if self.current_iteration >= max_iteration {
return None;
}
}
for i in 0..iteration {
strip[i] = self.color;
}
self.current_iteration += 1;
Some(strip)
}
}

56
src/patterns/fade.rs Normal file
View File

@ -0,0 +1,56 @@
use crate::patterns::PixelColor;
use crate::Strip;
use serde::{Serialize, Deserialize};
/// # fade pattern
/// fade from one color to an other
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Fade<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) nbr_iterations: usize,
pub(crate) begin_color: PixelColor,
pub(crate) end_color: PixelColor,
}
fn fade_value(value_start: u8, value_end: u8, index: usize, nbr_iter: usize) -> u8 {
((value_start as usize * (nbr_iter - index) + value_end as usize * index) / nbr_iter) as u8
}
impl<const N: usize> Iterator for Fade<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
let mut strip = Strip::default();
if self.current_iteration >= self.nbr_iterations {
return None;
}
let red = fade_value(
self.begin_color.red,
self.end_color.red,
self.current_iteration,
self.nbr_iterations,
);
let green = fade_value(
self.begin_color.green,
self.end_color.green,
self.current_iteration,
self.nbr_iterations,
);
let blue = fade_value(
self.begin_color.blue,
self.end_color.blue,
self.current_iteration,
self.nbr_iterations,
);
let current_color = PixelColor { red, green, blue };
strip.fill(current_color);
self.current_iteration += 1;
Some(strip)
}
}

View File

@ -0,0 +1,52 @@
use rand::Rng;
use crate::patterns::PixelColor;
use crate::Strip;
use serde::{Serialize, Deserialize};
/// # FillRandom
///
/// fill strip with color then apply random variation to each pixel
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct FillRandom<const N: usize> {
pub(crate) color: PixelColor,
pub(crate) stability: usize,
pub(crate) max_iteration: Option<usize>,
}
impl<const N: usize> Iterator for FillRandom<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(iteration) = self.max_iteration {
if iteration == 0 {
return None;
} else {
self.max_iteration = Some(iteration - 1);
}
}
let mut strip = Strip::<N>::default();
let mut rng = rand::thread_rng();
for i in 0..N {
let red_delta = rng.gen_range(0..self.stability) as u8;
let green_delta = rng.gen_range(0..self.stability) as u8;
let blue_delta = rng.gen_range(0..self.stability) as u8;
let operation = rng.gen_bool(0.5);
let red;
let green;
let blue;
if operation {
red = self.color.red.saturating_add(red_delta);
green = self.color.green.saturating_add(green_delta);
blue = self.color.blue.saturating_add(blue_delta);
} else {
red = self.color.red.saturating_sub(red_delta);
green = self.color.green.saturating_sub(green_delta);
blue = self.color.blue.saturating_sub(blue_delta);
}
let c = PixelColor { red, green, blue };
strip[i] = c;
}
Some(strip)
}
}

View File

@ -0,0 +1,49 @@
use rand::Rng;
use crate::patterns::PixelColor;
use crate::Strip;
use serde::{Serialize, Deserialize};
/// # FillUnstable
///
/// fill strip with color then apply same random variation to all pixel
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct FillUnstable<const N: usize> {
pub(crate) color: PixelColor,
pub(crate) stability: usize,
pub(crate) max_iteration: Option<usize>,
}
impl<const N: usize> Iterator for FillUnstable<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(iteration) = self.max_iteration {
if iteration == 0 {
return None;
} else {
self.max_iteration = Some(iteration - 1);
}
}
let mut strip = Strip::<N>::default();
let mut rng = rand::thread_rng();
let red_delta = rng.gen_range(0..self.stability) as u8;
let green_delta = rng.gen_range(0..self.stability) as u8;
let blue_delta = rng.gen_range(0..self.stability) as u8;
let operation = rng.gen_bool(0.5);
let red;
let green;
let blue;
if operation {
red = self.color.red.saturating_add(red_delta);
green = self.color.green.saturating_add(green_delta);
blue = self.color.blue.saturating_add(blue_delta);
} else {
red = self.color.red.saturating_sub(red_delta);
green = self.color.green.saturating_sub(green_delta);
blue = self.color.blue.saturating_sub(blue_delta);
}
strip.fill(PixelColor { red, green, blue });
Some(strip)
}
}

76
src/patterns/rainbow.rs Normal file
View File

@ -0,0 +1,76 @@
use crate::patterns::PixelColor;
use crate::Strip;
use serde::{Serialize, Deserialize};
/// # Rainbow pattern
///
/// every pattern implement the iterator trait
///
/// This pattern display a moving rainbow over the strip
///
/// ### Note
///
/// If max iteration is let to None, it's an infinite pattern.
///
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Rainbow<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) max_iteration: Option<usize>,
pub(crate) step: Option<usize>,
}
impl<const N: usize> Iterator for Rainbow<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(nbr_iteration) = self.max_iteration {
if nbr_iteration == self.current_iteration {
return None;
}
}
let mut strip = Strip::default();
let step = self.step.unwrap_or(255 / N);
for i in 0..N {
let pos = (i * step + self.current_iteration) as u8;
strip[i] = wheel(pos)
}
self.current_iteration += 1;
Some(strip)
}
}
/// compute **rgb** pixel color according to the **hsv** wheel
///
/// # Arguments
///
/// * `index`: position in the hsv wheel
///
/// returns: PixelColor
///
fn wheel(index: u8) -> PixelColor {
let pos = 255 - index;
match pos {
0..=85 => PixelColor {
red: 255 - (pos * 3),
green: 0,
blue: pos * 3,
},
86..=170 => {
let pos = pos - 85;
PixelColor {
red: 0,
green: pos * 3,
blue: 255 - (pos * 3),
}
}
_ => {
let pos = pos - 170;
PixelColor {
red: pos * 3,
green: 255 - (pos * 3),
blue: 0,
}
}
}
}

45
src/patterns/scanner.rs Normal file
View File

@ -0,0 +1,45 @@
use crate::patterns::PixelColor;
use crate::Strip;
use serde::{Serialize, Deserialize};
/// # scanner pattern
/// color one pixel with a color and leave a train of this color fading to black
///
/// # note
///
/// background_color work only for color not set by scanner pattern
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Scanner<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) color: PixelColor,
pub(crate) background_color: Option<PixelColor>,
}
impl<const N: usize> Iterator for Scanner<N> {
type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> {
let mut strip = Strip::<N>::default();
if let Some(c) = self.background_color {
strip.fill(c);
} else {
strip.fill(PixelColor::default());
}
let current_led = self.current_iteration % N;
let min_led;
if current_led < 8 {
min_led = 0;
} else {
min_led = current_led - 8;
}
let mut c = self.color;
for i in min_led..current_led {
strip[i] = c;
c = c / 2;
}
self.current_iteration += 1;
Some(strip)
}
}

View File

@ -9,9 +9,33 @@ use std::str::FromStr;
use std::time::Duration;
use tokio::sync::watch::{Receiver, Sender};
pub(crate) mod period {
use std::time::Duration;
use serde::{de::Error as _, Deserialize, Deserializer};
/// Custom deserializer for period from millisecond value
///
/// # Arguments
///
/// * `deserializer`:
///
/// returns: Result<Duration, <D as Deserializer>::Error>
///
pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(deserializer)?
.parse::<u64>().and_then(|d| Ok(Duration::from_millis(d)))
.map_err(|e| D::Error::custom(format!("{}", e)))
}
}
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Context<const N: usize> {
pub(crate) pattern: Patterns<N>,
#[serde(deserialize_with = "period::deserialize")]
pub period: Duration,
}
@ -42,7 +66,7 @@ pub struct Spectacle<const N: usize> {
impl<const N: usize> Spectacle<N> {
pub fn add(&mut self, mac_address: Address, runner: &DeviceSequence<N>) {
if let Some((_, rx)) = self.runners.get(&runner as &DeviceSequence<N>) {
if let Some((_, rx)) = self.runners.get(runner as &DeviceSequence<N>) {
self.channels.insert(mac_address, rx.clone());
} else {
let (tx, rx) = tokio::sync::watch::channel(Strip::<N>::new(PixelColor {
@ -98,7 +122,7 @@ impl<const N: usize> Spectacle<N> {
pub fn run(&mut self) -> Vec<impl Future<Output = ()>> {
let mut joinhandles = vec![];
if let Some(_) = &self.default_runner {
if self.default_runner.is_some() {
let d = std::mem::take(&mut self.default_runner).unwrap();
joinhandles.push(runner_loop(d.0.clone(), d.1));
println!("add default runner loop");