Skip to content

Commit 033c995

Browse files
committed
move to CCSDS + serde for sat-rs example
1 parent d7e6732 commit 033c995

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1618
-2451
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ members = [
44
"satrs",
55
"satrs-mib",
66
"satrs-example",
7-
"satrs-minisim",
7+
"satrs-example/models",
8+
"satrs-example/client",
9+
"satrs-example/minisim",
810
"satrs-shared",
911
"embedded-examples/embedded-client",
1012
]

satrs-example/Cargo.toml

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,18 @@ derive-new = "0.7"
2323
cfg-if = "1"
2424
arbitrary-int = "2"
2525
bitbybit = "1.4"
26+
postcard = "1"
2627
serde = { version = "1", features = ["derive"] }
2728
serde_json = "1"
2829

29-
[dependencies.satrs]
30-
path = "../satrs"
31-
features = ["test_util"]
32-
33-
[dependencies.satrs-minisim]
34-
path = "../satrs-minisim"
35-
36-
[dependencies.satrs-mib]
37-
version = "0.1.1"
38-
path = "../satrs-mib"
30+
satrs = { path = "../satrs", features = ["test_util"] }
31+
models = { path = "./models" }
32+
satrs-minisim = { path = "./minisim" }
33+
satrs-mib = { path = "../satrs-mib" }
3934

4035
[features]
41-
default = ["heap_tmtc"]
42-
heap_tmtc = []
36+
# default = ["heap_tmtc"]
37+
# heap_tmtc = []
4338

4439
[dev-dependencies]
4540
env_logger = "0.11"

