Présentation de l'architecture du BSIM.CCU
-
Présentation des fonctionnalités demandées
-
Solutions proposées
-
Développement futur
Plan
-
Présentation des fonctionnalités demandées
-
Solutions proposées
-
Développement futur
Plan
Présentation des fonctionnalités demandées
- Être stable sur le long terme (> 1 mois)
- Être résilient des erreurs du côté PyramIDS
- Envoyer les messages dans leurs formats corrects
- Avoir les fonctions nécessaires pour la science (?)
Présentation des fonctionnalités demandées
- Être stable sur le long terme (> 1 mois)
- Être résilient des erreurs du côté PyramIDS
- Envoyer les messages dans leurs formats corrects
- Avoir les fonctions nécessaires pour la science (?)
Présentation des fonctionnalités demandées
Être stable sur le long terme (> 1 mois)
⇒ Rust
- Être résilient des erreurs du côté PyramIDS
- Envoyer les messages dans leurs formats corrects
- Avoir les fonctions nécessaires pour la science (?)
Présentation des fonctionnalités demandées
Être stable sur le long terme (> 1 mois)- Être résilient des erreurs du côté PyramIDS
- Envoyer les messages dans leurs formats corrects
- Avoir les fonctions nécessaires pour la science (?)
Présentation des fonctionnalités demandées
Être stable sur le long terme (> 1 mois)- Être résilient des erreurs du côté PyramIDS
⇒ Spécifications des messages en JSON Schema
- Envoyer les messages dans leurs formats corrects
⇒ Spécifications des messages en JSON Schema
- Avoir les fonctions nécessaires pour la science (?)
JSON Schema

JSON Schema


