rsiot/components/cmp_esp_spi_master/
fn_process.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
use esp_idf_svc::hal::{
    gpio::AnyIOPin,
    peripheral::Peripheral,
    spi::{config, Operation, Spi, SpiAnyPins, SpiDeviceDriver, SpiDriver, SpiDriverConfig},
    units::FromValueType,
};
use tokio::{
    sync::{broadcast, mpsc},
    task::JoinSet,
    time::sleep,
};
use tracing::trace;

use crate::{
    components::shared_tasks::fn_process_master::FnProcessMaster,
    components_config::spi_master,
    executor::{join_set_spawn, CmpInOut},
    message::{MsgDataBound, ServiceBound},
};

use super::{config::ConfigDevicesCommSettings, Config};

pub async fn fn_process<TMsg, TService, TSpi, TPeripheral>(
    config: Config<TMsg, TSpi, TPeripheral>,
    msg_bus: CmpInOut<TMsg, TService>,
) -> super::Result<()>
where
    TMsg: MsgDataBound + 'static,
    TService: ServiceBound + 'static,
    TSpi: Peripheral<P = TPeripheral> + 'static,
    TPeripheral: Spi + SpiAnyPins + 'static,
{
    const BUFFER_SIZE: usize = 500;

    let mut task_set = JoinSet::new();

    let config_fn_process_master = FnProcessMaster {
        msg_bus: msg_bus.clone(),
        buffer_size: BUFFER_SIZE,
        task_set: &mut task_set,
        error_msgbus_to_broadcast: super::Error::TaskMsgbusToBroadcast,
        error_filter: super::Error::TaskFilter,
        error_mpsc_to_msgbus: super::Error::TaskMpscToMsgBus,
        error_master_device: super::Error::DeviceError,
        devices: config.devices,
    };
    let (ch_rx_devices_to_fieldbus, ch_tx_fieldbus_to_devices) = config_fn_process_master.spawn();

    // Коммуникация SPI ----------------------------------------------------------------------------
    let task = SpiComm {
        input: ch_rx_devices_to_fieldbus,
        output: ch_tx_fieldbus_to_devices,
        spi: config.spi,
        pin_miso: config.pin_miso,
        pin_mosi: config.pin_mosi,
        pin_sck: config.pin_sck,
        devices_comm_settings: config.devices_comm_settings,
    };
    join_set_spawn(&mut task_set, task.spawn());

    while let Some(res) = task_set.join_next().await {
        res??
    }

    Ok(())
}

struct SpiComm<TSpi, TPeripheral>
where
    TSpi: Peripheral<P = TPeripheral> + 'static,
    TPeripheral: Spi + SpiAnyPins,
{
    pub input: mpsc::Receiver<spi_master::FieldbusRequest>,
    pub output: broadcast::Sender<spi_master::FieldbusResponse>,
    pub spi: TSpi,
    pub pin_miso: AnyIOPin,
    pub pin_mosi: AnyIOPin,
    pub pin_sck: AnyIOPin,
    pub devices_comm_settings: Vec<ConfigDevicesCommSettings>,
}

impl<TSpi, TPeripheral> SpiComm<TSpi, TPeripheral>
where
    TSpi: Peripheral<P = TPeripheral> + 'static,
    TPeripheral: Spi + SpiAnyPins,
{
    pub async fn spawn(mut self) -> super::Result<()> {
        let spi_master_driver = SpiDriver::new(
            self.spi,
            self.pin_sck,
            self.pin_mosi,
            Some(self.pin_miso),
            &SpiDriverConfig::new(),
        )
        .unwrap();

        // TODO - добавить в конфигурацию

        let mut spi_devices: Vec<SpiDeviceDriver<'_, &SpiDriver<'_>>> = self
            .devices_comm_settings
            .into_iter()
            .map(|dvc| {
                let config = config::Config::new()
                    .baudrate(dvc.baudrate.Hz())
                    .data_mode(dvc.spi_mode.into());
                SpiDeviceDriver::new(&spi_master_driver, Some(dvc.pin_cs), &config).unwrap()
            })
            .collect();

        while let Some(request) = self.input.recv().await {
            trace!("New spi request: {:?}", request);

            let pin_cs = request.pin_cs as usize;

            // Номер CS недоступен
            if pin_cs >= spi_devices.len() {
                let err = super::Error::CsNotAvailable {
                    cs: request.pin_cs,
                    max_cs: spi_devices.len() as u8,
                };
                return Err(err);
            }

            let selected_device = &mut spi_devices[pin_cs];

            // Ответы от слейва
            let mut response_payload = vec![];

            // Выполняем все операции в цикле
            for operation in request.operations {
                let response = make_spi_operation(selected_device, &operation).await;
                if let Some(response) = response {
                    response_payload.push(response);
                }
            }

            let response = spi_master::FieldbusResponse {
                pin_cs: request.pin_cs,
                request_creation_time: request.request_creation_time,
                request_kind: request.request_kind,
                payload: response_payload,
            };

            self.output.send(response).unwrap();
        }
        Ok(())
    }
}

/// Выполняем обмен данными
///
/// Если присутствует операция чтения, то возвращаем данные
async fn make_spi_operation<'a>(
    device: &mut SpiDeviceDriver<'a, &SpiDriver<'a>>,
    operation: &spi_master::Operation,
) -> Option<Vec<u8>> {
    match operation {
        spi_master::Operation::Delay(duration) => {
            sleep(*duration).await;
            None
        }
        spi_master::Operation::WriteRead(write_data, read_len) => {
            let mut read_data = vec![0; *read_len as usize];
            let mut transaction = [
                Operation::Write(write_data),
                Operation::Read(&mut read_data),
            ];
            device.transaction(&mut transaction).unwrap();
            Some(read_data)
        }
        spi_master::Operation::Write(write_data) => {
            let mut transaction = [Operation::Write(write_data)];
            device.transaction(&mut transaction).unwrap();
            None
        }
    }
}