satrs-example/client/Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "client"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
clap = { version = "4", features = ["derive"] }
8+
log = "0.4"
9+
fern = "0.7"
10+
humantime = "2"
11+
serde = { version = "1" }
12+
satrs-example = { path = ".." }
13+
models = { path = "../models" }
14+
spacepackets = { version = "0.17", git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git", default-features = false }
15+
bitbybit = "1.4"
16+
arbitrary-int = "2"
17+
ctrlc = { version = "3.5" }
18+
postcard = { version = "1" }
19+
anyhow = "1"

satrs-example/client/src/main.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
use anyhow::bail;
2+
use arbitrary_int::u11;
3+
use clap::Parser as _;
4+
use models::{Apid, TcHeader};
5+
use satrs_example::config::{OBSW_SERVER_ADDR, SERVER_PORT};
6+
use spacepackets::{CcsdsPacketIdAndPsc, SpacePacketHeader};
7+
use std::{
8+
net::{IpAddr, SocketAddr, UdpSocket},
9+
sync::{
10+
Arc,
11+
atomic::{AtomicBool, Ordering},
12+
},
13+
time::{Duration, SystemTime},
14+
};
15+
16+
#[derive(clap::Parser)]
17+
pub struct Cli {
18+
#[arg(short, long)]
19+
ping: bool,
20+
}
21+
22+
fn setup_logger(level: log::LevelFilter) -> Result<(), fern::InitError> {
23+
fern::Dispatch::new()
24+
.format(|out, message, record| {
25+
out.finish(format_args!(
26+
"[{} {} {}] {}",
27+
humantime::format_rfc3339_seconds(SystemTime::now()),
28+
record.level(),
29+
record.target(),
30+
message
31+
))
32+
})
33+
.level(level)
34+
.chain(std::io::stdout())
35+
.chain(fern::log_file("output.log")?)
36+
.apply()?;
37+
Ok(())
38+
}
39+
40+
fn main() -> anyhow::Result<()> {
41+
setup_logger(log::LevelFilter::Debug).unwrap();
42+
let kill_signal = Arc::new(AtomicBool::new(false));
43+
let ctrl_kill_signal = kill_signal.clone();
44+
ctrlc::set_handler(move || ctrl_kill_signal.store(true, Ordering::Relaxed)).unwrap();
45+
let cli = Cli::parse();
46+
47+
let addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), SERVER_PORT);
48+
let client = UdpSocket::bind("127.0.0.1:7302").expect("Connecting to UDP server failed");
49+
client.set_nonblocking(true)?;
50+
client.set_read_timeout(Some(Duration::from_millis(200)))?;
51+
52+
if cli.ping {
53+
let request = models::ccsds::CcsdsTcPacketOwned::new_with_request(
54+
SpacePacketHeader::new_from_apid(u11::new(Apid::Tmtc as u16)),
55+
TcHeader::new(models::ComponentId::Controller, models::MessageType::Ping),
56+
models::control::request::Request::Ping,
57+
);
58+
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
59+
log::info!("sending ping request with TC ID {:#010x}", sent_tc_id.raw());
60+
let request_packet = request.to_vec();
61+
client.send_to(&request_packet, addr).unwrap();
62+
}
63+
64+
let mut recv_buf: Box<[u8; 2048]> = Box::new([0; 2048]);
65+
loop {
66+
if kill_signal.load(std::sync::atomic::Ordering::Relaxed) {
67+
log::info!("received kill signal, exiting");
68+
break;
69+
}
70+
match client.recv(recv_buf.as_mut_slice()) {
71+
Ok(received_bytes) => handle_raw_tm_packet(&recv_buf.as_slice()[0..received_bytes])?,
72+
Err(e) => {
73+
if e.kind() == std::io::ErrorKind::WouldBlock
74+
|| e.kind() == std::io::ErrorKind::TimedOut
75+
{
76+
continue;
77+
}
78+
log::warn!("UDP reception error: {}", e)
79+
}
80+
}
81+
}
82+
Ok(())
83+
}
84+
85+
fn handle_raw_tm_packet(data: &[u8]) -> anyhow::Result<()> {
86+
match spacepackets::CcsdsPacketReader::new_with_checksum(data) {
87+
Ok(packet) => {
88+
//let (tm_header, response, remainder) = unpack_tm_header_and_response(&packet)?;
89+
let tm_header_result =
90+
postcard::take_from_bytes::<models::TmHeader>(packet.user_data());
91+
if let Err(e) = tm_header_result {
92+
bail!("Failed to deserialize TM header: {}", e);
93+
}
94+
let (tm_header, remainder) = tm_header_result.unwrap();
95+
if let Some(tc_id) = tm_header.tc_id {
96+
log::info!(
97+
"Received TM with APID {} and from sender {:?} for TC ID {:#010x}",
98+
packet.apid(),
99+
tm_header.sender_id,
100+
tc_id.raw()
101+
);
102+
} else {
103+
log::info!(
104+
"Received unsolicited TM with APID {} and from sender {:?}",
105+
packet.apid(),
106+
tm_header.sender_id,
107+
);
108+
}
109+
match tm_header.sender_id {
110+
models::ComponentId::Pcdu => todo!(),
111+
models::ComponentId::Controller => {
112+
let response =
113+
postcard::from_bytes::<models::control::response::Response>(remainder);
114+
log::info!("Received response from controller: {:?}", response.unwrap());
115+
}
116+
models::ComponentId::AcsSubsystem => todo!(),
117+
models::ComponentId::AcsMgmAssembly => todo!(),
118+
models::ComponentId::AcsMgm0 => todo!(),
119+
models::ComponentId::AcsMgm1 => todo!(),
120+
models::ComponentId::EpsSubsystem => todo!(),
121+
models::ComponentId::EpsPcdu => todo!(),
122+
models::ComponentId::UdpServer => todo!(),
123+
models::ComponentId::TcpServer => todo!(),
124+
models::ComponentId::Ground => todo!(),
125+
models::ComponentId::EventManager => todo!(),
126+
}
127+
}
128+
Err(_) => todo!(),
129+
}
130+
Ok(())
131+
}
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@ strum = { version = "0.27", features = ["derive"] }
1515
num_enum = "0.7"
1616
humantime = "2"
1717
tai-time = { version = "0.3", features = ["serde"] }
18+
nexosim = { version = "0.3.1" }
1819

19-
[dependencies.nexosim]
20-
version = "0.3.1"
21-
22-
[dependencies.satrs]
23-
path = "../satrs"
20+
satrs = { path = "../../satrs" }
21+
models = { path = "../models" }
2422

