Skip to content

Commit

Permalink
the PCDU handler is already required
Browse files Browse the repository at this point in the history
  • Loading branch information
robamu committed May 11, 2024
1 parent 37b32a9 commit 7606767
Show file tree
Hide file tree
Showing 7 changed files with 338 additions and 105 deletions.
43 changes: 25 additions & 18 deletions satrs-example/src/acs/mgm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use satrs::spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader};
use satrs::spacepackets::SpHeader;
use satrs_example::{DeviceMode, TimestampHelper};
use satrs_minisim::acs::lis3mdl::{
MgmLis3MdlReply, FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR,
MgmLis3MdlReply, MgmLis3RawValues, FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR,
};
use satrs_minisim::acs::MgmRequestLis3Mdl;
use satrs_minisim::{SerializableSimMsgPayload, SimReply, SimRequest};
Expand Down Expand Up @@ -47,18 +47,16 @@ pub trait SpiInterface {

#[derive(Default)]
pub struct SpiDummyInterface {
pub dummy_val_0: i16,
pub dummy_val_1: i16,
pub dummy_val_2: i16,
pub dummy_values: MgmLis3RawValues,
}

impl SpiInterface for SpiDummyInterface {
type Error = ();

fn transfer(&mut self, _tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error> {
rx[X_LOWBYTE_IDX..X_LOWBYTE_IDX + 2].copy_from_slice(&self.dummy_val_0.to_le_bytes());
rx[Y_LOWBYTE_IDX..Y_LOWBYTE_IDX + 2].copy_from_slice(&self.dummy_val_1.to_be_bytes());
rx[Z_LOWBYTE_IDX..Z_LOWBYTE_IDX + 2].copy_from_slice(&self.dummy_val_2.to_be_bytes());
rx[X_LOWBYTE_IDX..X_LOWBYTE_IDX + 2].copy_from_slice(&self.dummy_values.x.to_le_bytes());
rx[Y_LOWBYTE_IDX..Y_LOWBYTE_IDX + 2].copy_from_slice(&self.dummy_values.y.to_be_bytes());
rx[Z_LOWBYTE_IDX..Z_LOWBYTE_IDX + 2].copy_from_slice(&self.dummy_values.z.to_be_bytes());
Ok(())
}
}
Expand All @@ -74,18 +72,27 @@ impl SpiInterface for SpiSimInterface {
// Right now, we only support requesting sensor data and not configuration of the sensor.
fn transfer(&mut self, _tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error> {
let mgm_sensor_request = MgmRequestLis3Mdl::RequestSensorData;
self.sim_request_tx
if let Err(e) = self
.sim_request_tx
.send(SimRequest::new_with_epoch_time(mgm_sensor_request))
.expect("failed to send request");
let sim_reply = self
.sim_reply_rx
.recv_timeout(Duration::from_millis(100))
.expect("reply timeout");
let sim_reply_lis3 =
MgmLis3MdlReply::from_sim_message(&sim_reply).expect("failed to parse LIS3 reply");
rx[X_LOWBYTE_IDX..X_LOWBYTE_IDX + 2].copy_from_slice(&sim_reply_lis3.raw.x.to_le_bytes());
rx[Y_LOWBYTE_IDX..Y_LOWBYTE_IDX + 2].copy_from_slice(&sim_reply_lis3.raw.y.to_le_bytes());
rx[Z_LOWBYTE_IDX..Z_LOWBYTE_IDX + 2].copy_from_slice(&sim_reply_lis3.raw.z.to_le_bytes());
{
log::error!("failed to send MGM LIS3 request: {}", e);
}
match self.sim_reply_rx.recv_timeout(Duration::from_millis(50)) {
Ok(sim_reply) => {
let sim_reply_lis3 = MgmLis3MdlReply::from_sim_message(&sim_reply)
.expect("failed to parse LIS3 reply");
rx[X_LOWBYTE_IDX..X_LOWBYTE_IDX + 2]
.copy_from_slice(&sim_reply_lis3.raw.x.to_le_bytes());
rx[Y_LOWBYTE_IDX..Y_LOWBYTE_IDX + 2]
.copy_from_slice(&sim_reply_lis3.raw.y.to_le_bytes());
rx[Z_LOWBYTE_IDX..Z_LOWBYTE_IDX + 2]
.copy_from_slice(&sim_reply_lis3.raw.z.to_le_bytes());
}
Err(e) => {
log::warn!("MGM LIS3 SIM reply timeout: {}", e);
}
}
Ok(())
}
}
Expand Down
1 change: 1 addition & 0 deletions satrs-example/src/eps/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod pcdu;
44 changes: 44 additions & 0 deletions satrs-example/src/eps/pcdu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::{
collections::HashMap,
sync::{mpsc, Arc, Mutex},
};

use derive_new::new;
use satrs::{
mode::ModeAndSubmode,
power::SwitchState,
pus::EcssTmSender,
request::{GenericMessage, UniqueApidTargetId},
};
use satrs_example::TimestampHelper;

use crate::{acs::mgm::MpscModeLeafInterface, pus::hk::HkReply, requests::CompositeRequest};

pub trait SerialInterface {}

#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum SwitchId {
Mgm0 = 0,
Mgt = 1,
}

pub type SwitchMap = HashMap<SwitchId, SwitchState>;

/// Example PCDU device handler.
#[derive(new)]
#[allow(clippy::too_many_arguments)]
pub struct PcduHandler<ComInterface: SerialInterface, TmSender: EcssTmSender> {
id: UniqueApidTargetId,
dev_str: &'static str,
mode_interface: MpscModeLeafInterface,
composite_request_rx: mpsc::Receiver<GenericMessage<CompositeRequest>>,
hk_reply_tx: mpsc::Sender<GenericMessage<HkReply>>,
tm_sender: TmSender,
pub com_interface: ComInterface,
shared_switch_map: Arc<Mutex<SwitchMap>>,
#[new(value = "ModeAndSubmode::new(satrs_example::DeviceMode::Off as u32, 0)")]
mode_and_submode: ModeAndSubmode,
#[new(default)]
stamp_helper: TimestampHelper,
}
1 change: 1 addition & 0 deletions satrs-example/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod acs;
mod eps;
mod events;
mod hk;
mod interface;
Expand Down
13 changes: 4 additions & 9 deletions satrs-minisim/src/acs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use satrs_minisim::{

use crate::time::current_millis;

// Earth magnetic field varies between -30 uT and 30 uT
// Earth magnetic field varies between roughly -30 uT and 30 uT
const AMPLITUDE_MGM_UT: f32 = 30.0;
// Lets start with a simple frequency here.
const FREQUENCY_MGM: f32 = 1.0;
Expand All @@ -26,14 +26,9 @@ const PHASE_Z: f32 = 0.2;

/// Simple model for a magnetometer where the measure magnetic fields are modeled with sine waves.
///
/// Please note that that a more realistic MGM model wouold include the following components
/// which are not included here to simplify the model:
///
/// 1. It would probably generate signed [i16] values which need to be converted to SI units
/// because it is a digital sensor
/// 2. It would sample the magnetic field at a high fixed rate. This might not be possible for
/// a general purpose OS, but self self-sampling at a relatively high rate (20-40 ms) might
/// stil lbe possible.
/// An ideal sensor would sample the magnetic field at a high fixed rate. This might not be
/// possible for a general purpose OS, but self self-sampling at a relatively high rate (20-40 ms)
/// might still be possible and is probably sufficient for many OBSW needs.
pub struct MagnetometerModel<ReplyProvider: MgmReplyProvider> {
pub switch_state: SwitchStateBinary,
pub periodicity: Duration,
Expand Down
53 changes: 33 additions & 20 deletions satrs-minisim/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ pub mod acs {
y: -30.0,
z: 30.0,
};
pub const ALL_ONES_SENSOR_VAL: i16 = 0xffff_u16 as i16;

pub mod lis3mdl {
use super::*;
Expand Down Expand Up @@ -264,27 +265,39 @@ pub mod acs {

impl MgmLis3MdlReply {
pub fn new(common: MgmReplyCommon) -> Self {
let mut raw_reply: [u8; 7] = [0; 7];
let raw_x: i16 = (common.sensor_values.x
/ (GAUSS_TO_MICROTESLA_FACTOR as f32 * FIELD_LSB_PER_GAUSS_4_SENS))
.round() as i16;
let raw_y: i16 = (common.sensor_values.y
/ (GAUSS_TO_MICROTESLA_FACTOR as f32 * FIELD_LSB_PER_GAUSS_4_SENS))
.round() as i16;
let raw_z: i16 = (common.sensor_values.z
/ (GAUSS_TO_MICROTESLA_FACTOR as f32 * FIELD_LSB_PER_GAUSS_4_SENS))
.round() as i16;
// The first byte is a dummy byte.
raw_reply[1..3].copy_from_slice(&raw_x.to_be_bytes());
raw_reply[3..5].copy_from_slice(&raw_y.to_be_bytes());
raw_reply[5..7].copy_from_slice(&raw_z.to_be_bytes());
Self {
common,
raw: MgmLis3RawValues {
x: raw_x,
y: raw_y,
z: raw_z,
match common.switch_state {
SwitchStateBinary::Off => Self {
common,
raw: MgmLis3RawValues {
x: ALL_ONES_SENSOR_VAL,
y: ALL_ONES_SENSOR_VAL,
z: ALL_ONES_SENSOR_VAL,
},
},
SwitchStateBinary::On => {
let mut raw_reply: [u8; 7] = [0; 7];
let raw_x: i16 = (common.sensor_values.x
/ (GAUSS_TO_MICROTESLA_FACTOR as f32 * FIELD_LSB_PER_GAUSS_4_SENS))
.round() as i16;
let raw_y: i16 = (common.sensor_values.y
/ (GAUSS_TO_MICROTESLA_FACTOR as f32 * FIELD_LSB_PER_GAUSS_4_SENS))
.round() as i16;
let raw_z: i16 = (common.sensor_values.z
/ (GAUSS_TO_MICROTESLA_FACTOR as f32 * FIELD_LSB_PER_GAUSS_4_SENS))
.round() as i16;
// The first byte is a dummy byte.
raw_reply[1..3].copy_from_slice(&raw_x.to_be_bytes());
raw_reply[3..5].copy_from_slice(&raw_y.to_be_bytes());
raw_reply[5..7].copy_from_slice(&raw_z.to_be_bytes());
Self {
common,
raw: MgmLis3RawValues {
x: raw_x,
y: raw_y,
z: raw_z,
},
}
}
}
}
}
Expand Down
Loading

0 comments on commit 7606767

Please sign in to comment.