secop_modules/lib.rs
1// -----------------------------------------------------------------------------
2// Rust SECoP playground
3//
4// This program is free software; you can redistribute it and/or modify it under
5// the terms of the GNU General Public License as published by the Free Software
6// Foundation; either version 2 of the License, or (at your option) any later
7// version.
8//
9// This program is distributed in the hope that it will be useful, but WITHOUT
10// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12// details.
13//
14// You should have received a copy of the GNU General Public License along with
15// this program; if not, write to the Free Software Foundation, Inc.,
16// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17//
18// Module authors:
19// Georg Brandl <g.brandl@fz-juelich.de>
20//
21// -----------------------------------------------------------------------------
22//
23//! Module dispatcher.
24
25#[macro_use]
26extern crate secop_core;
27
28mod simcryo;
29mod serial;
30mod tcp;
31mod toellner;
32
33pub(crate) mod support;
34
35use std::panic::catch_unwind;
36use std::error::Error as StdError;
37use std::time::Duration;
38use std::thread::{Builder, sleep};
39use log::*;
40
41use secop_core::module::{Module, ModInternals};
42
43
44/// Inner (generic) implementation of `run_module`.
45fn inner_run<T: Module>(internals: ModInternals) {
46 let name = internals.name().to_owned();
47 Builder::new().name(name.clone()).spawn(move || loop {
48 if catch_unwind(|| {
49 T::create(internals.clone()).expect("init failed").run()
50 }).is_err() {
51 error!("module {} panicked, waiting...", name);
52 // remove all pending requests
53 internals.req_receiver().try_iter().count();
54 // wait for another request to arrive
55 while internals.req_receiver().is_empty() {
56 sleep(Duration::from_millis(100));
57 }
58 info!("now restarting module {}", name);
59 }
60 }).expect("could not start thread");
61}
62
63
64/// Start the module's own thread.
65pub fn run_module(internals: ModInternals) -> Result<(), Box<dyn StdError>> {
66 Ok(match &*internals.class() {
67 "SimCryo" => inner_run::<simcryo::SimCryo>(internals),
68 "SerialComm" => inner_run::<serial::SerialComm>(internals),
69 "TcpComm" => inner_run::<tcp::TcpComm>(internals),
70 "ToellnerPS" => inner_run::<toellner::ToellnerPS>(internals),
71 _ => return Err(format!("no such module class: {}", internals.class()).into())
72 })
73}