2523
[dev-dependencies]
2624
delegate = "0.13"
File renamed without changes.
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use std::{f32::consts::PI, sync::mpsc, time::Duration};
22

3+
use models::pcdu::SwitchStateBinary;
34
use nexosim::{
45
model::{Context, Model},
56
ports::Output,
67
};
7-
use satrs::power::SwitchStateBinary;
88
use satrs_minisim::{
99
acs::{
1010
lis3mdl::MgmLis3MdlReply, MgmReplyCommon, MgmReplyProvider, MgmSensorValuesMicroTesla,
@@ -179,13 +179,12 @@ impl Model for MagnetorquerModel {}
179179
pub mod tests {
180180
use std::time::Duration;
181181

182-
use satrs::power::SwitchStateBinary;
182+
use models::pcdu::{SwitchId, SwitchStateBinary};
183183
use satrs_minisim::{
184184
acs::{
185185
lis3mdl::{self, MgmLis3MdlReply},
186186
MgmRequestLis3Mdl, MgtDipole, MgtHkSet, MgtReply, MgtRequest,
187187
},
188-
eps::PcduSwitch,
189188
SerializableSimMsgPayload, SimComponent, SimMessageProvider, SimRequest,
190189
};
191190

@@ -215,7 +214,7 @@ pub mod tests {
215214
#[test]
216215
fn test_basic_mgm_request_switched_on() {
217216
let mut sim_testbench = SimTestbench::new();
218-
switch_device_on(&mut sim_testbench, PcduSwitch::Mgm);
217+
switch_device_on(&mut sim_testbench, SwitchId::Mgm0);
219218

220219
let mut request = SimRequest::new_with_epoch_time(MgmRequestLis3Mdl::RequestSensorData);
221220
sim_testbench
@@ -279,7 +278,7 @@ pub mod tests {
279278
#[test]
280279
fn test_basic_mgt_request_is_on() {
281280
let mut sim_testbench = SimTestbench::new();
282-
switch_device_on(&mut sim_testbench, PcduSwitch::Mgt);
281+
switch_device_on(&mut sim_testbench, SwitchId::Mgt);
283282
let request = SimRequest::new_with_epoch_time(MgtRequest::RequestHk);
284283

285284
sim_testbench
@@ -324,7 +323,7 @@ pub mod tests {
324323
#[test]
325324
fn test_basic_mgt_request_is_on_and_torquing() {
326325
let mut sim_testbench = SimTestbench::new();
327-
switch_device_on(&mut sim_testbench, PcduSwitch::Mgt);
326+
switch_device_on(&mut sim_testbench, SwitchId::Mgt);
328327
let commanded_dipole = MgtDipole {
329328
x: -200,
330329
y: 200,
Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
use std::{sync::mpsc, time::Duration};
22

3+
use models::pcdu::{SwitchId, SwitchMapBinaryWrapper, SwitchStateBinary};
34
use nexosim::{
45
model::{Context, Model},
56
ports::Output,
67
};
7-
use satrs::power::SwitchStateBinary;
8-
use satrs_minisim::{
9-
eps::{PcduReply, PcduSwitch, SwitchMapBinaryWrapper},
10-
SimReply,
11-
};
8+
use satrs_minisim::{eps::PcduReply, SimReply};
129

1310
pub const SWITCH_INFO_DELAY_MS: u64 = 10;
1411

@@ -45,23 +42,21 @@ impl PcduModel {
4542
self.reply_sender.send(reply).unwrap();
4643
}
4744

48-
pub async fn switch_device(
49-
&mut self,
50-
switch_and_target_state: (PcduSwitch, SwitchStateBinary),
51-
) {
45+
pub async fn switch_device(&mut self, switch_and_target_state: (SwitchId, SwitchStateBinary)) {
5246
let val = self
5347
.switcher_map
5448
.0
5549
.get_mut(&switch_and_target_state.0)
5650
.unwrap_or_else(|| panic!("switch {:?} not found", switch_and_target_state.0));
5751
*val = switch_and_target_state.1;
5852
match switch_and_target_state.0 {
59-
PcduSwitch::Mgm => {
53+
SwitchId::Mgm0 => {
6054
self.mgm_0_switch.send(switch_and_target_state.1).await;
6155
}
62-
PcduSwitch::Mgt => {
56+
SwitchId::Mgt => {
6357
self.mgt_switch.send(switch_and_target_state.1).await;
6458
}
59+
SwitchId::Mgm1 => todo!(),
6560
}
6661
}
6762
}
@@ -73,16 +68,16 @@ pub(crate) mod tests {
7368
use super::*;
7469
use std::time::Duration;
7570

71+
use models::pcdu::SwitchMapBinary;
7672
use satrs_minisim::{
77-
eps::{PcduRequest, SwitchMapBinary},
78-
SerializableSimMsgPayload, SimComponent, SimMessageProvider, SimRequest,
73+
eps::PcduRequest, SerializableSimMsgPayload, SimComponent, SimMessageProvider, SimRequest,
7974
};
8075

8176
use crate::test_helpers::SimTestbench;
8277

8378
fn switch_device(
8479
sim_testbench: &mut SimTestbench,
85-
switch: PcduSwitch,
80+
switch: SwitchId,
8681
target: SwitchStateBinary,
8782
) {
8883
let request = SimRequest::new_with_epoch_time(PcduRequest::SwitchDevice {
@@ -97,10 +92,10 @@ pub(crate) mod tests {
9792
}
9893

9994
#[allow(dead_code)]
100-
pub(crate) fn switch_device_off(sim_testbench: &mut SimTestbench, switch: PcduSwitch) {
95+
pub(crate) fn switch_device_off(sim_testbench: &mut SimTestbench, switch: SwitchId) {
10196
switch_device(sim_testbench, switch, SwitchStateBinary::Off);
10297
}
103-
pub(crate) fn switch_device_on(sim_testbench: &mut SimTestbench, switch: PcduSwitch) {
98+
pub(crate) fn switch_device_on(sim_testbench: &mut SimTestbench, switch: SwitchId) {
10499
switch_device(sim_testbench, switch, SwitchStateBinary::On);
105100
}
106101

@@ -128,7 +123,7 @@ pub(crate) mod tests {
128123
}
129124
}
130125

131-
fn test_pcdu_switching_single_switch(switch: PcduSwitch, target: SwitchStateBinary) {
126+
fn test_pcdu_switching_single_switch(switch: SwitchId, target: SwitchStateBinary) {
132127
let mut sim_testbench = SimTestbench::new();
133128
switch_device(&mut sim_testbench, switch, target);
134129
let mut switcher_map = get_all_off_switch_map();
@@ -165,17 +160,17 @@ pub(crate) mod tests {
165160

166161
#[test]
167162
fn test_pcdu_switching_mgm_on() {
168-
test_pcdu_switching_single_switch(PcduSwitch::Mgm, SwitchStateBinary::On);
163+
test_pcdu_switching_single_switch(SwitchId::Mgm0, SwitchStateBinary::On);
169164
}
170165

171166
#[test]
172167
fn test_pcdu_switching_mgt_on() {
173-
test_pcdu_switching_single_switch(PcduSwitch::Mgt, SwitchStateBinary::On);
168+
test_pcdu_switching_single_switch(SwitchId::Mgt, SwitchStateBinary::On);
174169
}
175170

176171
#[test]
177172
fn test_pcdu_switching_mgt_off() {
178-
test_pcdu_switching_single_switch(PcduSwitch::Mgt, SwitchStateBinary::On);
179-
test_pcdu_switching_single_switch(PcduSwitch::Mgt, SwitchStateBinary::Off);
173+
test_pcdu_switching_single_switch(SwitchId::Mgt, SwitchStateBinary::On);
174+
test_pcdu_switching_single_switch(SwitchId::Mgt, SwitchStateBinary::Off);
180175
}
181176
}

0 commit comments

Comments
 (0)