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.
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 {
...
}
}
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();
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
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 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.
-
Manual Cmd
./terminal_executable -c /path/to/config
-
Planning commands for a later contact (see TODO! for execution of planned commands)
./terminal_executable -c /path/to/config -p
-
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
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()?)
}
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"