xvc_server/lib.rs
1//! # XVC Server Library
2//!
3//! This crate provides a foundation for implementing Xilinx Virtual Cable (XVC) servers
4//! that handle JTAG communication with FPGA devices over network connections.
5//!
6//! ## Overview
7//!
8//! XVC is a protocol used by Xilinx design tools to interact with FPGA devices remotely.
9//! This library abstracts the protocol handling and provides a server implementation that
10//! can work with different backend device drivers.
11//!
12//! ## Architecture
13//!
14//! The crate is built around two main components:
15//!
16//! - **[`XvcServer`] Trait**: Defines the interface that backend drivers must implement
17//! to handle low-level JTAG operations (TCK configuration and vector shifting)
18//! - **[`server::Server`]**: A generic server that handles XVC protocol communication,
19//! message parsing, and client connections
20//!
21//! ## How It Works
22//!
23//! 1. A backend driver (e.g., kernel driver, UIO device) implements the [`XvcServer`] trait
24//! 2. The driver is wrapped in a [`server::Server`] instance
25//! 3. The server listens for TCP connections and processes XVC protocol messages
26//! 4. Each message is dispatched to the backend driver for actual JTAG operations
27//! 5. Results are serialized and sent back to the client
28//!
29//! ## Protocol Support
30//!
31//! This implementation supports the XVC 1.0 protocol with the following operations:
32//!
33//! - **GetInfo**: Query server capabilities (version, max vector size)
34//! - **SetTck**: Configure the JTAG Test Clock (TCK) period
35//! - **Shift**: Perform JTAG vector shifting (TMS/TDI/TDO)
36//!
37//! For detailed protocol information, see the [`xvc_protocol`](https://docs.rs/xvc-protocol/) crate.
38//!
39//! ## Basic Usage
40//!
41//! ### Implementing a Backend Driver
42//!
43//! Create a struct that implements the [`XvcServer`] trait:
44//!
45//! ```no_run
46//! use xvc_server::XvcServer;
47//!
48//! struct MyDriver {
49//! // device-specific fields
50//! }
51//!
52//! impl XvcServer for MyDriver {
53//! fn set_tck(&self, period_ns: u32) -> u32 {
54//! // Configure hardware TCK period
55//! period_ns
56//! }
57//!
58//! fn shift(&self, num_bits: u32, tms: &[u8], tdi: &[u8]) -> Box<[u8]> {
59//! // Perform JTAG shifting and return TDO data
60//! Box::default()
61//! }
62//! }
63//! ```
64//!
65//! ### Starting the Server
66//!
67//! ```ignore
68//! use xvc_server::server::{Server, Config};
69//! use std::net::{IpAddr, Ipv4Addr, SocketAddr};
70//!
71//! let driver = MyDriver::new()?;
72//! let config = Config::default();
73//! let server = Server::new(driver, config);
74//!
75//! let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 2542);
76//! server.listen(addr).await?;
77//! ```
78//!
79//! ## Error Handling
80//!
81//! The XVC 1.0 protocol specification does not support error reporting in the Shift operation.
82//! If a shift operation fails, an empty result is returned to the client.
83//! For other operations, standard I/O errors are propagated as appropriate.
84//!
85//! ## Configuration
86//!
87//! Server behavior can be customized via [`server::Config`]:
88//!
89//! - **max_vector_size**: Maximum size of JTAG vectors (default: 10 MiB)
90//! - **read_write_timeout**: Socket I/O timeout duration (default: 30 seconds)
91//!
92//! ## Logging
93//!
94//! This crate uses the `log` crate for diagnostics. Enable logging to see:
95//! - Client connections and disconnections
96//! - Protocol messages being processed
97//! - Configuration details and error conditions
98//!
99//! Configure logging with an implementation like `env_logger`:
100//!
101//! ```ignore
102//! env_logger::init();
103//! ```
104//!
105//! ## Thread Model
106//!
107//! The server is async (tokio) and accepts connections concurrently, but enforces
108//! **at-most-one active client** at a time. A second connection attempt while a client
109//! is active is immediately rejected. This matches the XVC protocol assumption of a
110//! single JTAG session and prevents interleaved access to the hardware state machine.
111//!
112//! Backend methods (`set_tck`, `shift`) are called via `block_in_place`, so the server
113//! requires a multi-thread tokio runtime.
114pub mod server;
115
116/// Trait that backend drivers must implement to provide JTAG functionality.
117///
118/// This trait defines the interface between the XVC protocol server and the actual
119/// hardware debug bridge driver. Implementors are responsible for translating
120/// high-level JTAG operations into hardware-specific commands.
121///
122/// See the [`xvc-server-debugbridge`](https://docs.rs/xvc-server-debugbridge/) crate for examples.
123pub trait XvcServer {
124 /// Set the TCK (Test Clock) period.
125 ///
126 /// Configures the frequency of the JTAG Test Clock (TCK). The server attempts to set
127 /// the requested period. If the hardware cannot achieve the exact period, it returns
128 /// the closest achievable period.
129 ///
130 /// # Arguments
131 ///
132 /// * `period_ns` - The desired TCK period in nanoseconds
133 ///
134 /// # Returns
135 ///
136 /// The actual TCK period set by the hardware (in nanoseconds). This may differ from
137 /// the requested value if the hardware has limited frequency resolution.
138 fn set_tck(&self, period_ns: u32) -> u32;
139
140 /// Shift JTAG TMS and TDI vectors into the device and return TDO data.
141 ///
142 /// Performs a JTAG shift operation by:
143 /// 1. Shifting `tms` and `tdi` data into the JTAG chain
144 /// 2. Capturing the corresponding `tdo` (Test Data Out) data
145 /// 3. Returning the captured `tdo` data
146 ///
147 /// The operation is atomic with respect to the JTAG state machine.
148 ///
149 /// # Arguments
150 ///
151 /// * `num_bits` - Number of TCK cycles to perform
152 /// * `tms` - Test Mode Select vector (must be ⌈num_bits / 8⌉ bytes)
153 /// * `tdi` - Test Data In vector (must be ⌈num_bits / 8⌉ bytes)
154 ///
155 /// # Returns
156 ///
157 /// Test Data Out vector of the same size as `tms` and `tdi`. On error,
158 /// an empty vector should be returned.
159 ///
160 /// # Error Handling
161 ///
162 /// The XVC 1.0 protocol does not support error reporting for shift operations.
163 /// Implementations should return an empty box on error rather than propagating errors.
164 fn shift(&self, num_bits: u32, tms: &[u8], tdi: &[u8]) -> Box<[u8]>;
165}