mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
examples: Add second Rust example (gcoap)
This commit is contained in:
parent
49403c7781
commit
6246ab70d1
BIN
examples/rust-gcoap/Cargo.lock
generated
Normal file
BIN
examples/rust-gcoap/Cargo.lock
generated
Normal file
Binary file not shown.
16
examples/rust-gcoap/Cargo.toml
Normal file
16
examples/rust-gcoap/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "rust-gcoap"
|
||||
version = "0.1.0"
|
||||
authors = ["Christian Amsüss <chrysn@fsfe.org>"]
|
||||
edition = "2018"
|
||||
resolver = "2"
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
riot-wrappers = { version = "^0.7", features = [ "with_coap_message", "with_coap_handler" ] }
|
||||
|
||||
coap-message-demos = { git = "https://gitlab.com/chrysn/coap-message-demos/", default-features = false }
|
||||
coap-handler-implementations = "0.1"
|
||||
riot-coap-handler-demos = { git = "https://gitlab.com/etonomy/riot-module-examples/", features = [ "vfs" ] }
|
39
examples/rust-gcoap/Makefile
Normal file
39
examples/rust-gcoap/Makefile
Normal file
@ -0,0 +1,39 @@
|
||||
# name of your application
|
||||
APPLICATION = rust_gcoap
|
||||
|
||||
# If no BOARD is found in the environment, use this default:
|
||||
BOARD ?= native
|
||||
|
||||
# This has to be the absolute path to the RIOT base directory:
|
||||
RIOTBASE ?= $(CURDIR)/../..
|
||||
|
||||
# Basic networking, and gcoap
|
||||
USEMODULE += gcoap
|
||||
USEMODULE += netdev_default
|
||||
USEMODULE += auto_init_gnrc_netif
|
||||
USEMODULE += gnrc_ipv6_default
|
||||
USEMODULE += gnrc_icmpv6_echo
|
||||
|
||||
USEMODULE += ztimer
|
||||
USEMODULE += ztimer_usec
|
||||
USEMODULE += ztimer_msec
|
||||
USEMODULE += ztimer_sec
|
||||
|
||||
USEMODULE += vfs
|
||||
USEMODULE += constfs
|
||||
|
||||
# Comment this out to disable code in RIOT that does safety checking
|
||||
# which is not needed in a production environment but helps in the
|
||||
# development process:
|
||||
DEVELHELP ?= 1
|
||||
|
||||
# Change this to 0 show compiler invocation lines by default:
|
||||
QUIET ?= 1
|
||||
|
||||
# The name of crate (as per Cargo.toml package name, but with '-' replaced with '_')
|
||||
APPLICATION_RUST_MODULE = rust_gcoap
|
||||
BASELIBS += $(APPLICATION_RUST_MODULE).module
|
||||
|
||||
FEATURES_REQUIRED += rust_target
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
8
examples/rust-gcoap/Makefile.ci
Normal file
8
examples/rust-gcoap/Makefile.ci
Normal file
@ -0,0 +1,8 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
blackpill \
|
||||
bluepill \
|
||||
nucleo-f302r8 \
|
||||
nucleo-f303k8 \
|
||||
nucleo-f334r8 \
|
||||
stm32mp157c-dk2 \
|
||||
#
|
53
examples/rust-gcoap/README.md
Normal file
53
examples/rust-gcoap/README.md
Normal file
@ -0,0 +1,53 @@
|
||||
gcoap used with Rust
|
||||
====================
|
||||
|
||||
This is the advanced Rust example; see ../rust-hello-world/ for the basics.
|
||||
|
||||
In extension to the basic example, it shows:
|
||||
|
||||
* C code can be mixed with Rust code easily; any C file is built and linked
|
||||
as in applications without Rust.
|
||||
|
||||
While it's technically possible to have header files for that code,
|
||||
it is easier (and likewise often done in C applications)
|
||||
to just translate the entry function's signature manually,
|
||||
as is done with the `do_vfs_init()` function.
|
||||
|
||||
* Code of Rust applications can be spread out into modules,
|
||||
even if it builds on RIOT components.
|
||||
|
||||
The CoAP handler built in the main function
|
||||
combines generic CoAP components (from `coap_message_demos`)
|
||||
with RIOT specific components (from `riot-coap-handler-demos`).
|
||||
|
||||
* Many features of RIOT are exposed to Rust through the riot-wrappers crate,
|
||||
which provides safe wrappers around RIOT structures.
|
||||
|
||||
In this example, the abovementioned CoAP handler is run on the gcoap server,
|
||||
for which the wrappers provide adaptation to the platform independent handler interface.
|
||||
|
||||
Then, ztimer is used to sleep until the network interfaces are expected to be ready.
|
||||
|
||||
Finally, the available network interfaces are iterated over
|
||||
and queried for their IP addresses,
|
||||
which makes it easier (in absence of an interactive shell) to find which address CoAP requests can be directed at.
|
||||
|
||||
How to use
|
||||
----------
|
||||
|
||||
```
|
||||
$ make all flash term
|
||||
[...]
|
||||
main(): This is RIOT! (Version: 2022.01-devel-560-g7f8ed-rust-application)
|
||||
constfs mounted successfully
|
||||
CoAP server ready; waiting for interfaces to settle before reporting addresses...
|
||||
Active interface from PID KernelPID(6) ("gnrc_netdev_tap")
|
||||
Address fe80:0000:0000:0000:1234:56ff:fe78:90ab
|
||||
Address 2a02:0b18:c13b:8018:1234:56ff:fe78:90ab
|
||||
```
|
||||
|
||||
Once that is ready, in a parallel shell, run:
|
||||
|
||||
```
|
||||
$ aiocoap-client 'coap://[2a02:0b18:c13b:8018:1234:56ff:fe78:90ab]/.well-known/core'
|
||||
```
|
57
examples/rust-gcoap/src/lib.rs
Normal file
57
examples/rust-gcoap/src/lib.rs
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright (C) 2020 Christian Amsüss
|
||||
//
|
||||
// This file is subject to the terms and conditions of the GNU Lesser
|
||||
// General Public License v2.1. See the file LICENSE in the top level
|
||||
// directory for more details.
|
||||
#![no_std]
|
||||
|
||||
use riot_wrappers::{riot_main, println};
|
||||
use riot_wrappers::{gcoap, thread, ztimer, gnrc};
|
||||
|
||||
use coap_handler_implementations::{ReportingHandlerBuilder, HandlerBuilder};
|
||||
|
||||
riot_main!(main);
|
||||
|
||||
fn main() {
|
||||
extern "C" {
|
||||
fn do_vfs_init();
|
||||
}
|
||||
|
||||
unsafe { do_vfs_init() };
|
||||
|
||||
let handler = coap_message_demos::full_application_tree(None)
|
||||
.below(&["ps"], riot_coap_handler_demos::ps::ps_tree())
|
||||
.below(&["vfs"], riot_coap_handler_demos::vfs::vfs("/const"))
|
||||
.with_wkc()
|
||||
;
|
||||
let mut handler = riot_wrappers::coap_handler::GcoapHandler(handler);
|
||||
|
||||
let mut listener = gcoap::SingleHandlerListener::new_catch_all(&mut handler);
|
||||
|
||||
gcoap::scope(|greg| {
|
||||
greg.register(&mut listener);
|
||||
|
||||
println!("CoAP server ready; waiting for interfaces to settle before reporting addresses...");
|
||||
|
||||
let sectimer = ztimer::ZTimer::sec();
|
||||
sectimer.sleep_ticks(2);
|
||||
|
||||
for netif in gnrc::Netif::all() {
|
||||
println!("Active interface from PID {:?} ({:?})", netif.pid(), netif.pid().get_name().unwrap_or("unnamed"));
|
||||
match netif.ipv6_addrs() {
|
||||
Ok(addrs) => {
|
||||
for a in addrs.addresses() {
|
||||
println!(" Address {:?}", a);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!(" Does not support IPv6.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sending main thread to sleep; can't return or the Gcoap handler would need to be
|
||||
// deregistered (which it can't).
|
||||
loop { thread::sleep(); }
|
||||
})
|
||||
}
|
72
examples/rust-gcoap/vfs.c
Normal file
72
examples/rust-gcoap/vfs.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2018 OTA keys S.A.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file demonstrates how C code can be mixed with Rust code in an
|
||||
* application in an ad-hoc fashion.
|
||||
*/
|
||||
|
||||
#include <vfs.h>
|
||||
#include "fs/constfs.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define HELLO_WORLD_CONTENT "Hello World!\n"
|
||||
#define HELLO_RIOT_CONTENT "Hello RIOT!\n"
|
||||
|
||||
#define LARGE "1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n" \
|
||||
"1234567890---------\n"
|
||||
|
||||
static constfs_file_t constfs_files[] = {
|
||||
{
|
||||
.path = "/hello-world",
|
||||
.size = sizeof(HELLO_WORLD_CONTENT),
|
||||
.data = (const uint8_t *)HELLO_WORLD_CONTENT,
|
||||
},
|
||||
{
|
||||
.path = "/hello-riot",
|
||||
.size = sizeof(HELLO_RIOT_CONTENT),
|
||||
.data = (const uint8_t *)HELLO_RIOT_CONTENT,
|
||||
},
|
||||
{
|
||||
.path = "/large",
|
||||
.size = sizeof(LARGE),
|
||||
.data = (const uint8_t *)LARGE,
|
||||
}
|
||||
};
|
||||
|
||||
static constfs_t constfs_desc = {
|
||||
.nfiles = ARRAY_SIZE(constfs_files),
|
||||
.files = constfs_files,
|
||||
};
|
||||
|
||||
static vfs_mount_t const_mount = {
|
||||
.fs = &constfs_file_system,
|
||||
.mount_point = "/const",
|
||||
.private_data = &constfs_desc,
|
||||
};
|
||||
|
||||
void do_vfs_init(void) {
|
||||
int res = vfs_mount(&const_mount);
|
||||
if (res < 0) {
|
||||
puts("Error while mounting constfs");
|
||||
}
|
||||
else {
|
||||
puts("constfs mounted successfully");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user