1use crate::common::phys::PhysLayer;
2use std::ops::Range;
3
4use crate::common::buffer::ReadBuffer;
5use crate::common::function::FunctionCode;
6use crate::common::traits::{Loggable, LoggableDisplay, Serialize};
7use crate::error::RequestError;
8use crate::tcp::frame::{MbapDisplay, MbapHeader, MbapParser};
9use crate::types::UnitId;
10use crate::{DecodeLevel, ExceptionCode, FrameDecodeLevel};
11
12use scursor::WriteCursor;
13
14pub(crate) mod constants {
15 const fn max(lhs: usize, rhs: usize) -> usize {
16 if lhs > rhs {
17 lhs
18 } else {
19 rhs
20 }
21 }
22
23 pub(crate) const MAX_ADU_LENGTH: usize = 253;
24
25 #[cfg(feature = "serial")]
26 const fn serial_frame_size() -> usize {
27 crate::serial::frame::constants::MAX_FRAME_LENGTH
28 }
29
30 #[cfg(not(feature = "serial"))]
31 const fn serial_frame_size() -> usize {
32 0
33 }
34
35 pub(crate) const MAX_FRAME_LENGTH: usize = max(
37 crate::tcp::frame::constants::MAX_FRAME_LENGTH,
38 serial_frame_size(),
39 );
40}
41
42#[derive(PartialEq, Copy, Clone, Debug)]
43pub(crate) struct TxId {
44 value: u16,
45}
46
47impl TxId {
48 pub(crate) fn new(value: u16) -> Self {
49 TxId { value }
50 }
51
52 pub(crate) fn to_u16(self) -> u16 {
53 self.value
54 }
55
56 pub(crate) fn next(&mut self) -> TxId {
57 if self.value == u16::MAX {
58 self.value = 0;
59 TxId::new(u16::MAX)
60 } else {
61 let ret = self.value;
62 self.value += 1;
63 TxId::new(ret)
64 }
65 }
66}
67
68impl Default for TxId {
69 fn default() -> Self {
70 TxId::new(0)
71 }
72}
73
74impl std::fmt::Display for TxId {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 write!(f, "{:#04X}", self.value)
77 }
78}
79
80#[derive(Debug, Copy, Clone, PartialEq)]
81pub(crate) enum FrameDestination {
82 UnitId(UnitId),
84 Broadcast,
86}
87
88impl FrameDestination {
89 #[cfg(test)]
90 pub(crate) fn new_unit_id(value: u8) -> Self {
91 Self::UnitId(UnitId::new(value))
92 }
93
94 pub(crate) fn value(&self) -> u8 {
95 match self {
96 Self::UnitId(unit_id) => unit_id.value,
97 Self::Broadcast => UnitId::broadcast().value,
98 }
99 }
100
101 pub(crate) fn into_unit_id(self) -> UnitId {
102 UnitId::new(self.value())
103 }
104
105 pub(crate) fn is_broadcast(&self) -> bool {
106 std::matches!(self, FrameDestination::Broadcast)
107 }
108}
109
110impl std::fmt::Display for FrameDestination {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 match self {
113 Self::UnitId(unit_id) => write!(f, "{unit_id}"),
114 Self::Broadcast => write!(f, "BCAST ({})", UnitId::broadcast()),
115 }
116 }
117}
118
119#[derive(Debug, Copy, Clone)]
120pub(crate) struct FrameHeader {
121 pub(crate) destination: FrameDestination,
122 pub(crate) tx_id: Option<TxId>,
124}
125
126impl FrameHeader {
127 pub(crate) fn new_tcp_header(unit_id: UnitId, tx_id: TxId) -> Self {
128 FrameHeader {
129 destination: FrameDestination::UnitId(unit_id),
130 tx_id: Some(tx_id),
131 }
132 }
133
134 #[cfg(feature = "serial")]
135 pub(crate) fn new_rtu_header(destination: FrameDestination) -> Self {
136 FrameHeader {
137 destination,
138 tx_id: None,
139 }
140 }
141}
142
143pub(crate) struct Frame {
144 pub(crate) header: FrameHeader,
145 length: usize,
146 pdu: [u8; constants::MAX_ADU_LENGTH],
147}
148
149impl Frame {
150 pub(crate) fn new(header: FrameHeader) -> Frame {
151 Frame {
152 header,
153 length: 0,
154 pdu: [0; constants::MAX_ADU_LENGTH],
155 }
156 }
157
158 pub(crate) fn set(&mut self, src: &[u8]) -> bool {
159 if src.len() > self.pdu.len() {
160 return false;
161 }
162
163 self.pdu[0..src.len()].copy_from_slice(src);
164 self.length = src.len();
165 true
166 }
167
168 pub(crate) fn payload(&self) -> &[u8] {
169 &self.pdu[0..self.length]
170 }
171}
172
173pub(crate) enum FrameParser {
175 #[cfg(feature = "serial")]
176 Rtu(crate::serial::frame::RtuParser),
177 Tcp(MbapParser),
178}
179
180impl FrameParser {
181 pub(crate) fn parse(
188 &mut self,
189 cursor: &mut ReadBuffer,
190 decode_level: FrameDecodeLevel,
191 ) -> Result<Option<Frame>, RequestError> {
192 match self {
193 #[cfg(feature = "serial")]
194 FrameParser::Rtu(x) => x.parse(cursor, decode_level),
195 FrameParser::Tcp(x) => x.parse(cursor, decode_level),
196 }
197 }
198
199 pub(crate) fn reset(&mut self) {
201 match self {
202 #[cfg(feature = "serial")]
203 FrameParser::Rtu(x) => x.reset(),
204 FrameParser::Tcp(x) => x.reset(),
205 }
206 }
207}
208
209pub(crate) enum FrameType {
210 Mbap(MbapHeader),
211 #[cfg(feature = "serial")]
212 Rtu(FrameDestination, u16),
214}
215
216pub(crate) struct FrameInfo {
217 pub(crate) frame_type: FrameType,
219 pub(crate) pdu_body: Range<usize>,
221}
222
223impl FrameInfo {
224 pub(crate) fn new(frame_type: FrameType, pdu_body: Range<usize>) -> Self {
225 Self {
226 frame_type,
227 pdu_body,
228 }
229 }
230}
231
232enum FormatType {
233 Tcp,
234 #[cfg(feature = "serial")]
235 Rtu,
236}
237
238impl FormatType {
239 fn format(
240 &self,
241 cursor: &mut WriteCursor,
242 header: FrameHeader,
243 function: FunctionField,
244 body: &dyn Serialize,
245 ) -> Result<FrameInfo, RequestError> {
246 match self {
247 FormatType::Tcp => crate::tcp::frame::format_mbap(cursor, header, function, body),
248 #[cfg(feature = "serial")]
249 FormatType::Rtu => crate::serial::frame::format_rtu_pdu(cursor, header, function, body),
250 }
251 }
252}
253
254pub(crate) struct FrameWriter {
255 format_type: FormatType,
256 buffer: [u8; constants::MAX_FRAME_LENGTH],
257}
258
259#[derive(Copy, Clone, Debug)]
260pub(crate) enum FunctionField {
261 Valid(FunctionCode),
262 Exception(FunctionCode),
263 UnknownFunction(u8),
264}
265
266impl std::fmt::Display for FunctionField {
267 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
268 let value = self.get_value();
269 match self {
270 FunctionField::Valid(x) => {
271 write!(f, "{x}")
272 }
273 FunctionField::Exception(x) => {
274 write!(f, "Exception({value}) for {x}")
275 }
276 FunctionField::UnknownFunction(_) => {
277 write!(f, "Unknown Function Exception: {value}")
278 }
279 }
280 }
281}
282
283impl FunctionField {
284 pub(crate) fn unknown(fc: u8) -> Self {
285 Self::UnknownFunction(fc)
286 }
287
288 pub(crate) fn get_value(&self) -> u8 {
289 match self {
290 FunctionField::Valid(x) => x.get_value(),
291 FunctionField::Exception(x) => x.get_value() | 0x80,
292 FunctionField::UnknownFunction(x) => x | 0x80,
293 }
294 }
295}
296
297impl FrameWriter {
298 fn new(format_type: FormatType) -> Self {
299 Self {
300 format_type,
301 buffer: [0; constants::MAX_FRAME_LENGTH],
302 }
303 }
304
305 pub(crate) fn format_reply<T>(
306 &mut self,
307 header: FrameHeader,
308 function: FunctionCode,
309 body: &T,
310 decode_level: DecodeLevel,
311 ) -> Result<&[u8], RequestError>
312 where
313 T: Serialize + Loggable,
314 {
315 match self.format_generic(header, FunctionField::Valid(function), body, decode_level) {
316 Ok(x) => Ok(&self.buffer[x]),
317 Err(RequestError::Exception(ex)) => {
318 self.format_ex(header, FunctionField::Exception(function), ex, decode_level)
319 }
320 Err(err) => Err(err),
321 }
322 }
323
324 pub(crate) fn format_request<T>(
325 &mut self,
326 header: FrameHeader,
327 function: FunctionCode,
328 body: &T,
329 decode_level: DecodeLevel,
330 ) -> Result<&[u8], RequestError>
331 where
332 T: Serialize + Loggable,
333 {
334 let range =
335 self.format_generic(header, FunctionField::Valid(function), body, decode_level)?;
336 Ok(&self.buffer[range])
337 }
338
339 pub(crate) fn format_ex(
340 &mut self,
341 header: FrameHeader,
342 function: FunctionField,
343 ex: ExceptionCode,
344 decode_level: DecodeLevel,
345 ) -> Result<&[u8], RequestError> {
346 let function = match function {
347 FunctionField::Valid(x) => FunctionField::Exception(x),
348 FunctionField::Exception(x) => FunctionField::Exception(x),
349 FunctionField::UnknownFunction(x) => FunctionField::UnknownFunction(x),
350 };
351
352 let range = self.format_generic(header, function, &ex, decode_level)?;
353
354 Ok(&self.buffer[range])
355 }
356
357 fn format_generic<T>(
358 &mut self,
359 header: FrameHeader,
360 function: FunctionField,
361 body: &T,
362 decode_level: DecodeLevel,
363 ) -> Result<Range<usize>, RequestError>
364 where
365 T: Serialize + Loggable,
366 {
367 let (frame_type, frame_bytes, pdu_body) = {
368 let mut cursor = WriteCursor::new(self.buffer.as_mut());
369 let info = self
370 .format_type
371 .format(&mut cursor, header, function, body)?;
372 let end = cursor.position();
373 (info.frame_type, 0..end, &self.buffer[info.pdu_body])
374 };
375
376 if decode_level.app.enabled() {
377 tracing::info!(
378 "PDU TX - {} {}",
379 function,
380 LoggableDisplay::new(body, pdu_body, decode_level.app)
381 );
382 }
383
384 if decode_level.frame.enabled() {
385 let frame_bytes = &self.buffer[frame_bytes.clone()];
386 match frame_type {
387 FrameType::Mbap(header) => {
388 tracing::info!(
389 "MBAP TX - {}",
390 MbapDisplay::new(decode_level.frame, header, frame_bytes)
391 );
392 }
393 #[cfg(feature = "serial")]
394 FrameType::Rtu(dest, crc) => {
395 tracing::info!(
396 "RTU TX - {}",
397 crate::serial::frame::RtuDisplay::new(
398 decode_level.frame,
399 dest,
400 frame_bytes,
401 crc
402 )
403 );
404 }
405 }
406 }
407
408 Ok(frame_bytes)
409 }
410
411 pub(crate) fn tcp() -> Self {
412 Self::new(FormatType::Tcp)
413 }
414
415 #[cfg(feature = "serial")]
416 pub(crate) fn rtu() -> Self {
417 Self::new(FormatType::Rtu)
418 }
419}
420
421pub(crate) struct FramedReader {
422 parser: FrameParser,
423 buffer: ReadBuffer,
424}
425
426impl FramedReader {
427 pub(crate) fn tcp() -> Self {
428 Self::new(FrameParser::Tcp(MbapParser::new()))
429 }
430
431 #[cfg(feature = "serial")]
432 pub(crate) fn rtu_request() -> Self {
433 Self::new(FrameParser::Rtu(
434 crate::serial::frame::RtuParser::new_request_parser(),
435 ))
436 }
437
438 #[cfg(feature = "serial")]
439 pub(crate) fn rtu_response() -> Self {
440 Self::new(FrameParser::Rtu(
441 crate::serial::frame::RtuParser::new_response_parser(),
442 ))
443 }
444
445 fn new(parser: FrameParser) -> Self {
446 Self {
447 parser,
448 buffer: ReadBuffer::new(),
449 }
450 }
451
452 pub(crate) async fn next_frame(
453 &mut self,
454 io: &mut PhysLayer,
455 decode_level: DecodeLevel,
456 ) -> Result<Frame, RequestError> {
457 loop {
458 match self.parser.parse(&mut self.buffer, decode_level.frame) {
459 Ok(Some(frame)) => return Ok(frame),
460 Ok(None) => {
461 self.buffer.read_some(io, decode_level.physical).await?;
462 }
463 Err(err) => {
464 self.parser.reset();
465 return Err(err);
466 }
467 }
468 }
469 }
470}