xvc_client/
lib.rs

1//! # XVC Client
2//!
3//! A Rust client library for connecting to Xilinx Virtual Cable (XVC) servers
4//! and performing remote JTAG operations on FPGA devices.
5//!
6//! ## Overview
7//!
8//! This crate provides a high-level client interface to XVC servers, allowing applications
9//! to interact with FPGA debug interfaces over network connections. It handles protocol
10//! communication, message serialization, and provides convenient methods for JTAG operations.
11//!
12//! ## Protocol Support
13//!
14//! This implementation supports the XVC 1.0 protocol with the following operations:
15//!
16//! - **GetInfo**: Query server capabilities (version, max vector size)
17//! - **SetTck**: Configure the JTAG Test Clock (TCK) period
18//! - **Shift**: Perform JTAG vector shifting (TMS/TDI/TDO)
19//!
20//! For detailed protocol information, see the [`xvc_protocol`](https://docs.rs/xvc-protocol/) crate.
21//!
22//! ## Basic Usage
23//!
24//! ### Connecting to a Server
25//!
26//! ```ignore
27//! use xvc_client::XvcClient;
28//! use std::net::SocketAddr;
29//!
30//! let mut client = XvcClient::connect("127.0.0.1:2542")?;
31//!
32//! // Query server capabilities
33//! let info = client.get_info()?;
34//! println!("Server version: {}", info.version());
35//! println!("Max vector size: {} bytes", info.max_vector_size());
36//! ```
37//!
38//! ### Setting Clock Frequency
39//!
40//! ```ignore
41//! // Set TCK period to 10 nanoseconds
42//! let actual_period = client.set_tck(10)?;
43//! println!("Set TCK to {} ns", actual_period);
44//! ```
45//!
46//! ### Performing JTAG Shifts
47//!
48//! ```ignore
49//! // Perform a 8-bit JTAG shift
50//! let num_bits = 8;
51//! let tms = vec![0x00]; // Test Mode Select vector
52//! let tdi = vec![0xA5]; // Test Data In vector
53//!
54//! let tdo = client.shift(num_bits, tms, tdi)?;
55//! println!("TDO data: {:?}", tdo);
56//! ```
57//!
58//! ## Related Crates
59//!
60//! - [`xvc_server`](https://docs.rs/xvc-server/) - Server implementation
61//! - [`xvc_protocol`](https://docs.rs/xvc-protocol/) - Protocol encoding/decoding
62//! - [`xvc_server_linux`](https://docs.rs/xvc-server-debugbridge/) - Linux server drivers
63use std::{
64    io::{self, Read},
65    net::{TcpStream, ToSocketAddrs},
66};
67
68use xvc_protocol::{Message, XvcInfo, error::ReadError};
69
70/// XVC client for remote JTAG operations.
71///
72/// Connects to an XVC server and provides methods for JTAG operations.
73pub struct XvcClient {
74    tcp: TcpStream,
75}
76
77impl XvcClient {
78    pub fn new(addr: impl ToSocketAddrs) -> io::Result<XvcClient> {
79        Ok(XvcClient {
80            tcp: TcpStream::connect(addr)?,
81        })
82    }
83
84    /// Query server capabilities and version information.
85    pub fn get_info(&mut self) -> Result<XvcInfo, ReadError> {
86        Message::GetInfo.write_to(&mut self.tcp)?;
87        XvcInfo::from_reader(&mut self.tcp)
88    }
89
90    /// Set the JTAG Test Clock (TCK) period.
91    /// # Returns
92    ///
93    /// The actual TCK period set by the server.
94    // May differ from requested, if the server does not support the requested rate.
95    pub fn set_tck(&mut self, period_ns: u32) -> io::Result<u32> {
96        Message::SetTck { period_ns }.write_to(&mut self.tcp)?;
97        let mut buf = [0u8; 4];
98        self.tcp.read_exact(&mut buf)?;
99        Ok(u32::from_le_bytes(buf))
100    }
101
102    /// Perform a JTAG shift operation.
103    ///
104    /// # Arguments
105    ///
106    /// * `num_bits` - Number of bits to shift
107    /// * `tms` - Test Mode Select vector (length must be ⌈num_bits / 8⌉)
108    /// * `tdi` - Test Data In vector (length must be ⌈num_bits / 8⌉)
109    ///
110    /// # Returns
111    ///
112    /// Test Data Out vector from the JTAG chain of the same length as `tms` and `tdi`.
113    pub fn shift(&mut self, num_bits: u32, tms: &[u8], tdi: &[u8]) -> io::Result<Box<[u8]>> {
114        Message::Shift {
115            num_bits,
116            tms: tms.into(),
117            tdi: tdi.into(),
118        }
119        .write_to(&mut self.tcp)?;
120        let mut buf = vec![0; num_bits.div_ceil(8) as usize];
121        self.tcp.read_exact(&mut buf)?;
122        Ok(buf.into_boxed_slice())
123    }
124}