-
Présentation des fonctionnalités demandées
-
Solutions proposées
-
Développement futur
Plan
Solutions proposées
/// This trait centralizes all the interaction with PyramIDS
pub trait Pyramids {
/// Associated type for the initialization
type Initialization;
/// Associated type for the incoming messages
type Incoming;
/// Associated type for the outgoing messages
type Outgoing;
/// Associated Result type from the crate
type Result<T>;
/// Initialization step sending back the `JoinHandle` given by `tokio::spawn`
async fn initialize(&mut self) -> Self::Result<Self::Initialization>;
fn subscriptions<Topic, Message>(
&mut self,
m: IncomingMessages<Topic, Message>
)
where
Topic: Into<String>,
Message: Into<String>;
/// Helper to send all the messages that we can to the broker
async fn send<Topic, Message>(
&self,
message: OutgoingPayload<Topic, Message>,
) -> Self::Result<Self::Outgoing>
where
Topic: Into<String>,
Message: Into<String>;
/// Helper to receive all the messages that we subscribed to
async fn recv(&mut self) -> Self::Result<Self::Incoming>;
}
Trait
Comportement partagé en Rust ⇒ Trait
Exemple - TAS
## Topics
### Pyramids -> TAS
`lisa/{prod_or_simu}/devices/bsim/tas/<cmd>`
used to start scan, stop scan, sync datalogger time.
### TAS -> Pyramids
`lisa/{prod_or_simu}/devices/bsim/tas/housekeeping`
used to send if tas is scanning or not.
`lisa/{prod_or_simu}/devices/bsim/tas/measures`
used to send temperatures measurements.
## Payloads
### cmd
Action has to be one of the following :
Start // Start scan
Stop // Stop scan
Sync // Sync datalogger clock with clock from PC
pub struct Tas {
pyramids_client: Pyramids_Client,
instrument_client: Instrument_Client,
settings: TasSettings,
subscriptions: Vec<Payload>,
// ... Internal fields
}
impl Pyramids for Tas {
type Initialization = ();
type Incoming = Event;
type Outgoing = ();
type Result<T> = Result<T>;
async fn initialize(&mut self) -> Result<()> {
self.init().await?;
Ok(())
}
async fn send<S: Into<String>, M: Into<String>>(
&self,
message: OutgoingPayload<S, M>,
) -> Result<()> {
self.pyramids_client
.publish(
message.topic.into(),
QoS::ExactlyOnce,
false,
message.message.into().clone(),
)
.await?;
Ok(())
}
async fn recv(&mut self) -> Result<Event> {
Ok(self.pyramids_client.poll().await?)
}
}
Exemple - TAS
And in the binary definition
// main
let settings = Settings::new()
.map_err(|e| e.to_string())
.expect("Can not read settings");
let tas_settings = settings
.tas
.into_iter()
.next()
.expect("Did not find the dataloggers settings");
let addr = tas_settings.address.clone();
let instrument_client = tas::Client::connect(addr)
.await
.expect("cant connect to datalogger");
let pyramids_client = mqtt_Client::connect(["localhost:1883", "localhost:1883"])
.await
.expect("Could not reach the MQTT broker");
let mut tas = Pyramids_Client::from_settings(instrument_client, pyramids_client, tas_settings);
tas.initialize().await?;
// Continue right// Continued
loop {
let message = tas.recv().await?;
// XXX: Match in trait ?
match message {
// We receive communication on the client
Event::Incoming(packet) => {
// Someone published (most likely on a topic we subscribe to)
if let Packet::Publish(p) = packet {
// We grab the topic and the payload
let Publish { topic, payload, .. } = p;
match topic.as_str() {
"lisa/prod/devices/bsim/tas/start" => tas.start(),
"lisa/prod/devices/bsim/tas/stop" => tas.stop(),
"lisa/prod/devices/bsim/tas/sync" => tas.sync(),
_ => {
// XXX: Unknown topic, what do we do ?
todo!();
}
}
} else {
match packet {
Packet::Subscribe(subscribe) => todo!(),
Packet::Unsubscribe(unsubscribe) => todo!(),
Packet::PingReq => todo!(),
Packet::PingResp => todo!(),
Packet::Disconnect => todo!(),
_ => continue,
}
}
}
// XXX: Log outgoing requests?
_ => continue,
}
}
}
Exemple - TAS
And in the binary definition
// main
/* Initialization */
let settings = Settings::new()
.map_err(|e| e.to_string())
.expect("Can not read settings");
let tas_settings = settings
.tas
.into_iter()
.next()
.expect("Did not find the dataloggers settings");
let addr = tas_settings.address.clone();
let instrument_client = tas::Client::connect(addr)
.await
.expect("cant connect to datalogger");
let pyramids_client = mqtt_Client::connect(["localhost:1883", "localhost:1883"])
.await
.expect("Could not reach the MQTT broker");
let mut tas = Pyramids_Client::from_settings(instrument_client, pyramids_client, tas_settings);
tas.initialize().await?;
/* Main control loop */
// Continue right ↗// Continued
loop {
let message = tas.recv().await?;
// XXX: Match in trait ?
match message {
// We receive communication on the client
Event::Incoming(packet) => {
// Someone published (most likely on a topic we subscribe to)
if let Packet::Publish(p) = packet {
// We grab the topic and the payload
let Publish { topic, payload, .. } = p;
match topic.as_str() {
"lisa/prod/devices/bsim/tas/start" => tas.start(),
"lisa/prod/devices/bsim/tas/stop" => tas.stop(),
"lisa/prod/devices/bsim/tas/sync" => tas.sync(),
_ => {
// XXX: Unknown topic, what do we do ?
todo!();
}
}
} else {
match packet {
Packet::Subscribe(subscribe) => todo!(),
Packet::Unsubscribe(unsubscribe) => todo!(),
Packet::PingReq => todo!(),
Packet::PingResp => todo!(),
Packet::Disconnect => todo!(),
_ => continue,
}
}
}
// XXX: Log outgoing requests?
_ => continue,
}
}
}
-
Présentation des fonctionnalités demandées
-
Solutions proposées
-
Développement futur
Plan
Les casseroles
- IHM
- Mock Pyramids
- Amélioration de l’encapsulation
- Création d'une variable d'état (automate fini ?)
// Continued
loop {
let message = tas.recv().await?;
// XXX: Match in trait ?
match message {
// We receive communication on the client
Event::Incoming(packet) => {
// Same ol' same
} else {
// XXX: Useful ?
match packet {
Packet::Subscribe(subscribe) => todo!(),
Packet::Unsubscribe(unsubscribe) => todo!(),
Packet::PingReq => todo!(),
Packet::PingResp => todo!(),
Packet::Disconnect => todo!(),
_ => continue,
}
}
}
// XXX: Log outgoing requests?
_ => continue,
}
}
}
Présentation de l'avancement de l'architecture du BSIM.CCU
By Claude-Alban RANÉLY-VERGÉ-DÉPRÉ
Présentation de l'avancement de l'architecture du BSIM.CCU
- 13