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}