rsiot/components/cmp_esp_spi_master/
fn_process.rs

1use esp_idf_svc::hal::{
2    gpio::AnyIOPin,
3    peripheral::Peripheral,
4    spi::{config, Operation, Spi, SpiAnyPins, SpiDeviceDriver, SpiDriver, SpiDriverConfig},
5    units::FromValueType,
6};
7use tokio::{sync::mpsc, task::JoinSet, time::sleep};
8use tracing::trace;
9
10use crate::{
11    components::shared_tasks::fn_process_master::FnProcessMaster,
12    components_config::{
13        master_device::{FieldbusRequestWithIndex, FieldbusResponseWithIndex},
14        spi_master,
15    },
16    executor::{join_set_spawn, CmpInOut},
17    message::MsgDataBound,
18};
19
20use super::{config::ConfigDevicesCommSettings, Config};
21
22pub async fn fn_process<TMsg, TSpi, TPeripheral>(
23    config: Config<TMsg, TSpi, TPeripheral>,
24    msg_bus: CmpInOut<TMsg>,
25) -> super::Result<()>
26where
27    TMsg: MsgDataBound + 'static,
28    TSpi: Peripheral<P = TPeripheral> + 'static,
29    TPeripheral: Spi + SpiAnyPins + 'static,
30{
31    const BUFFER_SIZE: usize = 500;
32
33    let mut task_set = JoinSet::new();
34
35    let config_fn_process_master = FnProcessMaster {
36        msg_bus: msg_bus.clone(),
37        buffer_size: BUFFER_SIZE,
38        task_set: &mut task_set,
39        error_msgbus_to_broadcast: super::Error::TaskMsgbusToBroadcast,
40        error_filter: super::Error::TaskFilter,
41        error_mpsc_to_msgbus: super::Error::TaskMpscToMsgBus,
42        error_master_device: super::Error::DeviceError,
43        error_tokiompscsend: || super::Error::TokioMpscSend,
44        devices: config.devices,
45    };
46    let (ch_rx_devices_to_fieldbus, ch_tx_fieldbus_to_devices) = config_fn_process_master.spawn();
47
48    // Коммуникация SPI ----------------------------------------------------------------------------
49    let task = SpiComm {
50        input: ch_rx_devices_to_fieldbus,
51        output: ch_tx_fieldbus_to_devices,
52        spi: config.spi,
53        pin_miso: config.pin_miso,
54        pin_mosi: config.pin_mosi,
55        pin_sck: config.pin_sck,
56        devices_comm_settings: config.devices_comm_settings,
57    };
58    join_set_spawn(&mut task_set, task.spawn());
59
60    while let Some(res) = task_set.join_next().await {
61        res??
62    }
63
64    Ok(())
65}
66
67struct SpiComm<TSpi, TPeripheral>
68where
69    TSpi: Peripheral<P = TPeripheral> + 'static,
70    TPeripheral: Spi + SpiAnyPins,
71{
72    pub input: mpsc::Receiver<FieldbusRequestWithIndex<spi_master::FieldbusRequest>>,
73    pub output: mpsc::Sender<FieldbusResponseWithIndex<spi_master::FieldbusResponse>>,
74    pub spi: TSpi,
75    pub pin_miso: AnyIOPin,
76    pub pin_mosi: AnyIOPin,
77    pub pin_sck: AnyIOPin,
78    pub devices_comm_settings: Vec<ConfigDevicesCommSettings>,
79}
80
81impl<TSpi, TPeripheral> SpiComm<TSpi, TPeripheral>
82where
83    TSpi: Peripheral<P = TPeripheral> + 'static,
84    TPeripheral: Spi + SpiAnyPins,
85{
86    pub async fn spawn(mut self) -> super::Result<()> {
87        let spi_master_driver = SpiDriver::new(
88            self.spi,
89            self.pin_sck,
90            self.pin_mosi,
91            Some(self.pin_miso),
92            &SpiDriverConfig::new(),
93        )
94        .unwrap();
95
96        let mut spi_devices: Vec<SpiDeviceDriver<'_, &SpiDriver<'_>>> = self
97            .devices_comm_settings
98            .into_iter()
99            .map(|dvc| {
100                let config = config::Config::new()
101                    .baudrate(dvc.baudrate.Hz())
102                    .data_mode(dvc.spi_mode.into());
103                SpiDeviceDriver::new(&spi_master_driver, Some(dvc.pin_cs), &config).unwrap()
104            })
105            .collect();
106
107        while let Some(request_with_index) = self.input.recv().await {
108            trace!("New spi request: {:?}", request_with_index);
109
110            let device_index = request_with_index.device_index;
111            let request = request_with_index.request;
112
113            // Номер CS недоступен
114            if device_index >= spi_devices.len() {
115                let err = super::Error::CsNotAvailable {
116                    cs: device_index as u8,
117                    max_cs: spi_devices.len() as u8,
118                };
119                return Err(err);
120            }
121
122            let selected_device = &mut spi_devices[device_index];
123
124            // Ответы от слейва
125            let mut response_payload = vec![];
126
127            // Выполняем все операции в цикле
128            for operation in request.operations {
129                let response = make_spi_operation(selected_device, &operation).await;
130                if let Some(response) = response {
131                    response_payload.push(response);
132                }
133            }
134
135            let response = spi_master::FieldbusResponse {
136                request_creation_time: request.request_creation_time,
137                request_kind: request.request_kind,
138                payload: response_payload,
139            };
140            let response_with_index = FieldbusResponseWithIndex {
141                device_index,
142                response,
143            };
144
145            trace!("Response: {:?}", response_with_index);
146
147            self.output.send(response_with_index).await.unwrap();
148        }
149        Ok(())
150    }
151}
152
153/// Выполняем обмен данными
154///
155/// Если присутствует операция чтения, то возвращаем данные
156async fn make_spi_operation<'a>(
157    device: &mut SpiDeviceDriver<'a, &SpiDriver<'a>>,
158    operation: &spi_master::Operation,
159) -> Option<Vec<u8>> {
160    match operation {
161        spi_master::Operation::Delay(duration) => {
162            sleep(*duration).await;
163            None
164        }
165        spi_master::Operation::WriteRead(write_data, read_len) => {
166            let mut read_data = vec![0; *read_len as usize];
167            trace!("Write SPI data: {:x?}", write_data);
168            let mut transaction = [
169                Operation::Write(write_data),
170                Operation::Read(&mut read_data),
171            ];
172            device.transaction(&mut transaction).unwrap();
173            trace!("Read SPI data: {:x?}", read_data);
174            Some(read_data)
175        }
176        spi_master::Operation::Write(write_data) => {
177            trace!("Write SPI data: {:x?}", write_data);
178            let mut transaction = [Operation::Write(write_data)];
179            device.transaction(&mut transaction).unwrap();
180            None
181        }
182    }
183}