diff --git a/src/Dixon/version.txt b/src/Dixon/version.txt index 593b66a..15e23ae 100644 --- a/src/Dixon/version.txt +++ b/src/Dixon/version.txt @@ -1 +1 @@ -1.0.70 \ No newline at end of file +1.0.71 \ No newline at end of file diff --git a/src/rustylee/src/brain.rs b/src/rustylee/src/brain.rs index f090f80..9a9765a 100644 --- a/src/rustylee/src/brain.rs +++ b/src/rustylee/src/brain.rs @@ -127,7 +127,7 @@ impl Brain { fn request_heart_beat(&self) { if let Some(socket) = self.organ_sockets.first() { let envelope = OrganCommandEnvelope { - command: OrganCommand::Beat(0), + command: OrganCommand::HeartBeat(0), issued_at: Time::time_stamp_millis(), }; diff --git a/src/rustylee/src/macros.rs b/src/rustylee/src/macros.rs new file mode 100644 index 0000000..ecd15ad --- /dev/null +++ b/src/rustylee/src/macros.rs @@ -0,0 +1 @@ +pub mod identifiable; \ No newline at end of file diff --git a/src/rustylee/src/macros/identifiable.rs b/src/rustylee/src/macros/identifiable.rs new file mode 100644 index 0000000..61ded7f --- /dev/null +++ b/src/rustylee/src/macros/identifiable.rs @@ -0,0 +1,12 @@ +#[macro_export] +macro_rules! impl_identifiable { + ($target:ident, { $($body:tt)* }) => { + impl Parenchyma for $target { + fn id(&self) -> u32 { + self.id + } + + $($body)* + } + }; +} \ No newline at end of file diff --git a/src/rustylee/src/main.rs b/src/rustylee/src/main.rs index 09e5789..6d9821f 100644 --- a/src/rustylee/src/main.rs +++ b/src/rustylee/src/main.rs @@ -4,6 +4,7 @@ pub mod organs; pub mod coordinates; pub mod protocols; pub mod system; +pub mod macros; use std::fmt::Alignment::Left; use tracing::{debug, info}; diff --git a/src/rustylee/src/organs.rs b/src/rustylee/src/organs.rs index 22f903c..bce2e32 100644 --- a/src/rustylee/src/organs.rs +++ b/src/rustylee/src/organs.rs @@ -1,4 +1,6 @@ -pub mod heart; pub mod organ; pub mod organ_socket; pub mod organ_factory; +pub mod led_pump; +pub mod parenchyma; + diff --git a/src/rustylee/src/organs/heart.rs b/src/rustylee/src/organs/heart.rs deleted file mode 100644 index 798c241..0000000 --- a/src/rustylee/src/organs/heart.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::sync::mpsc; -use std::sync::mpsc::{Receiver, Sender}; -use tracing::{debug, info, instrument}; -use crate::lifecycle::LifeState; -use crate::protocols::{BrainMessage, OrganCommand, OrganCommandEnvelope, OrganResponse}; -use crate::system::time::Time; - -pub struct Heart { - id: u32, - brain_command_rx: mpsc::Receiver, - feedback_to_brain_tx: mpsc::Sender, - last_beat_time: u64, - timestamp: u64, - life_state: LifeState, -} - -impl Heart { - pub(crate) fn new(id: u32, initial_life_state: LifeState, rx: Receiver, tx: Sender) -> Self { - Self { - id, - brain_command_rx: rx, - feedback_to_brain_tx: tx, - last_beat_time: 0, - timestamp: 0, - life_state: initial_life_state, - } - } - - #[instrument(skip(self), fields(heart_id = self.id))] - pub fn start(&mut self) { - info!("Heart listener active"); - - while let Ok(envelope) = self.brain_command_rx.recv() { - self.timestamp = Time::time_stamp_millis(); - debug!("Received brain command: {:?}", envelope); - - match envelope.command { - OrganCommand::Waken => { - self.wake_up(envelope); - } - - OrganCommand::Beat(_) => { - if self.ready_to_beat() { - self.beat(envelope); - } - } - _ => { - self.send_response_brain(envelope, OrganResponse::Ignored) - } - } - } - } - - fn ready_to_beat(&self) -> bool { - self.is_ready_state() && self.timestamp >= self.last_beat_time + 500 - } - - fn is_ready_state(&self) -> bool { - self.life_state == LifeState::Awake - } - - fn beat(&mut self, command_envelope: OrganCommandEnvelope) { - self.last_beat_time = self.timestamp; - debug!("Beat time: {}", self.last_beat_time); - self.send_response_brain(command_envelope, OrganResponse::Ok); - } - - fn wake_up(&mut self, command_envelope: OrganCommandEnvelope) { - self.life_state = LifeState::Awake; - debug!("Awake"); - self.send_response_brain(command_envelope, OrganResponse::Ok); - } - - fn send_response_brain(&self, command_envelope: OrganCommandEnvelope, response: OrganResponse) { - - let reply = BrainMessage { - organ_command: command_envelope, - responded_at: Time::time_stamp_millis(), - organ_id: self.id, - response, - }; - - info!(?reply, "Sending response to Brain"); - let _ = self.feedback_to_brain_tx.send(reply); - } -} - - diff --git a/src/rustylee/src/organs/led_pump.rs b/src/rustylee/src/organs/led_pump.rs new file mode 100644 index 0000000..06972a0 --- /dev/null +++ b/src/rustylee/src/organs/led_pump.rs @@ -0,0 +1,28 @@ +use crate::impl_identifiable; +use crate::organs::parenchyma::Parenchyma; +use crate::protocols::{OrganCommand, OrganCommandEnvelope, OrganResponse}; + +pub struct LedPump { + id: u32, + last_beat: u128, +} + +impl_identifiable!(LedPump, { + fn do_work(&mut self, _envelope: OrganCommandEnvelope) -> OrganResponse { + // Your logic here + OrganResponse::Ok + } + + fn get_supported_commands(&self) -> Vec { + vec![OrganCommand::HeartBeat(0)] + } +}); + +impl LedPump { + pub fn new(id: u32) -> Self { + Self { + id, + last_beat: 0 + } + } +} \ No newline at end of file diff --git a/src/rustylee/src/organs/organ.rs b/src/rustylee/src/organs/organ.rs index 16cf238..069ca27 100644 --- a/src/rustylee/src/organs/organ.rs +++ b/src/rustylee/src/organs/organ.rs @@ -1,9 +1,128 @@ -use crate::coordinates::Point3D; +use std::sync::mpsc; +use std::sync::mpsc::{Receiver, Sender}; +use tracing::{debug, info, instrument}; use crate::lifecycle::LifeState; +use crate::organs::parenchyma::Parenchyma; +use crate::protocols::{BrainMessage, OrganCommand, OrganCommandEnvelope, OrganResponse}; +use crate::system::time::Time; -pub trait Organ: Send { - /// Returns the immutable U32 ID assigned by the factory. - fn id(&self) -> u32; -} \ No newline at end of file +// pub trait Organ: Send { +// /// Returns the immutable U32 ID assigned by the factory. +// fn id(&self) -> u32; +// +// fn add_parenchyma(&mut self, parenchyma: Box); +// } + + +pub struct Organ { + id: u32, + brain_command_rx: mpsc::Receiver, + feedback_to_brain_tx: mpsc::Sender, + last_work_done_time: u64, + timestamp: u64, + life_state: LifeState, + parenchymas: Vec>, + supported_commands: Vec, +} + +impl Organ { + pub(crate) fn new( + id: u32, initial_life_state: + LifeState, + rx: Receiver, + tx: Sender) -> Self { + Self { + id, + brain_command_rx: rx, + feedback_to_brain_tx: tx, + last_work_done_time: 0, + timestamp: 0, + life_state: initial_life_state, + parenchymas: Vec::new(), + supported_commands: Vec::new(), + } + } + + #[instrument(skip(self), fields(heart_id = self.id))] + pub fn start(&mut self) { + info!("Heart listener active"); + + while let Ok(envelope) = self.brain_command_rx.recv() { + self.timestamp = Time::time_stamp_millis(); + debug!("Received brain command: {:?}", envelope); + + match envelope.command { + OrganCommand::Waken => { + self.wake_up(envelope); + } + + OrganCommand::HeartBeat(_) => { + if self.is_ready() { + self.process_command(envelope); + } + } + _ => { + self.send_response_brain(envelope, OrganResponse::Ignored) + } + } + } + } + + pub fn add_parenchyma(&mut self, component: Box) { + + let new_commands = component.get_supported_commands(); + + for command in new_commands { + if !self.supported_commands.contains(&command) { + self.supported_commands.push(command); + } + } + + self.parenchymas.push(component); + } + + pub fn is_supported(&self, command:OrganCommand) -> bool { + self.supported_commands.contains(&command) + } + + fn is_ready(&self) -> bool { + self.is_ready_state() && self.timestamp >= self.last_work_done_time + 500 + } + + fn is_ready_state(&self) -> bool { + self.life_state == LifeState::Awake + } + + fn process_command (&mut self, command_envelope: OrganCommandEnvelope) { + self.last_work_done_time = self.timestamp; + debug!("Work time: {}", self.last_work_done_time); + + for part in &mut self.parenchymas { + part.do_work(command_envelope); + } + + self.send_response_brain(command_envelope, OrganResponse::Ok); + } + + fn wake_up(&mut self, command_envelope: OrganCommandEnvelope) { + self.life_state = LifeState::Awake; + debug!("Awake"); + self.send_response_brain(command_envelope, OrganResponse::Ok); + } + + fn send_response_brain(&self, command_envelope: OrganCommandEnvelope, response: OrganResponse) { + + let reply = BrainMessage { + organ_command: command_envelope, + responded_at: Time::time_stamp_millis(), + organ_id: self.id, + response, + }; + + info!(?reply, "Sending response to Brain"); + let _ = self.feedback_to_brain_tx.send(reply); + } +} + diff --git a/src/rustylee/src/organs/organ_factory.rs b/src/rustylee/src/organs/organ_factory.rs index 1e90e70..4cd9094 100644 --- a/src/rustylee/src/organs/organ_factory.rs +++ b/src/rustylee/src/organs/organ_factory.rs @@ -1,14 +1,19 @@ +use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; use std::sync::mpsc::{self, Receiver, Sender}; use std::thread; use crate::lifecycle::LifeState; +use crate::organs::led_pump::LedPump; use crate::organs::organ_socket::OrganSocket; -use crate::organs::heart::Heart; // Assuming Heart is our first organ +use crate::organs::organ; +use crate::organs::organ::Organ; use crate::protocols::{OrganCommandEnvelope, BrainMessage}; pub struct OrganFactory { brain_tx: Sender, } +static NEXT_ORGAN_ID: AtomicU32 = AtomicU32::new(1000000); + impl OrganFactory { pub(crate) fn new(brain_sender: Sender) -> Self { Self { @@ -18,24 +23,44 @@ impl OrganFactory { } impl OrganFactory { + + fn next_organ_id() -> u32 { + NEXT_ORGAN_ID.fetch_add(1000000, Ordering::SeqCst) + } + + fn next_parenchyma_id(last_parenchyma_id_for_organ:u32) -> u32 { + last_parenchyma_id_for_organ+1 + } + pub fn build_organs(brain_tx: Sender) -> Vec { let mut sockets = Vec::new(); - let mut ids = 1..; + // let mut ids = 1..; - sockets.push(Self::spawn_heart(ids.next().unwrap(), brain_tx.clone())); + sockets.push(Self::spawn_heart(brain_tx.clone())); tracing::info!(count = sockets.len(), "Organ collection built and threads spawned"); sockets } - fn spawn_heart(id: u32, feedback_to_brain_tx: Sender) -> OrganSocket { + fn spawn_heart(feedback_to_brain_tx: Sender) -> OrganSocket { let initial_life_state = LifeState::Dead; let (brain_command_to_organ_tx, brain_command_to_organ_rx) = Self::get_organ_channels(); - let socket = OrganSocket::new(id, initial_life_state, brain_command_to_organ_tx); + let organ_id = OrganFactory::next_organ_id(); + let socket = OrganSocket::new(organ_id, initial_life_state, brain_command_to_organ_tx); thread::spawn(move || { - let mut heart = Heart::new(id, initial_life_state, brain_command_to_organ_rx, feedback_to_brain_tx); + let mut heart = Organ::new( + organ_id, + initial_life_state, + brain_command_to_organ_rx, + feedback_to_brain_tx + ); + + + let last_parenchyma_id = organ_id; + let led_pump = LedPump::new(OrganFactory::next_parenchyma_id(last_parenchyma_id)); + heart.add_parenchyma(Box::new(led_pump)); heart.start(); }); diff --git a/src/rustylee/src/organs/parenchyma.rs b/src/rustylee/src/organs/parenchyma.rs new file mode 100644 index 0000000..b223568 --- /dev/null +++ b/src/rustylee/src/organs/parenchyma.rs @@ -0,0 +1,13 @@ + +/* + Parenchyma: The essential and distinctive functional tissue of an organ, + as distinguished from its connective tissue, blood vessels, + and nerves (the stroma) + */ +use crate::protocols::{OrganCommand, OrganCommandEnvelope, OrganResponse}; + +pub trait Parenchyma: Send { + fn id(&self) -> u32; + fn do_work (&mut self, command_envelope: OrganCommandEnvelope) -> OrganResponse; + fn get_supported_commands(&self) -> Vec; +} \ No newline at end of file diff --git a/src/rustylee/src/protocols.rs b/src/rustylee/src/protocols.rs index 02e72a1..7bad7c4 100644 --- a/src/rustylee/src/protocols.rs +++ b/src/rustylee/src/protocols.rs @@ -1,12 +1,13 @@ +use std::ffi::CString; use crate::coordinates::Point3D; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum OrganCommand { // Sleep, Waken, // Pause, // Resume, - Beat (u32), + HeartBeat(u32), // ChangeSpeed (u32), // GoFaster(u32), // GoSlower(u32), @@ -22,8 +23,26 @@ pub enum OrganResponse { Ignored, Rejected } +#[derive(Debug)] +pub enum TelemetryControlPlaneData { + AppendagePosition { + space: Point3D, + time: u64, + }, + BeatIntervalMillis(u32), +} #[derive(Debug)] +pub struct OrganMessage { + pub organ_id: u32, + pub organ_component_id: u32, + pub organ_command: Option, + pub last_response: Option, + pub message:Option, + pub telemetry:Option, +} + +#[derive(Debug, Clone, Copy)] pub struct OrganCommandEnvelope { pub command: OrganCommand, pub issued_at: u64 @@ -35,4 +54,5 @@ pub struct BrainMessage { pub responded_at: u64, pub organ_id: u32, pub response: OrganResponse, -} \ No newline at end of file +} +