use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::time::Duration;
use heapless::String as HString;
use heapless::Vec as HVec;
use crate::protocol::dds::discovery::endpoint_data::SubscriptionBuiltinTopicData;
use crate::protocol::dds::discovery::qos_profile::QosProfile;
use crate::protocol::dds::stateful::{ReaderConfig, StatefulReader};
use crate::protocol::dds::transport::{TransportConfig, UdpTransport};
use crate::protocol::dds::types::guid::{EntityId, Guid, GuidPrefix};
use crate::protocol::dds::types::locator::Locator;
use super::dds_type::{DdsType, Sample};
use super::error::DdsApiError;
use super::publisher::addr_to_locator;
pub const SUBSCRIPTION_QUEUE_DEPTH: usize = 16;
pub(super) struct ReaderEntry {
pub(super) reader: StatefulReader,
pub(super) sub_data: SubscriptionBuiltinTopicData,
pub(super) announced: bool,
pub(super) raw_queue: HVec<(Vec<u8>, [u8; 16]), SUBSCRIPTION_QUEUE_DEPTH>,
}
impl ReaderEntry {
pub(super) fn new(
guid_prefix: GuidPrefix,
entity_id: EntityId,
topic_name: &str,
type_name: &str,
qos: &QosProfile,
) -> Result<Self, DdsApiError> {
let bind = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0));
let cfg = TransportConfig {
read_timeout: Some(Duration::from_millis(1)),
..TransportConfig::unicast(bind)
};
let transport = UdpTransport::new(cfg)?;
let local_addr = transport.local_addr()?;
let guid = Guid::new(guid_prefix, entity_id);
let reader_cfg = ReaderConfig::new(guid);
let reader = StatefulReader::new(reader_cfg, transport);
let unicast_locator = addr_to_locator(local_addr)?;
let mut unicast_locators = heapless::Vec::new();
unicast_locators
.push(unicast_locator)
.map_err(|_| DdsApiError::Serialization("locator list full"))?;
let mut topic = HString::<256>::new();
topic
.push_str(topic_name)
.map_err(|_| DdsApiError::TopicNameTooLong)?;
let mut ttype = HString::<256>::new();
ttype
.push_str(type_name)
.map_err(|_| DdsApiError::TypeNameTooLong)?;
let sub_data = SubscriptionBuiltinTopicData {
endpoint_guid: guid,
topic_name: topic,
type_name: ttype,
unicast_locators,
multicast_locators: heapless::Vec::new(),
reliability: qos.reliability,
history: qos.history,
durability: qos.durability,
liveliness: qos.liveliness,
deadline: qos.deadline,
};
Ok(Self {
reader,
sub_data,
announced: false,
raw_queue: HVec::new(),
})
}
}
pub struct Subscription<T: DdsType> {
pub(super) entry_idx: usize,
_marker: core::marker::PhantomData<T>,
}
impl<T: DdsType> Subscription<T> {
pub(super) fn new(entry_idx: usize) -> Self {
Self {
entry_idx,
_marker: core::marker::PhantomData,
}
}
pub(super) fn take(&self, entry: &mut ReaderEntry) -> Vec<Sample<T>> {
let raw: Vec<_> = entry.raw_queue.iter().cloned().collect();
entry.raw_queue.clear();
let mut out = Vec::with_capacity(raw.len());
for (payload, guid_bytes) in raw {
if let Ok(data) = T::deserialize(&payload) {
out.push(Sample {
data,
writer_guid_bytes: guid_bytes,
});
}
}
out
}
}
pub(super) fn guid_to_bytes(g: &Guid) -> [u8; 16] {
let mut out = [0u8; 16];
out[..12].copy_from_slice(&g.prefix.0);
out[12] = g.entity_id.entity_key[0];
out[13] = g.entity_id.entity_key[1];
out[14] = g.entity_id.entity_key[2];
out[15] = g.entity_id.entity_kind;
out
}
pub(super) fn sub_data_locator(sub_data: &SubscriptionBuiltinTopicData) -> Option<Locator> {
sub_data.unicast_locators.first().copied()
}
pub(super) fn pub_data_locators(
pub_data: &crate::protocol::dds::discovery::endpoint_data::PublicationBuiltinTopicData,
) -> Vec<Locator> {
pub_data.unicast_locators.iter().copied().collect()
}