Skip to main content

rtlp_lib/
lib.rs

1use std::convert::TryFrom;
2use std::fmt::Display;
3
4#[macro_use]
5extern crate bitfield;
6
7/// Errors that can occur when parsing TLP packets
8#[derive(Debug, Clone, PartialEq)]
9pub enum TlpError {
10    /// Invalid format field value (bits don't match any known format)
11    InvalidFormat,
12    /// Invalid type field value (bits don't match any known type encoding)
13    InvalidType,
14    /// Unsupported combination of format and type
15    UnsupportedCombination,
16}
17
18#[repr(u8)]
19#[derive(PartialEq, Copy, Clone)]
20pub enum TlpFmt {
21    NoDataHeader3DW     = 0b000,
22    NoDataHeader4DW     = 0b001,
23    WithDataHeader3DW   = 0b010,
24    WithDataHeader4DW   = 0b011,
25    TlpPrefix           = 0b100,
26}
27
28impl Display for TlpFmt {
29    fn fmt (&self, fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
30        let name = match &self {
31            TlpFmt::NoDataHeader3DW => "3DW no Data Header",
32            TlpFmt::NoDataHeader4DW => "4DW no Data Header",
33            TlpFmt::WithDataHeader3DW => "3DW with Data Header",
34            TlpFmt::WithDataHeader4DW => "4DW with Data Header",
35            TlpFmt::TlpPrefix => "Tlp Prefix",
36        };
37        write!(fmt, "{}", name)
38    }
39}
40
41impl TryFrom<u32> for TlpFmt {
42    type Error = TlpError;
43
44    fn try_from(v: u32) -> Result<Self, Self::Error> {
45        match v {
46            x if x == TlpFmt::NoDataHeader3DW as u32 => Ok(TlpFmt::NoDataHeader3DW),
47            x if x == TlpFmt::NoDataHeader4DW as u32 => Ok(TlpFmt::NoDataHeader4DW),
48            x if x == TlpFmt::WithDataHeader3DW as u32 => Ok(TlpFmt::WithDataHeader3DW),
49            x if x == TlpFmt::WithDataHeader4DW as u32 => Ok(TlpFmt::WithDataHeader4DW),
50            x if x == TlpFmt::TlpPrefix as u32 => Ok(TlpFmt::TlpPrefix),
51            _ => Err(TlpError::InvalidFormat),
52        }
53    }
54}
55
56#[derive(PartialEq)]
57pub enum TlpFormatEncodingType {
58    MemoryRequest           = 0b00000,
59    MemoryLockRequest       = 0b00001,
60    IORequest               = 0b00010,
61    ConfigType0Request      = 0b00100,
62    ConfigType1Request      = 0b00101,
63    Completion              = 0b01010,
64    CompletionLocked        = 0b01011,
65    FetchAtomicOpRequest    = 0b01100,
66    UnconSwapAtomicOpRequest= 0b01101,
67    CompSwapAtomicOpRequest = 0b01110,
68}
69
70impl TryFrom<u32> for TlpFormatEncodingType {
71    type Error = TlpError;
72
73    fn try_from(v: u32) -> Result<Self, Self::Error> {
74        match v {
75            x if x == TlpFormatEncodingType::MemoryRequest as u32 			=> Ok(TlpFormatEncodingType::MemoryRequest),
76            x if x == TlpFormatEncodingType::MemoryLockRequest as u32 		=> Ok(TlpFormatEncodingType::MemoryLockRequest),
77            x if x == TlpFormatEncodingType::IORequest as u32 				=> Ok(TlpFormatEncodingType::IORequest),
78            x if x == TlpFormatEncodingType::ConfigType0Request as u32 		=> Ok(TlpFormatEncodingType::ConfigType0Request),
79            x if x == TlpFormatEncodingType::ConfigType1Request as u32 		=> Ok(TlpFormatEncodingType::ConfigType1Request),
80            x if x == TlpFormatEncodingType::Completion as u32 				=> Ok(TlpFormatEncodingType::Completion),
81            x if x == TlpFormatEncodingType::CompletionLocked  as u32 		=> Ok(TlpFormatEncodingType::CompletionLocked),
82            x if x == TlpFormatEncodingType::FetchAtomicOpRequest as u32 	=> Ok(TlpFormatEncodingType::FetchAtomicOpRequest),
83            x if x == TlpFormatEncodingType::UnconSwapAtomicOpRequest as u32 => Ok(TlpFormatEncodingType::UnconSwapAtomicOpRequest),
84            x if x == TlpFormatEncodingType::CompSwapAtomicOpRequest as u32 => Ok(TlpFormatEncodingType::CompSwapAtomicOpRequest),
85            _ => Err(TlpError::InvalidType),
86        }
87    }
88}
89
90#[derive(PartialEq)]
91#[derive(Debug)]
92pub enum TlpType {
93    MemReadReq,
94    MemReadLockReq,
95    MemWriteReq,
96    IOReadReq,
97    IOWriteReq,
98    ConfType0ReadReq,
99    ConfType0WriteReq,
100    ConfType1ReadReq,
101    ConfType1WriteReq,
102    MsgReq,
103    MsgReqData,
104    Cpl,
105    CplData,
106    CplLocked,
107    CplDataLocked,
108    FetchAddAtomicOpReq,
109    SwapAtomicOpReq,
110    CompareSwapAtomicOpReq,
111    LocalTlpPrefix,
112    EndToEndTlpPrefix,
113}
114
115impl Display for TlpType {
116    fn fmt (&self, fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
117        let name = match &self {
118            TlpType::MemReadReq => "Memory Read Request",
119            TlpType::MemReadLockReq => "Locked Memory Read Request",
120            TlpType::MemWriteReq => "Memory Write Request",
121            TlpType::IOReadReq => "IO Read Request",
122            TlpType::IOWriteReq => "IO Write Request",
123            TlpType::ConfType0ReadReq => "Type 0 Config Read Request",
124            TlpType::ConfType0WriteReq => "Type 0 Config Write Request",
125            TlpType::ConfType1ReadReq => "Type 1 Config Read Request",
126            TlpType::ConfType1WriteReq => "Type 1 Config Write Request",
127            TlpType::MsgReq => "Message Request",
128            TlpType::MsgReqData => "Message with Data Request",
129            TlpType::Cpl => "Completion",
130            TlpType::CplData => "Completion with Data",
131            TlpType::CplLocked => "Locked Completion",
132            TlpType::CplDataLocked => "Locked Completion with Data",
133            TlpType::FetchAddAtomicOpReq => "Fetch Add Atomic Op Request",
134            TlpType::SwapAtomicOpReq => "Swap Atomic Op Request",
135            TlpType::CompareSwapAtomicOpReq => "Compare Swap Atomic Op Request",
136            TlpType::LocalTlpPrefix => "Local Tlp Prefix",
137            TlpType::EndToEndTlpPrefix => "End To End Tlp Prefix",
138        };
139        write!(fmt, "{}", name)
140    }
141}
142
143bitfield! {
144        struct TlpHeader(MSB0 [u8]);
145        u32;
146        get_format, _: 2, 0;
147        get_type,   _: 7, 3;
148        get_t9,     _: 8, 8;
149        get_tc,     _: 11, 9;
150        get_t8,     _: 12, 12;
151        get_attr_b2, _: 13, 13;
152        get_ln,     _: 14, 14;
153        get_th,     _: 15, 15;
154        get_td,     _: 16, 16;
155        get_ep,     _: 17, 17;
156        get_attr,   _: 19, 18;
157        get_at,     _: 21, 20;
158        get_length, _: 31, 22;
159}
160
161impl<T: AsRef<[u8]>> TlpHeader<T> {
162
163    fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
164        let tlp_type = self.get_type();
165        let tlp_fmt = self.get_format();
166
167        match TlpFormatEncodingType::try_from(tlp_type) {
168            Ok(TlpFormatEncodingType::MemoryRequest) => {
169                match TlpFmt::try_from(tlp_fmt) {
170                    Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::MemReadReq),
171                    Ok(TlpFmt::NoDataHeader4DW) => Ok(TlpType::MemReadReq),
172                    Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::MemWriteReq),
173                    Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::MemWriteReq),
174					Ok(_) => Err(TlpError::UnsupportedCombination),
175					Err(e) => Err(e),
176                }
177            }
178            Ok(TlpFormatEncodingType::MemoryLockRequest) => {
179                match TlpFmt::try_from(tlp_fmt) {
180                    Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::MemReadLockReq),
181                    Ok(TlpFmt::NoDataHeader4DW) => Ok(TlpType::MemReadLockReq),
182					Ok(_) => Err(TlpError::UnsupportedCombination),
183					Err(e) => Err(e),
184                }
185            }
186			Ok(TlpFormatEncodingType::IORequest) => {
187				match TlpFmt::try_from(tlp_fmt) {
188					Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::IOReadReq),
189					Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::IOWriteReq),
190					Ok(_) => Err(TlpError::UnsupportedCombination),
191					Err(e) => Err(e),
192				}
193			}
194			Ok(TlpFormatEncodingType::ConfigType0Request) => {
195				match TlpFmt::try_from(tlp_fmt) {
196					Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::ConfType0ReadReq),
197					Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::ConfType0WriteReq),
198					Ok(_) => Err(TlpError::UnsupportedCombination),
199					Err(e) => Err(e),
200				}
201			}
202            Ok(TlpFormatEncodingType::ConfigType1Request) => {
203                    match TlpFmt::try_from(tlp_fmt) {
204                            Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::ConfType1ReadReq),
205                            Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::ConfType1WriteReq),
206                            Ok(_) => Err(TlpError::UnsupportedCombination),
207							Err(e) => Err(e),
208                    }
209            }
210			Ok(TlpFormatEncodingType::Completion) => {
211				match TlpFmt::try_from(tlp_fmt) {
212					Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::Cpl),
213					Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CplData),
214					Ok(_) => Err(TlpError::UnsupportedCombination),
215					Err(e) => Err(e),
216				}
217			}
218			Ok(TlpFormatEncodingType::CompletionLocked) => {
219				match TlpFmt::try_from(tlp_fmt) {
220					Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::CplLocked),
221					Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CplDataLocked),
222					Ok(_) => Err(TlpError::UnsupportedCombination),
223					Err(e) => Err(e),
224				}
225			}
226			Ok(TlpFormatEncodingType::FetchAtomicOpRequest) => {
227				match TlpFmt::try_from(tlp_fmt) {
228					Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::FetchAddAtomicOpReq),
229					Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::FetchAddAtomicOpReq),
230					Ok(_) => Err(TlpError::UnsupportedCombination),
231					Err(e) => Err(e),
232				}
233			}
234			Ok(TlpFormatEncodingType::UnconSwapAtomicOpRequest) => {
235				match TlpFmt::try_from(tlp_fmt) {
236					Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::SwapAtomicOpReq),
237					Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::SwapAtomicOpReq),
238					Ok(_) => Err(TlpError::UnsupportedCombination),
239					Err(e) => Err(e),
240				}
241			}
242			Ok(TlpFormatEncodingType::CompSwapAtomicOpRequest) => {
243				match TlpFmt::try_from(tlp_fmt) {
244					Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CompareSwapAtomicOpReq),
245					Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::CompareSwapAtomicOpReq),
246					Ok(_) => Err(TlpError::UnsupportedCombination),
247					Err(e) => Err(e),
248				}
249			}
250			Err(e) => Err(e)
251        }
252    }
253}
254
255/// Memory Request Trait:
256/// Applies to 32 and 64 bits requests as well as legacy IO-Request
257/// (Legacy IO Request has the same structure as MemRead3DW)
258/// Software using the library may want to use trait instead of bitfield structures
259/// Both 3DW (32-bit) and 4DW (64-bit) headers implement this trait
260/// 3DW header is also used for all Legacy IO Requests.
261pub trait MemRequest {
262    fn address(&self) -> u64;
263    fn req_id(&self) -> u16;
264    fn tag(&self) -> u8;
265    fn ldwbe(&self) -> u8;
266    fn fdwbe(&self) -> u8;
267}
268
269// Structure for both 3DW Memory Request as well as Legacy IO Request
270bitfield! {
271    pub struct MemRequest3DW(MSB0 [u8]);
272    u32;
273    pub get_requester_id,   _: 15, 0;
274    pub get_tag,            _: 23, 16;
275    pub get_last_dw_be,     _: 27, 24;
276    pub get_first_dw_be,    _: 31, 28;
277    pub get_address32,      _: 63, 32;
278}
279
280bitfield! {
281    pub struct MemRequest4DW(MSB0 [u8]);
282    u64;
283    pub get_requester_id,   _: 15, 0;
284    pub get_tag,            _: 23, 16;
285    pub get_last_dw_be,     _: 27, 24;
286    pub get_first_dw_be,    _: 31, 28;
287    pub get_address64,      _: 95, 32;
288}
289
290impl <T: AsRef<[u8]>> MemRequest for MemRequest3DW<T> {
291    fn address(&self) -> u64 {
292        self.get_address32().into()
293    }
294    fn req_id(&self) -> u16 {
295        self.get_requester_id() as u16
296    }
297    fn tag(&self) -> u8 {
298        self.get_tag() as u8
299    }
300    fn ldwbe(&self) -> u8 {
301        self.get_last_dw_be() as u8
302    }
303    fn fdwbe(&self) -> u8 {
304        self.get_first_dw_be() as u8
305    }
306}
307
308impl <T: AsRef<[u8]>> MemRequest for MemRequest4DW<T> {
309    fn address(&self) -> u64 {
310        self.get_address64()
311    }
312    fn req_id(&self) -> u16 {
313        self.get_requester_id() as u16
314    }
315    fn tag(&self) -> u8 {
316        self.get_tag() as u8
317    }
318    fn ldwbe(&self) -> u8 {
319        self.get_last_dw_be() as u8
320    }
321    fn fdwbe(&self) -> u8 {
322        self.get_first_dw_be() as u8
323    }
324}
325
326/// Obtain Memory Request trait from bytes in vector as dyn
327/// This is preffered way of dealing with TLP headers as exact format (32/64 bits) is not required
328///
329/// # Examples
330///
331/// ```
332/// use std::convert::TryFrom;
333///
334/// use rtlp_lib::TlpPacket;
335/// use rtlp_lib::TlpFmt;
336/// use rtlp_lib::MemRequest;
337/// use rtlp_lib::new_mem_req;
338///
339/// let bytes = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
340/// let tlp = TlpPacket::new(bytes);
341///
342/// if let Ok(tlpfmt) = TlpFmt::try_from(tlp.get_tlp_format()) {
343///     // MemRequest contain only fields specific to PCI Memory Requests
344///     let mem_req: Box<dyn MemRequest> = new_mem_req(tlp.get_data(), &tlpfmt);
345///
346///     // Address is 64 bits regardles of TLP format
347///     //println!("Memory Request Address: {:x}", mem_req.address());
348///
349///     // Format of TLP (3DW vs 4DW) is stored in the TLP header
350///     println!("This TLP size is: {}", tlpfmt);
351///     // Type LegacyIO vs MemRead vs MemWrite is stored in first DW of TLP
352///     println!("This TLP type is: {:?}", tlp.get_tlp_type());
353/// }
354/// ```
355pub fn new_mem_req(bytes: Vec<u8>, format: &TlpFmt) -> Box<dyn MemRequest> {
356    match format {
357        TlpFmt::NoDataHeader3DW => Box::new(MemRequest3DW(bytes)),
358        TlpFmt::NoDataHeader4DW => Box::new(MemRequest4DW(bytes)),
359        TlpFmt::WithDataHeader3DW => Box::new(MemRequest3DW(bytes)),
360        TlpFmt::WithDataHeader4DW => Box::new(MemRequest4DW(bytes)),
361        TlpFmt::TlpPrefix => Box::new(MemRequest3DW(bytes)),
362    }
363}
364
365/// Configuration Request Trait:
366/// Configuration Requests Headers are always same size (3DW),
367/// this trait is provided to have same API as other headers with variable size
368pub trait ConfigurationRequest {
369    fn req_id(&self) -> u16;
370    fn tag(&self) -> u8;
371    fn bus_nr(&self) -> u8;
372    fn dev_nr(&self) -> u8;
373    fn func_nr(&self) -> u8;
374    fn ext_reg_nr(&self) -> u8;
375    fn reg_nr(&self) -> u8;
376}
377
378/// Obtain Configuration Request trait from bytes in vector as dyn
379///
380/// # Examples
381///
382/// ```
383/// use std::convert::TryFrom;
384///
385/// use rtlp_lib::TlpPacket;
386/// use rtlp_lib::TlpFmt;
387/// use rtlp_lib::ConfigurationRequest;
388/// use rtlp_lib::new_conf_req;
389///
390/// let bytes = vec![0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
391/// let tlp = TlpPacket::new(bytes);
392///
393/// if let Ok(tlpfmt) = TlpFmt::try_from(tlp.get_tlp_format()) {
394///     let config_req: Box<dyn ConfigurationRequest> = new_conf_req(tlp.get_data(), &tlpfmt);
395///
396///     //println!("Configuration Request Bus: {:x}", config_req.bus_nr());
397/// }
398/// ```
399pub fn new_conf_req(bytes: Vec<u8>, _format: &TlpFmt) -> Box<dyn ConfigurationRequest> {
400	Box::new(ConfigRequest(bytes))
401}
402
403bitfield! {
404    pub struct ConfigRequest(MSB0 [u8]);
405    u32;
406    pub get_requester_id,   _: 15, 0;
407    pub get_tag,            _: 23, 16;
408    pub get_last_dw_be,     _: 27, 24;
409    pub get_first_dw_be,    _: 31, 28;
410    pub get_bus_nr,         _: 39, 32;
411    pub get_dev_nr,         _: 44, 40;
412    pub get_func_nr,        _: 47, 45;
413    pub rsvd,               _: 51, 48;
414    pub get_ext_reg_nr,     _: 55, 52;
415    pub get_register_nr,    _: 61, 56;
416    r,                      _: 63, 62;
417}
418
419impl <T: AsRef<[u8]>> ConfigurationRequest for ConfigRequest<T> {
420    fn req_id(&self) -> u16 {
421        self.get_requester_id() as u16
422    }
423    fn tag(&self) -> u8 {
424        self.get_tag() as u8
425    }
426    fn bus_nr(&self) -> u8 {
427        self.get_bus_nr() as u8
428    }
429    fn dev_nr(&self) -> u8 {
430        self.get_dev_nr() as u8
431    }
432    fn func_nr(&self) -> u8 {
433        self.get_func_nr() as u8
434    }
435    fn ext_reg_nr(&self) -> u8 {
436        self.get_ext_reg_nr() as u8
437    }
438    fn reg_nr(&self) -> u8 {
439        self.get_register_nr() as u8
440    }
441}
442
443/// Completion Request Trait
444/// Completions are always 3DW (for with data (fmt = b010) and without data (fmt = b000) )
445/// This trait is provided to have same API as other headers with variable size
446/// To obtain this trait `new_cmpl_req()` function has to be used
447/// Trait release user from dealing with bitfield structures.
448pub trait CompletionRequest {
449    fn cmpl_id(&self) -> u16;
450    fn cmpl_stat(&self) -> u8;
451    fn bcm(&self) -> u8;
452    fn byte_cnt(&self) -> u16;
453    fn req_id(&self) -> u16;
454    fn tag(&self) -> u8;
455    fn laddr(&self) -> u8;
456}
457
458bitfield! {
459    pub struct CompletionReqDW23(MSB0 [u8]);
460    u16;
461    pub get_completer_id,   _: 15, 0;
462    pub get_cmpl_stat,      _: 18, 16;
463    pub get_bcm,            _: 19, 19;
464    pub get_byte_cnt,       _: 31, 20;
465    pub get_req_id,         _: 47, 32;
466    pub get_tag,            _: 55, 48;
467    r,                      _: 57, 56;
468    pub get_laddr,          _: 63, 58;
469}
470
471impl <T: AsRef<[u8]>> CompletionRequest for CompletionReqDW23<T> {
472    fn cmpl_id(&self) -> u16 {
473        self.get_completer_id()
474    }
475    fn cmpl_stat(&self) -> u8 {
476        self.get_cmpl_stat() as u8
477    }
478    fn bcm(&self) -> u8 {
479        self.get_bcm() as u8
480    }
481    fn byte_cnt(&self) -> u16 {
482        self.get_byte_cnt()
483    }
484    fn req_id(&self) -> u16 {
485        self.get_req_id()
486    }
487    fn tag(&self) -> u8 {
488        self.get_tag() as u8
489    }
490    fn laddr(&self) -> u8 {
491        self.get_laddr() as u8
492    }
493}
494
495/// Obtain Completion Request dyn Trait:
496///
497/// # Examples
498///
499/// ```
500/// use rtlp_lib::TlpFmt;
501/// use rtlp_lib::CompletionRequest;
502/// use rtlp_lib::new_cmpl_req;
503///
504/// let bytes = vec![0x20, 0x01, 0xFF, 0xC2, 0x00, 0x00, 0x00, 0x00];
505/// // TLP Format usually comes from TlpPacket or Header here we made up one for example
506/// let tlpfmt = TlpFmt::WithDataHeader4DW;
507///
508/// let cmpl_req: Box<dyn CompletionRequest> = new_cmpl_req(bytes, &tlpfmt);
509///
510/// println!("Requester ID from Completion{}", cmpl_req.req_id());
511/// ```
512pub fn new_cmpl_req(bytes: Vec<u8>, _format: &TlpFmt) -> Box<dyn CompletionRequest> {
513	Box::new(CompletionReqDW23(bytes))
514}
515
516/// Message Request trait
517/// Provide method to access fields in DW2-4 header is handled by TlpHeader
518pub trait MessageRequest {
519    fn req_id(&self) -> u16;
520    fn tag(&self) -> u8;
521	fn msg_code(&self) -> u8;
522	/// DW3-4 vary with Message Code Field
523    fn dw3(&self) -> u32;
524    fn dw4(&self) -> u32;
525}
526
527bitfield! {
528    pub struct MessageReqDW24(MSB0 [u8]);
529    u16;
530    pub get_requester_id,   _: 15, 0;
531    pub get_tag,            _: 23, 16;
532    pub get_msg_code,       _: 31, 24;
533    pub get_dw3,            _: 63, 32;
534    pub get_dw4,            _: 96, 64;
535}
536
537impl <T: AsRef<[u8]>> MessageRequest for MessageReqDW24<T> {
538    fn req_id(&self) -> u16 {
539        self.get_requester_id()
540    }
541    fn tag(&self) -> u8 {
542        self.get_tag() as u8
543    }
544    fn msg_code(&self) -> u8 {
545        self.get_msg_code() as u8
546    }
547    fn dw3(&self) -> u32 {
548        self.get_dw3() as u32
549    }
550    fn dw4(&self) -> u32 {
551        self.get_dw4() as u32
552    }
553    // TODO: implement routedby method based on type
554}
555
556/// Obtain Message Request dyn Trait:
557///
558/// # Examples
559///
560/// ```
561/// use rtlp_lib::TlpFmt;
562/// use rtlp_lib::MessageRequest;
563/// use rtlp_lib::new_msg_req;
564///
565/// let bytes = vec![0x20, 0x01, 0xFF, 0xC2, 0x00, 0x00, 0x00, 0x00];
566/// let tlpfmt = TlpFmt::NoDataHeader3DW;
567///
568/// let msg_req: Box<dyn MessageRequest> = new_msg_req(bytes, &tlpfmt);
569///
570/// println!("Requester ID from Message{}", msg_req.req_id());
571/// ```
572pub fn new_msg_req(bytes: Vec<u8>, _format: &TlpFmt) -> Box<dyn MessageRequest> {
573	Box::new(MessageReqDW24(bytes))
574}
575
576/// TLP Packet Header
577/// Contains bytes for Packet header and informations about TLP type
578pub struct TlpPacketHeader {
579    header: TlpHeader<Vec<u8>>,
580}
581
582impl TlpPacketHeader {
583    pub fn new(bytes: Vec<u8>) -> TlpPacketHeader {
584        let mut dw0 = vec![0; 4];
585        dw0[..4].clone_from_slice(&bytes[0..4]);
586
587        TlpPacketHeader { header: TlpHeader(dw0) }
588    }
589
590    pub fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
591        self.header.get_tlp_type()
592    }
593
594    pub fn get_format(&self) -> u32 {self.header.get_format()}
595    pub fn get_type(&self) -> u32 {self.header.get_type()}
596    pub fn get_t9(&self) -> u32 {self.header.get_t9()}
597    pub fn get_tc(&self) -> u32 {self.header.get_tc()}
598    pub fn get_t8(&self) -> u32 {self.header.get_t8()}
599    pub fn get_attr_b2(&self) -> u32 {self.header.get_attr_b2()}
600    pub fn get_ln(&self) -> u32 {self.header.get_ln()}
601    pub fn get_th(&self) -> u32 {self.header.get_th()}
602    pub fn get_td(&self) -> u32 {self.header.get_td()}
603    pub fn get_ep(&self) -> u32 {self.header.get_ep()}
604    pub fn get_attr(&self) -> u32 {self.header.get_attr()}
605    pub fn get_at(&self) -> u32 {self.header.get_at()}
606    pub fn get_length(&self) -> u32 {self.header.get_length()}
607
608}
609
610/// TLP Packet structure is high level abstraction for entire TLP packet
611/// Contains Header and Data
612///
613/// # Examples
614///
615/// ```
616/// use rtlp_lib::TlpPacket;
617/// use rtlp_lib::TlpFmt;
618/// use rtlp_lib::TlpType;
619/// use rtlp_lib::new_msg_req;
620/// use rtlp_lib::new_conf_req;
621/// use rtlp_lib::new_mem_req;
622/// use rtlp_lib::new_cmpl_req;
623///
624/// // Bytes for full TLP Packet
625/// //               <------- DW1 -------->  <------- DW2 -------->  <------- DW3 -------->  <------- DW4 -------->
626/// let bytes = vec![0x00, 0x00, 0x20, 0x01, 0x04, 0x00, 0x00, 0x01, 0x20, 0x01, 0xFF, 0x00, 0xC2, 0x81, 0xFF, 0x10];
627/// let packet = TlpPacket::new(bytes);
628///
629/// let header = packet.get_header();
630/// // TLP Type tells us what is this packet
631/// let tlp_type = header.get_tlp_type().unwrap();
632/// let tlp_format = packet.get_tlp_format();
633/// let requester_id;
634/// match (tlp_type) {
635///      TlpType::MemReadReq |
636///      TlpType::MemReadLockReq |
637///      TlpType::MemWriteReq |
638///      TlpType::IOReadReq |
639///      TlpType::IOWriteReq |
640///      TlpType::FetchAddAtomicOpReq |
641///      TlpType::SwapAtomicOpReq |
642///      TlpType::CompareSwapAtomicOpReq => requester_id = new_mem_req(packet.get_data(), &tlp_format).req_id(),
643///      TlpType::ConfType0ReadReq |
644///      TlpType::ConfType0WriteReq |
645///      TlpType::ConfType1ReadReq |
646///      TlpType::ConfType1WriteReq => requester_id = new_conf_req(packet.get_data(), &tlp_format).req_id(),
647///      TlpType::MsgReq |
648///      TlpType::MsgReqData => requester_id = new_msg_req(packet.get_data(), &tlp_format).req_id(),
649///      TlpType::Cpl |
650///      TlpType::CplData |
651///      TlpType::CplLocked |
652///      TlpType::CplDataLocked => requester_id = new_cmpl_req(packet.get_data(), &tlp_format).req_id(),
653///      TlpType::LocalTlpPrefix |
654///      TlpType::EndToEndTlpPrefix => println!("I need to implement TLP Type: {:?}", tlp_type),
655/// }
656/// ```
657pub struct TlpPacket {
658    header: TlpPacketHeader,
659    data: Vec<u8>,
660}
661
662impl TlpPacket {
663    pub fn new(bytes: Vec<u8>) -> TlpPacket {
664        let mut ownbytes = bytes.to_vec();
665        let mut header = vec![0; 4];
666        header.clone_from_slice(&ownbytes[0..4]);
667        let data = ownbytes.drain(4..).collect();
668        TlpPacket {
669            header: TlpPacketHeader::new(header),
670            data,
671        }
672    }
673
674    pub fn get_header(&self) -> &TlpPacketHeader {
675        &self.header
676    }
677
678    pub fn get_data(&self) -> Vec<u8> {
679        self.data.to_vec()
680    }
681
682    pub fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
683        self.header.get_tlp_type()
684    }
685
686    pub fn get_tlp_format(&self) -> TlpFmt {
687        let fmt : TlpFmt = TlpFmt::try_from(self.header.get_format()).unwrap();
688
689        fmt
690    }
691}
692
693
694#[cfg(test)]
695mod tests {
696    use super::*;
697
698    #[test]
699    fn test_tlp_packet() {
700        let d = vec![0x04, 0x00, 0x00, 0x01, 0x20, 0x01, 0xFF, 0x00, 0xC2, 0x81, 0xFF, 0x10];
701        let tlp = TlpPacket::new(d);
702
703        assert_eq!(tlp.get_tlp_type().unwrap(), TlpType::ConfType0ReadReq);
704        assert_eq!(tlp.get_data(), vec![0x20, 0x01, 0xFF, 0x00, 0xC2, 0x81, 0xFF, 0x10]);
705    }
706
707    #[test]
708    fn test_complreq_trait() {
709		let cmpl_req = CompletionReqDW23([0x20, 0x01, 0xFF, 0x00, 0xC2, 0x81, 0xFF, 0x10]);
710
711        assert_eq!(0x2001, cmpl_req.cmpl_id());
712        assert_eq!(0x7, cmpl_req.cmpl_stat());
713        assert_eq!(0x1, cmpl_req.bcm());
714        assert_eq!(0xF00, cmpl_req.byte_cnt());
715        assert_eq!(0xC281, cmpl_req.req_id());
716        assert_eq!(0xFF, cmpl_req.tag());
717        assert_eq!(0x10, cmpl_req.laddr());
718    }
719
720    #[test]
721    fn test_configreq_trait() {
722		let conf_req = ConfigRequest([0x20, 0x01, 0xFF, 0x00, 0xC2, 0x81, 0xFF, 0x10]);
723
724        assert_eq!(0x2001, conf_req.req_id());
725        assert_eq!(0xFF, conf_req.tag());
726        assert_eq!(0xC2, conf_req.bus_nr());
727        assert_eq!(0x10, conf_req.dev_nr());
728        assert_eq!(0x01, conf_req.func_nr());
729        assert_eq!(0x0F, conf_req.ext_reg_nr());
730        assert_eq!(0x04, conf_req.reg_nr());
731    }
732
733    #[test]
734    fn is_memreq_tag_works() {
735        let mr3dw1 = MemRequest3DW([0x00, 0x00, 0x20, 0x0F, 0xF6, 0x20, 0x00, 0x0C]);
736        let mr3dw2 = MemRequest3DW([0x00, 0x00, 0x01, 0x0F, 0xF6, 0x20, 0x00, 0x0C]);
737        let mr3dw3 = MemRequest3DW([0x00, 0x00, 0x10, 0x0F, 0xF6, 0x20, 0x00, 0x0C]);
738        let mr3dw4 = MemRequest3DW([0x00, 0x00, 0x81, 0x0F, 0xF6, 0x20, 0x00, 0x0C]);
739
740        assert_eq!(0x20, mr3dw1.tag());
741        assert_eq!(0x01, mr3dw2.tag());
742        assert_eq!(0x10, mr3dw3.tag());
743        assert_eq!(0x81, mr3dw4.tag());
744
745        let mr4dw1 = MemRequest4DW([0x00, 0x00, 0x01, 0x0F, 0x00, 0x00, 0x01, 0x7f, 0xc0, 0x00, 0x00, 0x00]);
746        let mr4dw2 = MemRequest4DW([0x00, 0x00, 0x10, 0x0F, 0x00, 0x00, 0x01, 0x7f, 0xc0, 0x00, 0x00, 0x00]);
747        let mr4dw3 = MemRequest4DW([0x00, 0x00, 0x81, 0x0F, 0x00, 0x00, 0x01, 0x7f, 0xc0, 0x00, 0x00, 0x00]);
748        let mr4dw4 = MemRequest4DW([0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x01, 0x7f, 0xc0, 0x00, 0x00, 0x00]);
749        let mr4dw5 = MemRequest4DW([0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0x7f, 0xc0, 0x00, 0x00, 0x00]);
750
751        assert_eq!(0x01, mr4dw1.tag());
752        assert_eq!(0x10, mr4dw2.tag());
753        assert_eq!(0x81, mr4dw3.tag());
754        assert_eq!(0xFF, mr4dw4.tag());
755        assert_eq!(0x00, mr4dw5.tag());
756    }
757
758    #[test]
759    fn is_memreq_3dw_address_works() {
760        let memreq_3dw = [0x00, 0x00, 0x20, 0x0F, 0xF6, 0x20, 0x00, 0x0C];
761        let mr = MemRequest3DW(memreq_3dw);
762
763        assert_eq!(0xF620000C, mr.address());
764    }
765
766    #[test]
767    fn is_memreq_4dw_address_works() {
768        let memreq_4dw = [0x00, 0x00, 0x20, 0x0F, 0x00, 0x00, 0x01, 0x7f, 0xc0, 0x00, 0x00, 0x00];
769        let mr = MemRequest4DW(memreq_4dw);
770
771        assert_eq!(0x17fc0000000, mr.address());
772    }
773
774    #[test]
775    fn is_tlppacket_creates() {
776        let memrd32_header = [0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x20, 0x0F, 0xF6, 0x20, 0x00, 0x0C];
777
778        let mr = TlpPacketHeader::new(memrd32_header.to_vec());
779        assert_eq!(mr.get_tlp_type().unwrap(), TlpType::MemReadReq);
780    }
781
782    #[test]
783    fn tlp_header_type() {
784		// Empty packet is still MemREAD: FMT '000' Type '0 0000' Length 0
785        let memread = TlpHeader([0x0, 0x0, 0x0, 0x0]);
786        assert_eq!(memread.get_tlp_type().unwrap(), TlpType::MemReadReq);
787
788		// MemRead32 FMT '000' Type '0 0000'
789		let memread32 = TlpHeader([0x00, 0x00, 0x20, 0x01]);
790		assert_eq!(memread32.get_tlp_type().unwrap(), TlpType::MemReadReq);
791
792		// MemWrite32 FMT '010' Type '0 0000'
793		let memwrite32 = TlpHeader([0x40, 0x00, 0x00, 0x01]);
794		assert_eq!(memwrite32.get_tlp_type().unwrap(), TlpType::MemWriteReq);
795
796		// CPL without Data: FMT '000' Type '0 1010'
797		let cpl_no_data = TlpHeader([0x0a, 0x00, 0x10, 0x00]);
798		assert_eq!(cpl_no_data.get_tlp_type().unwrap(), TlpType::Cpl);
799
800		// CPL with Data: FMT '010' Type '0 1010'
801		let cpl_with_data = TlpHeader([0x4a, 0x00, 0x20, 0x40]);
802		assert_eq!(cpl_with_data.get_tlp_type().unwrap(), TlpType::CplData);
803
804		// MemRead 4DW: FMT: '001' Type '0 0000'
805		let memread_4dw = TlpHeader([0x20, 0x00, 0x20, 0x40]);
806		assert_eq!(memread_4dw.get_tlp_type().unwrap(), TlpType::MemReadReq);
807
808		// Config Type 0 Read request: FMT: '000' Type '0 0100'
809		let conf_t0_read = TlpHeader([0x04, 0x00, 0x00, 0x01]);
810		assert_eq!(conf_t0_read.get_tlp_type().unwrap(), TlpType::ConfType0ReadReq);
811
812		// Config Type 0 Write request: FMT: '010' Type '0 0100'
813		let conf_t0_write = TlpHeader([0x44, 0x00, 0x00, 0x01]);
814		assert_eq!(conf_t0_write.get_tlp_type().unwrap(), TlpType::ConfType0WriteReq);
815
816        // Config Type 1 Read request: FMT: '000' Type '0 0101'
817        let conf_t1_read = TlpHeader([0x05, 0x88, 0x80, 0x01]);
818               assert_eq!(conf_t1_read.get_tlp_type().unwrap(), TlpType::ConfType1ReadReq);
819
820        // Config Type 1 Read request: FMT: '010' Type '0 0101'
821        let conf_t1_write = TlpHeader([0x45, 0x88, 0x80, 0x01]);
822               assert_eq!(conf_t1_write.get_tlp_type().unwrap(), TlpType::ConfType1WriteReq);
823
824        // HeaderLog: 04000001 0000220f 01070000 af36fc70
825        // HeaderLog: 60009001 4000000f 00000280 4047605c
826        let memwrite64 = TlpHeader([0x60, 0x00, 0x90, 0x01]);
827        assert_eq!(memwrite64.get_tlp_type().unwrap(), TlpType::MemWriteReq);
828    }
829
830    #[test]
831    fn tlp_header_works_all_zeros() {
832        let bits_locations = TlpHeader([0x0, 0x0, 0x0, 0x0]);
833
834        assert_eq!(bits_locations.get_format(), 0);
835        assert_eq!(bits_locations.get_type(), 0);
836        assert_eq!(bits_locations.get_t9(), 0);
837        assert_eq!(bits_locations.get_tc(), 0);
838        assert_eq!(bits_locations.get_t8(), 0);
839        assert_eq!(bits_locations.get_attr_b2(), 0);
840        assert_eq!(bits_locations.get_ln(), 0);
841        assert_eq!(bits_locations.get_th(), 0);
842        assert_eq!(bits_locations.get_td(), 0);
843        assert_eq!(bits_locations.get_ep(), 0);
844        assert_eq!(bits_locations.get_attr(), 0);
845        assert_eq!(bits_locations.get_at(), 0);
846        assert_eq!(bits_locations.get_length(), 0);
847    }
848
849    #[test]
850    fn tlp_header_works_all_ones() {
851        let bits_locations = TlpHeader([0xff, 0xff, 0xff, 0xff]);
852
853        assert_eq!(bits_locations.get_format(), 0x7);
854        assert_eq!(bits_locations.get_type(), 0x1f);
855        assert_eq!(bits_locations.get_t9(), 0x1);
856        assert_eq!(bits_locations.get_tc(), 0x7);
857        assert_eq!(bits_locations.get_t8(), 0x1);
858        assert_eq!(bits_locations.get_attr_b2(), 0x1);
859        assert_eq!(bits_locations.get_ln(), 0x1);
860        assert_eq!(bits_locations.get_th(), 0x1);
861        assert_eq!(bits_locations.get_td(), 0x1);
862        assert_eq!(bits_locations.get_ep(), 0x1);
863        assert_eq!(bits_locations.get_attr(), 0x3);
864        assert_eq!(bits_locations.get_at(), 0x3);
865        assert_eq!(bits_locations.get_length(), 0x3ff);
866    }
867
868    #[test]
869    fn test_invalid_format_error() {
870        // Format field with invalid value (e.g., 0b101 = 5)
871        let invalid_fmt = TlpHeader([0xa0, 0x00, 0x00, 0x01]); // FMT='101' Type='00000'
872        let result = invalid_fmt.get_tlp_type();
873        assert!(result.is_err());
874        assert_eq!(result.unwrap_err(), TlpError::InvalidFormat);
875    }
876
877    #[test]
878    fn test_invalid_type_error() {
879        // Type field with invalid encoding (e.g., 0b01111 = 15)
880        let invalid_type = TlpHeader([0x0f, 0x00, 0x00, 0x01]); // FMT='000' Type='01111'
881        let result = invalid_type.get_tlp_type();
882        assert!(result.is_err());
883        assert_eq!(result.unwrap_err(), TlpError::InvalidType);
884    }
885
886    #[test]
887    fn test_unsupported_combination_error() {
888        // Valid format and type but unsupported combination
889        // IO Request with 4DW header (not valid)
890        let invalid_combo = TlpHeader([0x22, 0x00, 0x00, 0x01]); // FMT='001' Type='00010' (IO Request 4DW)
891        let result = invalid_combo.get_tlp_type();
892        assert!(result.is_err());
893        assert_eq!(result.unwrap_err(), TlpError::UnsupportedCombination);
894    }
895
896    #[test]
897    fn test_tlp_packet_invalid_type() {
898        // Test that TlpPacket::get_tlp_type properly returns error
899        let invalid_data = vec![0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00];
900        let packet = TlpPacket::new(invalid_data);
901        let result = packet.get_tlp_type();
902        assert!(result.is_err());
903        assert_eq!(result.unwrap_err(), TlpError::InvalidType);
904    }
905}