sim_pb/driving/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::driving::motors::SimMotors;
use crate::driving::network::SimNetwork;
use crate::driving::peripherals::{SimDisplay, SimPeripherals};
use async_channel::{bounded, Receiver, Sender};
use bevy::log::info;
use bevy::tasks::block_on;
use core_pb::driving::data::SharedRobotData;
use core_pb::driving::motors::motors_task;
use core_pb::driving::network::network_task;
use core_pb::driving::peripherals::peripherals_task;
use core_pb::driving::RobotBehavior;
use core_pb::messages::RobotButton;
use core_pb::names::RobotName;
use core_pb::util::WebTimeInstant;
use futures::{select, FutureExt};
use std::collections::VecDeque;
use std::sync::{Arc, RwLock};
use std::thread::spawn;

mod motors;
mod network;
mod peripherals;

pub const CHANNEL_BUFFER_SIZE: usize = 64;

pub struct SimRobot {
    pub name: RobotName,
    pub data: Arc<SharedRobotData<SimRobot>>,

    pub display: SimDisplay,
    pub display_updated: bool,

    pub thread_stopper: Sender<()>,
    pub firmware_updated: bool,
    pub reboot: bool,

    pub wasd_motor_speeds: Option<[f32; 3]>,
    pub requested_motor_speeds: [f32; 3],

    pub button_events: VecDeque<(RobotButton, bool)>,
    pub joystick: Option<(f32, f32)>,
}

impl SimRobot {
    pub fn start(name: RobotName, firmware_swapped: bool) -> Arc<RwLock<Self>> {
        let shared_data = Arc::new(SharedRobotData::new(name));
        let (thread_stopper_tx, thread_stopper_rx) = bounded(CHANNEL_BUFFER_SIZE);

        let robot = Arc::new(RwLock::new(Self {
            name,
            data: shared_data.clone(),

            display: SimDisplay::default(),
            display_updated: true,

            thread_stopper: thread_stopper_tx,
            firmware_updated: false,
            reboot: false,

            wasd_motor_speeds: None,
            requested_motor_speeds: [0.0; 3],

            button_events: VecDeque::new(),
            joystick: None,
        }));

        let motors = SimMotors::new(name, robot.clone());
        let network = SimNetwork::new(name, firmware_swapped, robot.clone());
        let peripherals = SimPeripherals::new(robot.clone());

        spawn(move || {
            block_on(Self::start_async(
                name,
                motors,
                network,
                shared_data.clone(),
                peripherals,
                thread_stopper_rx,
            ))
        });

        robot
    }

    pub(crate) fn destroy(&mut self) {
        block_on(async { self.thread_stopper.send(()).await }).unwrap();
    }

    #[allow(clippy::too_many_arguments)]
    async fn start_async(
        name: RobotName,
        motors: SimMotors,
        network: SimNetwork,
        data: Arc<SharedRobotData<SimRobot>>,
        peripherals: SimPeripherals,
        thread_stopper: Receiver<()>,
    ) {
        select! {
            _ = thread_stopper.recv().fuse() => {
                info!("{name} destroyed");
            }
            _ = network_task(&data, network).fuse() => {
                info!("{name} network task ended early");
            }
            _ = motors_task(&data, motors).fuse() => {
                info!("{name} motors task ended early");
            }
            _ = peripherals_task(&data, peripherals).fuse() => {
                info!("{name} peripherals task ended early");
            }
        }
    }
}

impl RobotBehavior for SimRobot {
    type Instant = WebTimeInstant;

    type Motors = SimMotors;
    type Network = SimNetwork;
    type Peripherals = SimPeripherals;
}