xpromache / xtce-rs

4 stars 2 forks source link

Support for multiple space systems #1

Closed jdiez17 closed 2 weeks ago

jdiez17 commented 2 weeks ago

Hi! I'm trying to use xtce-rs to extract arguments from command buffers (and in the future I'd also like to create commands/telemetry containers in Rust from given parameters).

I'm new to XTCE/YAMCS and such but I have found the ACubeSAT yamcs instance which contains XTCE descriptions for many PUS services, which I'd also like to use in my project.

My first naïve attempt was to do something like this:

use std::path::Path;
use xtce_rs::{mdb::MissionDatabase, parser, proc::containers::process};
use env_logger;

fn main() {
    env_logger::init();
    let mut mdb = MissionDatabase::new();
    let paths = [
        "yamcs-instance/src/main/yamcs/mdb/common/dt/base-dt.xml",
        //"yamcs-instance/src/main/yamcs/mdb/common/dt/dt.xml",
        "yamcs-instance/src/main/yamcs/mdb/services/ST[03].xml"
    ];

    for path in paths {
        println!("Parsing {}", path);
        parser::parse(&mut mdb, Path::new(path)).unwrap();
    }
}

I got an UndefinedReference("/base-dt/uint8_t", ParameterType) - meaning that it could not find a reference to the /base-dt/ SpaceSystem. Looking into the parser::parse() function it is obvious why it doesn't work; the NameTree is created reinitalized on every call to parse.

I also tried futzing around with making my own parse function that takes a mutable NameTree but I still wasn't able to parse multiple XTCE files.

So my questions are:

Thanks in advance!

xpromache commented 2 weeks ago

Hello,

The code now builds a NameTree and resolves references there before building the MDB. That parser::parse interface is unfortunate, I think it should just return an mdb instead of taking one as a mutable argument.

The reason for building first the name tree and then making it into an mdb is that in the Yamcs (java) I try to build it all at once from different files and I had struggled a bit resolving references correctly. So I thought it's cleaner to build a tree of names, resolve references and then make the mdb.

Now that NameTree uses references to XML file nodes. If we want to take multiple files, we need to open them all at the same time and modify the NameTree references to reference (file_id, node_id) instead of just node_id. Something like:

pub(crate) struct NameTree {
    pub name_db: NameDb,
    pub systems:
        HashMap<QualifiedName, EnumMap<NameReferenceType, HashMap<NameIdx, (usize, roxmltree::NodeId)>>>,
}

or just make a struct out of (usize, NodeId). The first element is the id of the file in the file list. Maybe you can already get this running if all your files are at the root level (like in the ACubeSAT example you linked). If you want that certain files are starting at sub-levels (this is what Yamcs does) then I guess you need to pass on not a list of files but a tree.

Not sure what your skill level is with Rust, I feel it can be implemented in a few hours; personally I do not have time right now to spend on this. But if you make a pull request I will gladly accept it...

Another thing you can do of course is just to use the Yamcs (java version).