Initial version of libcsp-rust
This commit is contained in:
1
examples/.gitignore
vendored
Normal file
1
examples/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
10
examples/Cargo.toml
Normal file
10
examples/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "libcsp-rust-examples"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libcsp = { path = "../libcsp" }
|
||||
|
||||
[build-dependencies]
|
||||
libcsp-cargo-build = { path = "../libcsp-cargo-build" }
|
25
examples/autoconfig.h
Normal file
25
examples/autoconfig.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// This file was auto-generated by libcsp-cargo-build v0.1.0
|
||||
#define CSP_POSIX 1
|
||||
#define CSP_ZEPHYR 0
|
||||
|
||||
#define CSP_HAVE_STDIO 1
|
||||
#define CSP_ENABLE_CSP_PRINT 1
|
||||
#define CSP_PRINT_STDIO 1
|
||||
#define CSP_REPRODUCIBLE_BUILDS 0
|
||||
|
||||
#define CSP_QFIFO_LEN 16
|
||||
#define CSP_PORT_MAX_BIND 16
|
||||
#define CSP_CONN_RXQUEUE_LEN 16
|
||||
#define CSP_CONN_MAX 8
|
||||
#define CSP_BUFFER_SIZE 256
|
||||
#define CSP_BUFFER_COUNT 15
|
||||
#define CSP_RDP_MAX_WINDOW 5
|
||||
#define CSP_RTABLE_SIZE 10
|
||||
|
||||
#define CSP_USE_RDP 1
|
||||
#define CSP_USE_HMAC 1
|
||||
#define CSP_USE_PROMISC 1
|
||||
#define CSP_USE_RTABLE 0
|
||||
|
||||
#define CSP_HAVE_LIBSOCKETCAN 0
|
||||
#define CSP_HAVE_LIBZMQ 0
|
8
examples/autoconfig.rs
Normal file
8
examples/autoconfig.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
// This file was auto-generated by libcsp-cargo-build v0.1.0
|
||||
pub const CSP_CONN_RXQUEUE_LEN: usize = 16;
|
||||
pub const CSP_QFIFO_LEN: usize = 16;
|
||||
pub const CSP_PORT_MAX_BIND: usize = 16;
|
||||
pub const CSP_CONN_MAX: usize = 8;
|
||||
pub const CSP_BUFFER_SIZE: usize = 256;
|
||||
pub const CSP_RDP_MAX_WINDOW: usize = 5;
|
||||
pub const CSP_RTABLE_SIZE: usize = 10;
|
38
examples/build.rs
Normal file
38
examples/build.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use std::{env, path::PathBuf};
|
||||
|
||||
use libcsp_cargo_build::{generate_autoconf_header_file, Builder};
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var("OUT_DIR").unwrap_or_default();
|
||||
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap_or_default();
|
||||
let manifest_path = PathBuf::from(&manifest_dir);
|
||||
let lib_cfg_dir = "../clib/cfg/csp";
|
||||
let libcsp_path = "../clib/libcsp";
|
||||
|
||||
// This helper structure will take care of the majority of work to compile libcsp using the
|
||||
// cc crate.
|
||||
let mut csp_builder = Builder::new(PathBuf::from(libcsp_path), PathBuf::from(&out_dir));
|
||||
// A lot of spam we are not interested in usually.
|
||||
csp_builder.compiler_warnings = false;
|
||||
|
||||
// We always re-generate the header file.
|
||||
generate_autoconf_header_file(manifest_path.clone(), &csp_builder.cfg)
|
||||
.expect("generating header file failed");
|
||||
|
||||
// Copy the file to lib/csp/cfg as well for binding generation.
|
||||
std::fs::copy(
|
||||
manifest_path.join("autoconfig.h"),
|
||||
PathBuf::from(&lib_cfg_dir).join("autoconfig.h"),
|
||||
)
|
||||
.expect("copying autoconfig.h failed");
|
||||
|
||||
// This file is required for the compile-time configuration of libcsp-rust.
|
||||
csp_builder
|
||||
.generate_autoconf_rust_file(manifest_path)
|
||||
.expect("generating autoconfig.rs failed");
|
||||
|
||||
csp_builder.compile().expect("compiling libcsp failed");
|
||||
|
||||
// If we change the libcsp build configuration, we need to re-run the build.
|
||||
println!("cargo::rerun-if-changed=build.rs");
|
||||
}
|
205
examples/src/main.rs
Normal file
205
examples/src/main.rs
Normal file
@@ -0,0 +1,205 @@
|
||||
use std::{
|
||||
ffi::CStr,
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicU32},
|
||||
Arc,
|
||||
},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use libcsp::{
|
||||
csp_accept_guarded, csp_bind, csp_buffer_get, csp_conn_dport, csp_conn_print_table,
|
||||
csp_connect_guarded, csp_init, csp_listen, csp_ping, csp_read_guarded, csp_reboot,
|
||||
csp_route_work, csp_send, csp_service_handler, iflist::csp_iflist_print, ConnectOpts, CspError,
|
||||
CspSocket, MsgPriority, SocketFlags, CSP_ANY, CSP_LOOPBACK,
|
||||
};
|
||||
|
||||
const MY_SERVER_PORT: i32 = 10;
|
||||
const TEST_MODE: bool = false;
|
||||
const RUN_DURATION_IN_SECS: u32 = 3;
|
||||
|
||||
fn main() -> Result<(), u32> {
|
||||
println!("CSP client/server example");
|
||||
|
||||
// SAFETY: We only call this once.
|
||||
unsafe { csp_init() };
|
||||
|
||||
let stop_signal = Arc::new(AtomicBool::new(false));
|
||||
let stop_signal_server = stop_signal.clone();
|
||||
let stop_signal_client = stop_signal.clone();
|
||||
let stop_signal_router = stop_signal.clone();
|
||||
let server_received = Arc::new(AtomicU32::new(0));
|
||||
let server_recv_copy = server_received.clone();
|
||||
|
||||
let csp_router_jh = thread::spawn(move || loop {
|
||||
if stop_signal_router.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
if let Err(e) = csp_route_work() {
|
||||
match e {
|
||||
CspError::TimedOut => continue,
|
||||
e => {
|
||||
println!("CSP router error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let csp_server_jh = thread::spawn(move || {
|
||||
server(server_received, stop_signal_server);
|
||||
});
|
||||
|
||||
let csp_client_jh = thread::spawn(move || {
|
||||
client(stop_signal_client);
|
||||
});
|
||||
|
||||
println!("CSP connection table");
|
||||
csp_conn_print_table();
|
||||
|
||||
println!("CSP interfaces");
|
||||
csp_iflist_print();
|
||||
let mut app_result = Ok(());
|
||||
// Wait for execution to end (ctrl+c)
|
||||
loop {
|
||||
std::thread::sleep(Duration::from_secs(RUN_DURATION_IN_SECS as u64));
|
||||
|
||||
if TEST_MODE {
|
||||
// Test mode is intended for checking that host & client can exchange packets over loopback
|
||||
let received_count = server_recv_copy.load(std::sync::atomic::Ordering::Relaxed);
|
||||
println!("CSP: Server received {} packets", received_count);
|
||||
if received_count < 5 {
|
||||
app_result = Err(1);
|
||||
}
|
||||
stop_signal.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
csp_router_jh.join().unwrap();
|
||||
csp_server_jh.join().unwrap();
|
||||
csp_client_jh.join().unwrap();
|
||||
app_result
|
||||
}
|
||||
|
||||
fn server(server_received: Arc<AtomicU32>, stop_signal: Arc<AtomicBool>) {
|
||||
println!("server task started");
|
||||
|
||||
// Create socket with no specific socket options, e.g. accepts CRC32, HMAC, etc. if enabled
|
||||
// during compilation
|
||||
let mut csp_socket = CspSocket::default();
|
||||
|
||||
// Bind socket to all ports, e.g. all incoming connections will be handled here
|
||||
csp_bind(&mut csp_socket, CSP_ANY);
|
||||
|
||||
// Create a backlog of 10 connections, i.e. up to 10 new connections can be queued
|
||||
csp_listen(&mut csp_socket, 10);
|
||||
|
||||
// Wait for connections and then process packets on the connection
|
||||
loop {
|
||||
if stop_signal.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait for a new connection, 10000 mS timeout
|
||||
let conn = csp_accept_guarded(&mut csp_socket, Duration::from_millis(10000));
|
||||
if conn.is_none() {
|
||||
continue;
|
||||
}
|
||||
let mut conn = conn.unwrap();
|
||||
|
||||
// Read packets on connection, timout is 100 mS
|
||||
loop {
|
||||
if stop_signal.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Guarded packet is cleaned up automatically.
|
||||
let packet = csp_read_guarded(&mut conn.0, Duration::from_millis(100));
|
||||
if packet.is_none() {
|
||||
break;
|
||||
}
|
||||
let packet = packet.unwrap();
|
||||
match csp_conn_dport(&conn.0) {
|
||||
MY_SERVER_PORT => {
|
||||
server_received.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
let cstr = CStr::from_bytes_with_nul(packet.as_ref().packet_data())
|
||||
.expect("invalid packet data format, is not C string");
|
||||
// Process packet here.
|
||||
println!("packet received on MY_SERVER_PORT: {:?}", cstr);
|
||||
}
|
||||
_ => {
|
||||
csp_service_handler(packet.take());
|
||||
}
|
||||
};
|
||||
}
|
||||
// No need to close, we accepted the connection with a guard.
|
||||
}
|
||||
}
|
||||
|
||||
fn client(stop_signal: Arc<AtomicBool>) {
|
||||
println!("client task started");
|
||||
let mut current_letter = 'A';
|
||||
|
||||
loop {
|
||||
if stop_signal.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
if TEST_MODE {
|
||||
thread::sleep(Duration::from_millis(20));
|
||||
} else {
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
}
|
||||
|
||||
// Send ping to server, timeout 1000 mS, ping size 20 bytes
|
||||
if let Err(e) = csp_ping(
|
||||
CSP_LOOPBACK,
|
||||
Duration::from_millis(1000),
|
||||
20,
|
||||
SocketFlags::NONE,
|
||||
) {
|
||||
println!("ping error: {:?}", e);
|
||||
}
|
||||
|
||||
// Send reboot request to server, the server has no actual implementation of
|
||||
// csp_sys_reboot() and fails to reboot.
|
||||
csp_reboot(CSP_LOOPBACK);
|
||||
|
||||
// Send data packet (string) to server
|
||||
|
||||
// 1. Connect to host on 'server_address', port MY_SERVER_PORT with regular UDP-like
|
||||
// protocol and 1000 ms timeout.
|
||||
let conn = csp_connect_guarded(
|
||||
MsgPriority::Normal,
|
||||
CSP_LOOPBACK,
|
||||
MY_SERVER_PORT as u8,
|
||||
Duration::from_millis(1000),
|
||||
ConnectOpts::NONE,
|
||||
);
|
||||
if conn.is_none() {
|
||||
println!("CSP client: connection failed");
|
||||
return;
|
||||
}
|
||||
let mut conn = conn.unwrap();
|
||||
|
||||
// 2. Get packet buffer for message/data.
|
||||
let packet_ref = csp_buffer_get();
|
||||
if packet_ref.is_none() {
|
||||
println!("CSP client: failed to get CSP buffer");
|
||||
return;
|
||||
}
|
||||
let mut packet_mut = packet_ref.unwrap();
|
||||
|
||||
// 3. Copy data to packet.
|
||||
let mut string_to_set = String::from("Hello world");
|
||||
string_to_set.push(' ');
|
||||
string_to_set.push(current_letter);
|
||||
current_letter = (current_letter as u8 + 1) as char;
|
||||
string_to_set.push('\0');
|
||||
packet_mut.set_data(string_to_set.as_bytes());
|
||||
|
||||
// 4. Send data.
|
||||
csp_send(&mut conn.0, packet_mut);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user