use embassy_sync::{
blocking_mutex::raw::CriticalSectionRawMutex,
watch::{Receiver, Sender, Watch},
};
#[cfg(feature = "autopilot")]
use radio_controllers::RcMode;
use radio_controllers::{Rates, RatesConfig, RcModes, RxChannel, RxFrame};
use crate::{
config::{ConfigItem, ConfigPublisher, ConfigSubscriber, FastConfigPublisher},
flight::{RcAdjustments, RxMessage},
};
const RX_WATCH_COUNT: usize = 2;
static RX_WATCH: Watch<CriticalSectionRawMutex, RxMessage, RX_WATCH_COUNT> = Watch::new();
type RxSender = Sender<'static, CriticalSectionRawMutex, RxMessage, RX_WATCH_COUNT>;
pub fn rx_sender() -> RxSender {
RX_WATCH.sender()
}
pub type RxReceiver = Receiver<'static, CriticalSectionRawMutex, RxMessage, RX_WATCH_COUNT>;
#[allow(clippy::expect_used)]
pub fn rx_receiver() -> RxReceiver {
RX_WATCH.receiver().expect("rx_receiver failed")
}
#[cfg(feature = "autopilot")]
use crate::tasks::autopilot_task::AutopilotReceiver;
pub struct RxContext {
pub rx_sender: RxSender,
pub config_subscriber: ConfigSubscriber,
pub config_publisher: ConfigPublisher,
pub fast_config_publisher: FastConfigPublisher,
pub rc_modes: RcModes,
pub rates: Rates,
pub rc_adjustments: RcAdjustments,
#[cfg(feature = "autopilot")]
pub autopilot_receiver: AutopilotReceiver,
}
impl RxContext {
#[rustfmt::skip]
pub fn new(
rx_sender: RxSender,
config_subscriber: ConfigSubscriber,
config_publisher: ConfigPublisher,
fast_config_publisher: FastConfigPublisher,
rates_config: RatesConfig,
#[cfg(feature = "autopilot")] autopilot_receiver: AutopilotReceiver,
) -> Self {
Self {
rx_sender,
config_subscriber,
config_publisher,
fast_config_publisher,
rates: Rates::new(rates_config),
rc_modes: RcModes::with_mac_arm(),
rc_adjustments: RcAdjustments::new(),
#[cfg(feature = "autopilot")] autopilot_receiver,
}
}
}
#[embassy_executor::task]
pub async fn rx_task(ctx: &'static mut RxContext) {
let mut loop_count: u32 = 0;
let mut ticker = embassy_time::Ticker::every(embassy_time::Duration::from_millis(20));
log::info!(" RX: task started");
loop {
ticker.next().await;
let mut rx_frame = RxFrame::new();
if loop_count == 1000 {
rx_frame.channels[RxChannel::AUX1] = RxChannel::MID_HIGH; } else if loop_count == 2000 {
rx_frame.channels[RxChannel::AUX1] = RxChannel::LOW; }
let failsafe = 0;
if let Some(wait_result) = ctx.config_subscriber.try_next_message()
&& let embassy_sync::pubsub::WaitResult::Message(ConfigItem::Rates(rates_config)) = wait_result
{
ctx.rates.set(rates_config);
}
ctx.rc_modes.update_activated_modes(&rx_frame);
ctx.rc_adjustments.process_adjustments(&ctx.config_publisher, &ctx.fast_config_publisher).await;
#[allow(unused_mut)]
let mut rx_message = RxMessage::new_from(&rx_frame, &ctx.rates, &ctx.rc_modes, loop_count, failsafe);
#[cfg(feature = "autopilot")]
if let Some(autopilot_message) = ctx.autopilot_receiver.try_changed() {
if ctx.rc_modes.is_mode_active(RcMode::ALTITUDE_HOLD) {
rx_message.controls.throttle_stick = autopilot_message.controls.throttle_stick;
} else if ctx.rc_modes.is_mode_active(RcMode::POSITION_HOLD)
|| ctx.rc_modes.is_mode_active(RcMode::GPS_RESCUE)
|| ctx.rc_modes.is_mode_active(RcMode::AUTOPILOT)
{
rx_message.controls = autopilot_message.controls;
}
}
ctx.rx_sender.send(rx_message);
if loop_count.is_multiple_of(5) {
log::info!(" RX: loop {loop_count}");
}
loop_count = loop_count.wrapping_add(1); }
}