diff --git a/gaia-stub/proto/broker.proto b/gaia-stub/proto/broker.proto index 298c4700..b26d734c 100644 --- a/gaia-stub/proto/broker.proto +++ b/gaia-stub/proto/broker.proto @@ -13,6 +13,7 @@ service Broker { rpc PostTelemetry(PostTelemetryRequest) returns (PostTelemetryResponse); rpc PostSetVR(PostSetVRRequest) returns (PostSetVRResponse); + rpc PostUnlock(PostUnlockRequest) returns (PostUnlockResponse); rpc PostADCommand(PostADCommandRequest) returns (PostADCommandResponse); rpc SubscribeFopFrameEvents(SubscribeFopFrameEventsRequest) returns (stream FopFrameEvent); } @@ -64,6 +65,10 @@ message PostSetVRRequest { message PostSetVRResponse { } +message PostUnlockRequest { } + +message PostUnlockResponse { } + message PostADCommandRequest { tco_tmiv.Tco tco = 1; } diff --git a/gaia-tmtc/src/broker.rs b/gaia-tmtc/src/broker.rs index 58c405db..3d83a7a4 100644 --- a/gaia-tmtc/src/broker.rs +++ b/gaia-tmtc/src/broker.rs @@ -47,6 +47,8 @@ pub enum FopFrameEvent { pub trait FopCommandService { async fn send_set_vr(&mut self, value: u8); + async fn send_unlock(&mut self); + async fn send_ad_command(&mut self, tco: Tco) -> Result; async fn subscribe_frame_events( @@ -107,6 +109,15 @@ where Ok(Response::new(PostSetVrResponse {})) } + #[tracing::instrument(skip(self))] + async fn post_unlock( + &self, + _request: Request, + ) -> Result, tonic::Status> { + self.fop_command_service.lock().await.send_unlock().await; + Ok(Response::new(PostUnlockResponse {})) + } + #[tracing::instrument(skip(self))] async fn post_ad_command( &self, diff --git a/tmtc-c2a/src/fop1.rs b/tmtc-c2a/src/fop1.rs index 040aa9b2..22cf2569 100644 --- a/tmtc-c2a/src/fop1.rs +++ b/tmtc-c2a/src/fop1.rs @@ -35,16 +35,15 @@ fn remove_acknowledged_frames( #[derive(Clone, Copy)] struct FarmState { next_expected_fsn: u8, - _lockout: bool, + lockout: bool, _wait: bool, retransmit: bool, } enum FopState { - Initial, Active(ActiveState), Retransmit(RetransmitState), - Initializing { expected_nr: u8 }, + Initial { expected_nr: Option }, } struct SentFrame { @@ -177,7 +176,7 @@ impl Fop { let (event_sender, _) = broadcast::channel(16); Self { next_frame_id: 0, - state: FopState::Initial, + state: FopState::Initial { expected_nr: None }, last_received_farm_state: None, event_sender, } @@ -191,7 +190,7 @@ impl Fop { tracing::debug!("Received CLCW: {:?}", clcw); let farm_state = FarmState { next_expected_fsn: clcw.report_value(), - _lockout: clcw.lockout() != 0, + lockout: clcw.lockout() != 0, _wait: clcw.wait() != 0, retransmit: clcw.retransmit() != 0, }; @@ -204,14 +203,11 @@ impl Fop { }; match &mut self.state { - FopState::Initial => { - // do nothing - } - FopState::Initializing { expected_nr } => { - if farm_state.next_expected_fsn == *expected_nr { + FopState::Initial { expected_nr } => { + if Some(farm_state.next_expected_fsn) == *expected_nr && !farm_state.lockout { tracing::info!("FOP initialized"); self.state = FopState::Active(ActiveState { - next_fsn: *expected_nr, + next_fsn: farm_state.next_expected_fsn, sent_queue: VecDeque::new(), }); } @@ -241,6 +237,38 @@ impl Fop { } } } + + if !farm_state.lockout { + return Ok(()); + } + + //lockout + let mut canceled_frames = VecDeque::new(); + match &mut self.state { + FopState::Initial { .. } => { + // do nothing + } + FopState::Active(state) => { + canceled_frames.append(&mut state.sent_queue); + self.state = FopState::Initial { + expected_nr: Some(state.next_fsn), + }; + } + FopState::Retransmit(state) => { + canceled_frames.append(&mut state.retransmit_sent_queue); + canceled_frames.append(&mut state.retransmit_wait_queue); + self.state = FopState::Initial { + expected_nr: Some(state.next_fsn), + }; + } + } + + for frame in canceled_frames { + self.event_sender + .send(FrameEvent::Cancel(frame.frame.id)) + .ok(); + } + Ok(()) } @@ -248,13 +276,10 @@ impl Fop { tracing::info!("Setting VR to {}", vr); let mut canceled_frames = VecDeque::new(); match &mut self.state { - FopState::Initializing { .. } => { + FopState::Initial { .. } => { // forget the previous setvr command // do nothing } - FopState::Initial => { - // do nothing - } FopState::Active(state) => { canceled_frames.append(&mut state.sent_queue); } @@ -270,7 +295,9 @@ impl Fop { .ok(); } - self.state = FopState::Initializing { expected_nr: vr }; + self.state = FopState::Initial { + expected_nr: Some(vr), + }; let frame = Frame { //TODO: manage BC retransmission and frame id for setvr command //id: self.next_frame_id, @@ -283,6 +310,19 @@ impl Fop { Some(frame) } + pub(crate) fn unlock(&mut self) -> Option { + let frame = Frame { + //TODO: manage BC retransmission and frame id for setvr command + //id: self.next_frame_id, + id: 0, + frame_type: tc::sync_and_channel_coding::FrameType::TypeBC, + // TODO: frame number of setvr command??? + sequence_number: 0, + data_field: vec![0x00], + }; + Some(frame) + } + pub(crate) fn send_ad(&mut self, data_field: Vec) -> Option> { let state = match &mut self.state { FopState::Active(state) => state, diff --git a/tmtc-c2a/src/satellite.rs b/tmtc-c2a/src/satellite.rs index c00a580e..8247409e 100644 --- a/tmtc-c2a/src/satellite.rs +++ b/tmtc-c2a/src/satellite.rs @@ -375,6 +375,33 @@ impl gaia_tmtc::broker::FopCommandService //transmitter. } + async fn send_unlock(&mut self) { + let frame = { + let mut fop = self.fop.lock().await; + let frame = fop.unlock(); + match frame { + Some(frame) => frame, + None => { + //TODO: return error? + return; + } + } + }; + + let vcid = 0; + let mut transmitter = self.transmitter.lock().await; + let _ = transmitter + .transmit( + self.tc_scid, + vcid, + frame.frame_type, + frame.sequence_number, + &frame.data_field, + ) + .await; + //transmitter. + } + async fn send_ad_command(&mut self, tco: Tco) -> Result { let Some(fat_schema) = self.registry.lookup(&tco.name) else { return Err(anyhow!("unknown command: {}", tco.name));