rsiot/components/cmp_esp_spi_master/
fn_process.rs1use 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 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 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 let mut response_payload = vec![];
126
127 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
153async 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}