Skip to main content

x328_proto/
node.rs

1//! An implementation of the "node" half of the X3.28 protocol. See [`Node`] for more details.
2
3use crate::ascii::*;
4use crate::bcc;
5use crate::buffer::Buffer;
6use crate::nom_parser::node::{parse_command, CommandToken};
7use crate::types::{Address, Parameter, Value};
8use core::marker::PhantomData;
9
10/// Bus node (listener/server) part of the X3.28 protocol
11///
12/// Create a new protocol instance with `Node::new(address)`. The current protocol state can be
13/// retrieved by calling `state()`. The [`NodeState`] enum returned contains structs that should
14/// be acted upon in order to advance the protocol state machine.
15///
16/// # Example
17///
18/// ```
19/// use x328_proto::node::{Node, NodeState};
20/// # use std::io::{Read, Write, Cursor};
21/// # fn connect_serial_interface() -> Result<Cursor<Vec<u8>>,  &'static str>
22/// # { Ok(Cursor::new(Vec::new())) }
23/// #
24/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
25/// use x328_proto::{addr, Value};
26/// let mut node = Node::new(addr(10)); // new protocol instance with address 10
27/// let mut serial = connect_serial_interface()?;
28/// let mut token = node.reset();
29///
30/// 'main: loop {
31///        # break // this snippet is only for show
32///        match node.state(token) {
33///            NodeState::ReceiveData(recv) => {
34///                let mut buf = [0; 1];
35///                if let Ok(len) = serial.read(&mut buf) {
36///                    if len == 0 {
37///                        break 'main;
38///                    }
39///                    token = recv.receive_data(&buf[..len]);
40///                } else {
41///                    break 'main;
42///                }
43///            }
44///
45///            NodeState::SendData(mut send) => {
46///                serial.write_all(send.send_data()).unwrap();
47///            }
48///
49///            NodeState::ReadParameter(read_command) => {
50///                if read_command.parameter() == 3 {
51///                    read_command.send_invalid_parameter();
52///                } else {
53///                    read_command.send_reply_ok(4u16.into());
54///                }
55///            }
56///
57///            NodeState::WriteParameter(write_command) => {
58///                let param = write_command.parameter();
59///                if param == 3 {
60///                    write_command.write_error();
61///                } else {
62///                    write_command.write_ok();
63///                }
64///            }
65///        };
66/// }
67/// # Ok(()) }
68///  ```
69#[derive(Debug)]
70pub struct Node {
71    state: InternalState,
72    address: Address,
73    read_again_param: Option<(Address, Parameter)>,
74    buffer: Buffer,
75}
76
77/// The current protocol state, as seen by this node.
78pub enum NodeState<'node> {
79    /// More data needs to be received from the bus.
80    ReceiveData(ReceiveData<'node>),
81    /// Data is waiting to be transmitted.
82    SendData(SendData<'node>),
83    /// A parameter read request.
84    ReadParameter(ReadParam<'node>),
85    /// A parameter write request.
86    WriteParameter(WriteParam<'node>),
87}
88
89/// ZST used for making sure that the protocol state always is advancing.
90pub struct StateToken(PhantomData<()>);
91
92impl<'a> From<ReceiveData<'a>> for NodeState<'a> {
93    fn from(x: ReceiveData<'a>) -> Self {
94        Self::ReceiveData(x)
95    }
96}
97
98impl<'a> From<SendData<'a>> for NodeState<'a> {
99    fn from(x: SendData<'a>) -> Self {
100        Self::SendData(x)
101    }
102}
103
104impl<'a> From<WriteParam<'a>> for NodeState<'a> {
105    fn from(x: WriteParam<'a>) -> Self {
106        Self::WriteParameter(x)
107    }
108}
109impl<'a> From<ReadParam<'a>> for NodeState<'a> {
110    fn from(x: ReadParam<'a>) -> Self {
111        Self::ReadParameter(x)
112    }
113}
114#[derive(Debug, Copy, Clone, PartialEq)]
115enum InternalState {
116    Recv,
117    Send,
118    Read {
119        address: Address,
120        parameter: Parameter,
121    },
122    Write {
123        address: Address,
124        parameter: Parameter,
125        value: Value,
126    },
127}
128
129impl Node {
130    /// Create a new protocol instance, accepting commands for the given address.
131    /// # Example
132    ///
133    /// ```
134    /// use x328_proto::{addr, node::Node};
135    /// let mut node = Node::new(addr(10)); // new protocol instance with address 10
136    /// ```
137    pub fn new(address: Address) -> Self {
138        Self {
139            state: InternalState::Recv,
140            address,
141            read_again_param: None,
142            buffer: Buffer::new(),
143        }
144    }
145
146    /// Obtain a new StateToken by resetting the protocol state to "receive data".
147    pub fn reset(&mut self) -> StateToken {
148        ReceiveData::from_state(self);
149        StateToken(PhantomData)
150    }
151
152    /// Returns the current protocol state. Act on the inner structs in order to advance the
153    /// protocol state machine.
154    pub fn state(&mut self, token: StateToken) -> NodeState<'_> {
155        let _ = token;
156        match self.state {
157            InternalState::Recv => ReceiveData::from_state(self).into(),
158            InternalState::Send => SendData::from_state(self).into(),
159            InternalState::Read { address, parameter } => {
160                ReadParam::from_state(self, address, parameter).into()
161            }
162            InternalState::Write {
163                address,
164                parameter,
165                value,
166            } => WriteParam::from_state(self, address, parameter, value).into(),
167        }
168    }
169
170    fn set_state(&mut self, state: InternalState) {
171        self.state = state;
172    }
173
174    /// Do not send any reply to the bus controller. Transition to the idle `ReceiveData` state instead.
175    /// You should avoid this, since this will leave the controller waiting until it times out.
176    pub fn no_reply(&mut self, _token: StateToken) -> StateToken {
177        self.reset()
178    }
179}
180
181/// "Receive data from bus" state.
182#[derive(Debug)]
183pub struct ReceiveData<'node> {
184    node: &'node mut Node,
185}
186
187impl<'node> ReceiveData<'node> {
188    fn from_state(node: &'node mut Node) -> Self {
189        if node.state != InternalState::Recv {
190            node.buffer.clear();
191        }
192        node.set_state(InternalState::Recv);
193        Self { node }
194    }
195
196    /// Feed data into the internal buffer, and try to parse the buffer afterwards.
197    ///
198    /// A state transition will occur if a complete command has been received,
199    /// or if a protocol error requires a response to be sent.
200    pub fn receive_data(self, data: &[u8]) -> StateToken {
201        self.node.buffer.write(data);
202        self.parse_buffer();
203        StateToken(PhantomData)
204    }
205
206    fn parse_buffer(self) -> NodeState<'node> {
207        use CommandToken::{
208            InvalidPayload, ReadAgain, ReadNext, ReadParameter, ReadPrevious, WriteParameter,
209        };
210
211        let buffer = &mut self.node.buffer;
212
213        let (token, read_again_param) = loop {
214            match parse_command(buffer.as_ref()) {
215                (0, _) => return self.need_data(),
216                (consumed, token) => {
217                    buffer.consume(consumed);
218                    // Take the read again parameter from our state. It would be invalid
219                    // to use it for later tokens, that's why it's extracted in the loop.
220                    let read_again_param = self.node.read_again_param.take();
221
222                    // We're done parsing when the buffer is empty
223                    if buffer.len() == 0 {
224                        break (token, read_again_param);
225                    }
226                }
227            };
228        };
229
230        match token {
231            ReadParameter(address, parameter) if self.for_us(address) => {
232                ReadParam::from_state(self.node, address, parameter).into()
233            }
234            WriteParameter(address, parameter, value) if self.for_us(address) => {
235                WriteParam::from_state(self.node, address, parameter, value).into()
236            }
237            ReadAgain | ReadNext | ReadPrevious if read_again_param.is_some() => {
238                let (addr, last_param) = read_again_param.unwrap();
239                match match token {
240                    ReadPrevious => last_param.prev(),
241                    ReadNext => last_param.next(),
242                    _ => Some(last_param),
243                } {
244                    Some(param) => ReadParam::from_state(self.node, addr, param).into(),
245                    None => SendData::from_byte(self.node, EOT).into(),
246                }
247            }
248            InvalidPayload(address) if address == self.node.address => self.send_nak(),
249            _ => self.need_data(), // This matches NeedData, and read/write to other addresses
250        }
251    }
252
253    fn send_byte(self, byte: u8) -> NodeState<'node> {
254        SendData::from_byte(self.node, byte).into()
255    }
256
257    fn need_data(self) -> NodeState<'node> {
258        self.into()
259    }
260
261    fn send_nak(self) -> NodeState<'node> {
262        self.send_byte(NAK)
263    }
264
265    fn for_us(&self, address: Address) -> bool {
266        self.node.address == address || self.node.address == 0
267    }
268}
269
270/// "Transmit data on the bus" state.
271///
272/// Call [`send_data()`](Self::send_data()) to get a reference to the data to be transmitted,
273/// and then call [`data_sent()`](Self::data_sent()) when the data has been successfully transmitted.
274#[derive(Debug)]
275pub struct SendData<'node> {
276    node: &'node mut Node,
277}
278
279impl<'node> SendData<'node> {
280    /// SendData::from_state expects that the node buffer already has been prepared
281    fn from_state(node: &'node mut Node) -> Self {
282        node.set_state(InternalState::Send);
283        Self { node }
284    }
285
286    fn from_byte(node: &'node mut Node, byte: u8) -> Self {
287        let buf = &mut node.buffer;
288        buf.clear();
289        buf.push(byte);
290        Self::from_state(node)
291    }
292
293    /// Returns the data to be sent on the bus, and changes the state to "receive data".
294    pub fn send_data(&self) -> &[u8] {
295        self.node.buffer.as_ref()
296    }
297
298    /// Indicate that the response data has been transmitted successfully, and move to the "receive data" state.
299    pub fn data_sent(self) -> StateToken {
300        self.node.set_state(InternalState::Recv);
301        self.node.buffer.get_ref_and_clear();
302        StateToken(PhantomData)
303    }
304}
305
306/// The "read command received" state. The bus controller expects a reply with the current
307/// value of the specified parameter.
308#[derive(Debug)]
309pub struct ReadParam<'node> {
310    node: &'node mut Node,
311    address: Address,
312    parameter: Parameter,
313}
314
315impl<'node> ReadParam<'node> {
316    fn from_state(node: &'node mut Node, address: Address, parameter: Parameter) -> Self {
317        node.set_state(InternalState::Read { address, parameter });
318        Self {
319            node,
320            address,
321            parameter,
322        }
323    }
324
325    /// Send a response to the master with the value of
326    /// the parameter in the read request.
327    pub fn send_reply_ok(self, value: Value) -> StateToken {
328        self.node.read_again_param = Some((self.address, self.parameter));
329
330        let data = &mut self.node.buffer;
331        data.clear();
332
333        data.push(STX);
334        data.write(&self.parameter.to_bytes());
335        data.write(&value.to_bytes());
336        data.push(ETX);
337        data.push(bcc(&data.as_ref()[1..]));
338
339        SendData::from_state(self.node);
340        StateToken(PhantomData)
341    }
342
343    /// Inform the master that the parameter in the request is invalid.
344    pub fn send_invalid_parameter(self) -> StateToken {
345        SendData::from_byte(self.node, EOT);
346        StateToken(PhantomData)
347    }
348
349    /// Inform the bus master that the read request failed
350    /// for some reason other than invalid parameter number.
351    pub fn send_read_failed(self) -> StateToken {
352        SendData::from_byte(self.node, NAK);
353        StateToken(PhantomData)
354    }
355
356    /// Do not send any reply to the master. Transition to the idle `ReceiveData` state instead.
357    /// You really shouldn't do this, since this will leave the master waiting until it times out.
358    pub fn no_reply(self) -> StateToken {
359        ReceiveData::from_state(self.node);
360        StateToken(PhantomData)
361    }
362
363    /// Get the address the request was sent to.
364    pub const fn address(&self) -> Address {
365        self.address
366    }
367
368    /// The parameter whose value is to be returned.
369    pub const fn parameter(&self) -> Parameter {
370        self.parameter
371    }
372}
373
374/// "Write command received" state. The bus controller wants to change the value
375/// of the specified parameter.
376#[derive(Debug)]
377pub struct WriteParam<'node> {
378    node: &'node mut Node,
379    address: Address,
380    parameter: Parameter,
381    value: Value,
382}
383
384impl<'node> WriteParam<'node> {
385    fn from_state(
386        node: &'node mut Node,
387        address: Address,
388        parameter: Parameter,
389        value: Value,
390    ) -> Self {
391        node.set_state(InternalState::Write {
392            address,
393            parameter,
394            value,
395        });
396        Self {
397            node,
398            address,
399            parameter,
400            value,
401        }
402    }
403
404    /// Inform the bus controller that the parameter value was successfully updated.
405    pub fn write_ok(self) -> StateToken {
406        SendData::from_byte(self.node, ACK);
407        StateToken(PhantomData)
408    }
409
410    /// The parameter or value is invalid, or something else is preventing
411    /// us from setting the parameter to the given value.
412    pub fn write_error(self) -> StateToken {
413        SendData::from_byte(self.node, NAK);
414        StateToken(PhantomData)
415    }
416
417    /// Do not send any reply to the bus controller. Transition to the idle `ReceiveData` state instead.
418    /// You should avoid this, since this will leave the controller waiting until it times out.
419    pub fn no_reply(self) -> StateToken {
420        ReceiveData::from_state(self.node);
421        StateToken(PhantomData)
422    }
423
424    /// The address the write request was sent to.
425    pub const fn address(&self) -> Address {
426        self.address
427    }
428
429    /// The parameter to be written.
430    pub const fn parameter(&self) -> Parameter {
431        self.parameter
432    }
433
434    /// The new value for the parameter.
435    pub const fn value(&self) -> Value {
436        self.value
437    }
438}