Skip to main content

xvc_protocol/
protocol.rs

1use std::{fmt::Display, str::FromStr};
2
3use crate::error::ParseVersionError;
4
5/// The version of the protocol.
6/// A version always consists of a major and a minor part.
7#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
8pub struct Version {
9    major: usize,
10    minor: usize,
11}
12
13impl Version {
14    /// Version 1.0 of the protocol
15    pub const V1_0: Version = Version { major: 1, minor: 0 };
16
17    /// Create a new version from major and minor components
18    pub fn new(major: usize, minor: usize) -> Version {
19        Version { major, minor }
20    }
21
22    /// Returns the latest supported version
23    pub const fn latest() -> Version {
24        Version::V1_0
25    }
26
27    /// The major part of the version
28    pub fn major(&self) -> usize {
29        self.major
30    }
31
32    /// The minor part of the version
33    pub fn minor(&self) -> usize {
34        self.minor
35    }
36}
37
38#[test]
39fn version_ordering() {
40    assert!(Version { major: 1, minor: 0 } < Version { major: 1, minor: 1 });
41    assert!(Version { major: 2, minor: 0 } > Version { major: 1, minor: 0 });
42}
43
44impl Default for Version {
45    fn default() -> Self {
46        Self::V1_0
47    }
48}
49
50impl Display for Version {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        write!(f, "{}.{}", self.major, self.minor)
53    }
54}
55
56impl FromStr for Version {
57    type Err = ParseVersionError;
58
59    fn from_str(s: &str) -> Result<Self, Self::Err> {
60        let (major_part, minor_part) = s.split_once(".").ok_or(ParseVersionError::MissingDot)?;
61        let major: usize = major_part.parse::<usize>()?;
62        let minor: usize = minor_part.parse::<usize>()?;
63        Ok(Self { major, minor })
64    }
65}
66
67#[test]
68fn correct_version_from_str() {
69    assert_eq!(Version::from_str("1.0").unwrap(), Version::new(1, 0));
70    assert_eq!(Version::from_str("2.0").unwrap(), Version::new(2, 0));
71    assert_eq!(Version::from_str("2.20").unwrap(), Version::new(2, 20));
72}
73
74#[test]
75fn incorrect_version_from_str() {
76    assert!(matches!(
77        Version::from_str("1"),
78        Err(ParseVersionError::MissingDot)
79    ));
80    match Version::from_str("1.1.1") {
81        Err(ParseVersionError::ParseInt(_)) => {}
82        Ok(_) => panic!("'1.1.1' should not be a valid version"),
83        Err(_) => panic!("'1.1.1' should raise ParseIntError"),
84    }
85}
86
87/// A Message is transferred from the client to the server.
88/// For each message, the client is expected to send the message and wait for a response from the server.
89/// The server needs to process each message in the order received and promptly provide a response.
90/// For the XVC 1.0 protocol, only one connection is assumed.
91#[derive(Clone, Debug, Eq, PartialEq)]
92pub enum Message<B = Box<[u8]>> {
93    /// Requests info from the server. This is used to determine protocol capabilities of the server.
94    GetInfo,
95    /// Configures the TCK period. When sending JTAG vectors the TCK rate may need to be varied to accommodate cable and board signal integrity conditions.
96    /// This command is used by clients to adjust the TCK rate in order to slow down or speed up the shifting of JTAG vectors.
97    SetTck { period_ns: u32 },
98    /// Used to shift JTAG vectors in-and out of a device.
99    Shift {
100        /// represents the number of TCK clk toggles needed to shift the vectors out
101        num_bits: u32,
102        /// a byte sized vector with all the TMS data.
103        /// The vector is num_bits and rounds up to the nearest byte.
104        tms: B,
105        /// a byte sized vector with all the TDI data.
106        /// The vector is num_bits and rounds up to the nearest byte.
107        tdi: B,
108    },
109}
110
111pub type OwnedMessage = Message<Box<[u8]>>;
112pub type BorrowedMessage<'a> = Message<&'a [u8]>;
113
114/// Contains static information about the server capabilities that are transferred between
115/// client and server in the beginning.
116#[derive(Clone, Debug, Eq, PartialEq)]
117pub struct XvcInfo {
118    version: Version,
119    max_vector_len: u32,
120}
121
122impl XvcInfo {
123    /// Creates a new info object from version and the maximum receivable vector length.
124    pub fn new(version: Version, max_vector_len: u32) -> XvcInfo {
125        XvcInfo {
126            version,
127            max_vector_len,
128        }
129    }
130
131    /// The version of the protocol
132    pub fn version(&self) -> Version {
133        self.version
134    }
135
136    /// the max width of the vector that can be shifted into the server
137    pub fn max_vector_len(&self) -> u32 {
138        self.max_vector_len
139    }
140}
141
142impl Default for XvcInfo {
143    fn default() -> XvcInfo {
144        XvcInfo {
145            version: Version::default(),
146            max_vector_len: 10 * 1024 * 1024, // 10 MiB default
147        }
148    }
149}
150
151/// Possible commands that are known to the XVC protocol.
152#[derive(Eq, PartialEq, Clone, Debug)]
153pub enum XvcCommand {
154    GetInfo,
155    SetTck,
156    Shift,
157}