Skip to content

Cube-OS/cubeos-service

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cubeos-service

This is an overhaul of the kubos-service. The main goal for this crate was to lighten the processing load for the OBC, which is achieved by substituting the original GraphQL commands with a simpler command handler via UDP.

The performance improvement comes with the sacrifice of the debugging qualities of GraphQL. For this purpose the service has been redeveloped around the service_macro! to replace the GraphQL server on the satellite with a lightweight UDP Handler. Instead the GraphQL server is now run on the Ground Station. This ground mode can be compiled from the same source by using the --features ground flag.

The ground service translates GraphQL inputs to UDP commands and forwards them to the satellite. The satellite's reply is then translated into JSON. This enables the user to have the usual human readable handling of GraphQL and the performance advantage of the UDP handling.

Additionally the debug feature enables some terminal printouts.

service_macro!

The service_macro! has the following structure:

service_macro!{
  use $api_krate::$error;
  $krate::$strukt {
    query: $cmdid0 => fn function0(&self, $Inputs) -> Result<$Reply>; out: $GroundReply;
    mutation: $cmdid1 => fn function1(&self, $Inputs) -> Result<()>;
  }
}

$api_krate::$error is the corresponding API crate and error defined within. If no error has been defined please use cubeos_error::Error instead.

$krate::$strukt is the crate name and name of the struct (e.g. subsystem::Subsystem) containing the functions to be exposed by the Service.

$Input(s) are the arguments for function\_() (leave blank if function\_() has no arguments). The whole part fn function_(&self, args) -> Result<$Reply> can be copied from the implementation of the function in the subsytem.rs.

query denotes commands that expect a return, such as telemetry, while mutations are commands that only expect an acknowledge/success as a return.

Here the cmdid is an Enum variant of the enum Command, which is generated by the macro to enable command handling.

After the => comes the function of the Subsystem associated with the CommandID.

The Result can be any Result Type, but the Error needs to be convertible to CubeOSError::Error::ServiceError(u8). CubeOSError.

The $Reply requires the #[derive(Serialize,Deserialize)] from the serde_json crate.

The $GroundReply gives the user the opportunity to make the output data more humanly readable on the ground. To use this it is necessary to implement the From Trait to convert $Reply into $GroundReply:

pub struct $GroundReply {
...
}
impl From<$Reply> for $GroundReply {
  fn from(g: $Reply) -> $GroundReply {
    ...
  }
}

Service

To accomodate the different use cases, the Service has been altered slightly as well. The following examples show how to start your service in main.rs:

In the default UDP case, the GraphQL Query and Mutationroot are replaced by the udp_handler function:

#[cfg(not(feature = "terminal"))]
//Start up UDP server
Service::new(
    service_config,
    subsystem,
    Some(Arc::new(udp_handler)),
)
.start();

The ground case, doesn't need the Subsystem, but adds a socket IP address, which can be any free Port on the Debug/GroundStation computer, and the target service's IP address on the satellite. It is handy to read them in from a config.toml file, but not necessary.

#[cfg(feature = "termial")]
// Start ground service
Service::new(
    service_config,
    socket.as_str().unwrap().to_string(),
    target.as_str().unwrap().to_string(),
    std::env::args().collect::<Vec<String>>(),
    Arc::new(input),
    Arc::new(output),
).start();

Compile your service (requires rust 1.67.0 or above)

As shown above, cubeos-service uses features so the user can decide the use case at compile time.

UDP handling

cargo build

or with cross compiler (requires KubOS SDK)

cargo kubos -c build --target kubos-linux-isis-gcc -- --release (for ISISpace iOBC)

cargo kubos -c build --target kubos-linux-beaglebone-gcc -- --release (for Beaglebone Black)

Terminal:

cargo build --features terminal

Additionally the UDP handling and Ground features can be combined with debug, e.g.: cargo build --features debug

cargo build --features terminal,debug

Run a service

To run a service simply transfer the executable to the satellite or ground station to a desired folder (e.g. /home/kubos/) and run:

./executable

This requires a config file, in Kubos/Cube-OS this is commonly stored under /etc/kubos-config.toml. Alternatively run the executable with the -c flag to specify a config file:

./executable -c /path/to/config

Run the Terminal Service

Run the terminal service on a computer connected to your OBC via SLIP or Ethernet or a radio link (which simulates an IP network). The terminal service can be called in 3 modes.

  1. Manual Cmd ./terminal_executable -c /path/to/config

  2. Planning commands for a later contact (see TODO! for execution of planned commands) ./terminal_executable -c /path/to/config -p

  3. Execution of single cmd (this is used to run planned commands by the TODO!) ./terminal_executable -c /path/to/config Cmd Arguments where Arguments are the inputs for a Cmd and optional

App

This crate now also features an app_macro!() and App type similar to the Service type.

The following example shows a way how to set-up a Cube-OS App:

use cubeos-service::*;

app_macro!{
  example_service: Example {
    query: GetValue => fn get_value(&self, get: ExampleEnum) -> Result<ExampleResult>; out: ExampleResult;
    mutation: SetValue => fn set_value(&self, set: ExampleInput) -> Result<()>;
  }
}

fn app_logic() -> Result<()> {
  let result = Example::get_value(ExampleEnum::All)?;

  println!("{}",result);

  let set = ExampleInput::default();

  Example::set_value(set)?;

  let result = Example::get_value(ExampleEnum::All)?;

  println!("{}",result);
}

fn main() -> Result<()> {
  // Logger
  Logger::init();

  // Set pin-logic on BBB to turn on payload (if needed)
  let pins: u8 = 2;

  Ok(App::new(app_logic,pins,"example-service").run()?)
  
}

Troubleshooting

CubeOS uses git ssh URL's for dependencies within the Organisation. Pls make sure to add your to the repository:

start ssh-agent eval `ssh-agent`

add key (in repo) ssh-add ~/.ssh/$your-key

Add the targets to your $HOME/.cargo/config file:

[target.armv5te-unknown-linux-gnueabi]
linker = "/usr/bin/iobc_toolchain/usr/bin/arm-linux-gcc"

[target.arm-unknown-linux-gnueabihf]
linker = "/usr/bin/bbb_toolchain/usr/bin/arm-linux-gcc"