Skip to main content

piper_driver/
builder.rs

1//! Builder 模式实现
2//!
3//! 提供链式构造 `Piper` 实例的便捷方式。
4
5use crate::error::DriverError;
6use crate::pipeline::PipelineConfig;
7use crate::piper::Piper;
8
9#[cfg(all(not(feature = "mock"), target_os = "linux"))]
10use piper_can::SocketCanAdapter;
11
12#[cfg(not(feature = "mock"))]
13use piper_can::gs_usb::GsUsbCanAdapter;
14
15#[cfg(not(feature = "mock"))]
16use piper_can::gs_usb_udp::GsUsbUdpAdapter;
17
18#[cfg(not(feature = "mock"))]
19use piper_can::{CanDeviceError, CanDeviceErrorKind, CanError};
20
21/// 驱动类型选择
22#[derive(Debug, Clone, Copy)]
23pub enum DriverType {
24    /// 自动探测(默认)
25    /// - Linux: 如果 interface 是 "can0"/"can1" 等,使用 SocketCAN;否则尝试 GS-USB
26    /// - 其他平台: 使用 GS-USB
27    Auto,
28    /// 强制使用 SocketCAN(仅 Linux)
29    SocketCan,
30    /// 强制使用 GS-USB(所有平台)
31    GsUsb,
32}
33
34/// Piper Builder(链式构造)
35///
36/// 使用 Builder 模式创建 `Piper` 实例,支持链式调用。
37///
38/// # Example
39///
40/// ```no_run
41/// use piper_driver::{PiperBuilder, PipelineConfig};
42///
43/// // 使用默认配置
44/// let piper = PiperBuilder::new()
45///     .build()
46///     .unwrap();
47///
48/// // 自定义波特率和 Pipeline 配置
49/// let config = PipelineConfig {
50///     receive_timeout_ms: 5,
51///     frame_group_timeout_ms: 20,
52///     velocity_buffer_timeout_us: 20_000,
53/// };
54/// let piper = PiperBuilder::new()
55///     .baud_rate(500_000)
56///     .pipeline_config(config)
57///     .build()
58///     .unwrap();
59/// ```
60pub struct PiperBuilder {
61    /// CAN 接口名称或设备序列号
62    ///
63    /// - Linux: "can0"/"can1" 等 SocketCAN 接口名,或设备序列号(使用 GS-USB)
64    /// - macOS/Windows: GS-USB 设备序列号
65    interface: Option<String>,
66    /// CAN 波特率(1M, 500K, 250K 等)
67    baud_rate: Option<u32>,
68    /// Pipeline 配置
69    pipeline_config: Option<PipelineConfig>,
70    /// 守护进程地址(如果设置,使用守护进程模式)
71    /// - UDS 路径(如 "/tmp/gs_usb_daemon.sock")
72    /// - UDP 地址(如 "127.0.0.1:8888")
73    daemon_addr: Option<String>,
74    /// 驱动类型选择(新增)
75    driver_type: DriverType,
76}
77
78impl PiperBuilder {
79    /// 创建新的 Builder
80    ///
81    /// # Example
82    ///
83    /// ```no_run
84    /// use piper_driver::PiperBuilder;
85    ///
86    /// let builder = PiperBuilder::new();
87    /// ```
88    pub fn new() -> Self {
89        Self {
90            interface: None,
91            baud_rate: None,
92            pipeline_config: None,
93            daemon_addr: None,
94            driver_type: DriverType::Auto,
95        }
96    }
97
98    /// 显式指定驱动类型(可选,默认 Auto)
99    ///
100    /// # Example
101    ///
102    /// ```no_run
103    /// use piper_driver::{PiperBuilder, DriverType};
104    ///
105    /// // 强制使用 GS-USB
106    /// let piper = PiperBuilder::new()
107    ///     .with_driver_type(DriverType::GsUsb)
108    ///     .build()
109    ///     .unwrap();
110    /// ```
111    pub fn with_driver_type(mut self, driver_type: DriverType) -> Self {
112        self.driver_type = driver_type;
113        self
114    }
115
116    /// 设置 CAN 接口(可选,默认自动检测)
117    ///
118    /// # 注意
119    /// - Linux: 此参数可以是 SocketCAN 接口名称(如 "can0" 或 "vcan0")或 GS-USB 设备序列号
120    ///   - 如果接口名是 "can0"/"can1" 等,优先使用 SocketCAN(通过 Smart Default)
121    ///   - 如果接口名是设备序列号或未提供,使用 GS-USB
122    /// - macOS/Windows (GS-USB): 此参数用作设备序列号,用于区分多个 GS-USB 设备
123    ///   - 如果提供序列号,只打开匹配序列号的设备
124    ///   - 如果不提供,自动选择第一个找到的设备
125    ///
126    /// # Example
127    ///
128    /// ```no_run
129    /// use piper_driver::PiperBuilder;
130    ///
131    /// // 通过序列号指定设备
132    /// let piper = PiperBuilder::new()
133    ///     .interface("ABC123456")
134    ///     .build()
135    ///     .unwrap();
136    /// ```
137    pub fn interface(mut self, interface: impl Into<String>) -> Self {
138        self.interface = Some(interface.into());
139        self
140    }
141
142    /// 设置 CAN 波特率(可选,默认 1M)
143    pub fn baud_rate(mut self, baud_rate: u32) -> Self {
144        self.baud_rate = Some(baud_rate);
145        self
146    }
147
148    /// 设置 Pipeline 配置(可选)
149    pub fn pipeline_config(mut self, config: PipelineConfig) -> Self {
150        self.pipeline_config = Some(config);
151        self
152    }
153
154    /// 使用守护进程模式(可选)
155    ///
156    /// 当指定守护进程地址时,使用 `GsUsbUdpAdapter` 通过守护进程访问 GS-USB 设备。
157    /// 这解决了 macOS 下 GS-USB 设备重连后无法正常工作的限制。
158    ///
159    /// # 参数
160    /// - `daemon_addr`: 守护进程地址
161    ///   - UDS 路径(如 "/tmp/gs_usb_daemon.sock")
162    ///   - UDP 地址(如 "127.0.0.1:8888")
163    ///
164    /// # Example
165    ///
166    /// ```no_run
167    /// use piper_driver::PiperBuilder;
168    ///
169    /// // 使用 UDS 连接守护进程
170    /// let piper = PiperBuilder::new()
171    ///     .with_daemon("/tmp/gs_usb_daemon.sock")
172    ///     .build()
173    ///     .unwrap();
174    ///
175    /// // 使用 UDP 连接守护进程(用于跨机器调试)
176    /// let piper = PiperBuilder::new()
177    ///     .with_daemon("127.0.0.1:8888")
178    ///     .build()
179    ///     .unwrap();
180    /// ```
181    pub fn with_daemon(mut self, daemon_addr: impl Into<String>) -> Self {
182        self.daemon_addr = Some(daemon_addr.into());
183        self
184    }
185
186    /// 构建 Piper 实例
187    ///
188    /// 创建并启动 `Piper` 实例,启动后台 IO 线程。
189    ///
190    /// # Errors
191    /// - `DriverError::Can`: CAN 设备初始化失败
192    ///
193    /// # Example
194    ///
195    /// ```no_run
196    /// use piper_driver::PiperBuilder;
197    ///
198    /// match PiperBuilder::new().build() {
199    ///     Ok(piper) => {
200    ///         // 使用 piper 读取状态
201    ///         let state = piper.get_joint_position();
202    ///     }
203    ///     Err(e) => {
204    ///         eprintln!("Failed to create Piper: {}", e);
205    ///     }
206    /// }
207    /// ```
208    pub fn build(self) -> Result<Piper, DriverError> {
209        // 1. 守护进程模式(所有平台,优先级最高)
210        #[cfg(not(feature = "mock"))]
211        if let Some(ref daemon_addr) = self.daemon_addr {
212            return self.build_gs_usb_daemon(daemon_addr.clone());
213        }
214
215        // 2. 根据 driver_type 和 interface 自动选择后端
216        #[cfg(not(feature = "mock"))]
217        {
218            match self.driver_type {
219                DriverType::Auto => {
220                    // Linux: Smart Default 逻辑
221                    #[cfg(target_os = "linux")]
222                    {
223                        if let Some(ref interface) = self.interface {
224                            // 如果接口名是 "can0", "can1" 等,尝试 SocketCAN
225                            if interface.starts_with("can") && interface.len() <= 5 {
226                                // 尝试 SocketCAN(可能失败,例如接口不存在)
227                                if let Ok(piper) = self.build_socketcan(interface.as_str()) {
228                                    return Ok(piper);
229                                }
230                                // 如果 SocketCAN 失败,fallback 到 GS-USB
231                                tracing::info!(
232                                    "SocketCAN interface '{}' not available, falling back to GS-USB",
233                                    interface
234                                );
235                            }
236                        }
237                        // 其他情况(未指定接口、USB 总线号等):使用 GS-USB
238                        self.build_gs_usb_direct()
239                    }
240
241                    // 其他平台:默认使用 GS-USB
242                    #[cfg(not(target_os = "linux"))]
243                    {
244                        self.build_gs_usb_direct()
245                    }
246                },
247                DriverType::SocketCan => {
248                    #[cfg(target_os = "linux")]
249                    {
250                        let interface = self.interface.as_deref().unwrap_or("can0");
251                        self.build_socketcan(interface)
252                    }
253                    #[cfg(not(target_os = "linux"))]
254                    {
255                        Err(DriverError::Can(CanError::Device(CanDeviceError::new(
256                            CanDeviceErrorKind::UnsupportedConfig,
257                            "SocketCAN is only available on Linux",
258                        ))))
259                    }
260                },
261                DriverType::GsUsb => self.build_gs_usb_direct(),
262            }
263        }
264
265        // Mock 模式:使用 MockCanAdapter
266        #[cfg(feature = "mock")]
267        {
268            use piper_can::MockCanAdapter;
269            let can = MockCanAdapter::new();
270
271            let interface = self.interface.unwrap_or_else(|| "mock".to_string());
272            let bus_speed = self.baud_rate.unwrap_or(1_000_000);
273            Piper::new(can, self.pipeline_config)
274                .map(|p| p.with_metadata(interface, bus_speed))
275                .map_err(DriverError::Can)
276        }
277    }
278
279    /// 构建 SocketCAN 适配器(Linux only)
280    #[cfg(all(not(feature = "mock"), target_os = "linux"))]
281    fn build_socketcan(&self, interface: &str) -> Result<Piper, DriverError> {
282        let mut can = SocketCanAdapter::new(interface).map_err(DriverError::Can)?;
283
284        // SocketCAN 的波特率由系统配置,但可以调用 configure 验证接口状态
285        if let Some(bitrate) = self.baud_rate {
286            can.configure(bitrate).map_err(DriverError::Can)?;
287        }
288
289        let config = self.pipeline_config.clone().unwrap_or_default();
290        can.set_read_timeout(std::time::Duration::from_millis(config.receive_timeout_ms))
291            .map_err(DriverError::Can)?;
292
293        // 使用双线程模式(默认)
294        let interface = interface.to_string();
295        let bus_speed = self.baud_rate.unwrap_or(1_000_000);
296        Piper::new_dual_thread(can, self.pipeline_config.clone())
297            .map(|p| p.with_metadata(interface, bus_speed))
298            .map_err(DriverError::Can)
299    }
300
301    /// 构建 GS-USB 直连适配器
302    #[cfg(not(feature = "mock"))]
303    fn build_gs_usb_direct(&self) -> Result<Piper, DriverError> {
304        // interface 可能是:
305        // - 设备序列号(如 "ABC123456")
306        // - USB 总线号(如 "1:12",表示 bus 1, address 12)
307        // - None(自动选择第一个设备)
308
309        let mut can = match &self.interface {
310            Some(serial) if serial.contains(':') => {
311                // USB 总线号格式:bus:address
312                let parts: Vec<&str> = serial.split(':').collect();
313                if parts.len() == 2 {
314                    if let (Ok(bus), Ok(addr)) = (parts[0].parse::<u8>(), parts[1].parse::<u8>()) {
315                        use piper_can::gs_usb::device::{GsUsbDevice, GsUsbDeviceSelector};
316                        let selector = GsUsbDeviceSelector::by_bus_address(bus, addr);
317                        let _device = GsUsbDevice::open(&selector).map_err(|e| {
318                            DriverError::Can(CanError::Device(CanDeviceError::new(
319                                CanDeviceErrorKind::Backend,
320                                format!("Failed to open GS-USB device at {}:{}: {}", bus, addr, e),
321                            )))
322                        })?;
323                        // 注意:从 device 创建 adapter 的完整实现需要访问 GsUsbCanAdapter 的内部
324                        // 暂时 fallback 到序列号方式
325                        GsUsbCanAdapter::new_with_serial(Some(serial.as_str()))
326                            .map_err(DriverError::Can)?
327                    } else {
328                        GsUsbCanAdapter::new_with_serial(Some(serial.as_str()))
329                            .map_err(DriverError::Can)?
330                    }
331                } else {
332                    GsUsbCanAdapter::new_with_serial(Some(serial.as_str()))
333                        .map_err(DriverError::Can)?
334                }
335            },
336            Some(serial) => {
337                GsUsbCanAdapter::new_with_serial(Some(serial.as_str())).map_err(DriverError::Can)?
338            },
339            None => GsUsbCanAdapter::new().map_err(DriverError::Can)?,
340        };
341
342        let bitrate = self.baud_rate.unwrap_or(1_000_000);
343        can.configure(bitrate).map_err(DriverError::Can)?;
344
345        let config = self.pipeline_config.clone().unwrap_or_default();
346        can.set_receive_timeout(std::time::Duration::from_millis(config.receive_timeout_ms));
347
348        // 使用双线程模式(默认)
349        let interface = self.interface.clone().unwrap_or_else(|| {
350            // Try to get the actual device serial
351            "unknown".to_string()
352        });
353        let bus_speed = bitrate;
354        Piper::new_dual_thread(can, self.pipeline_config.clone())
355            .map(|p| p.with_metadata(interface, bus_speed))
356            .map_err(DriverError::Can)
357    }
358
359    /// 构建 GS-USB 守护进程适配器
360    ///
361    /// 注意:GsUsbUdpAdapter 不支持 SplittableAdapter,因此使用单线程模式。
362    #[cfg(not(feature = "mock"))]
363    fn build_gs_usb_daemon(&self, daemon_addr: String) -> Result<Piper, DriverError> {
364        let mut can = if daemon_addr.starts_with('/') || daemon_addr.starts_with("unix:") {
365            // UDS 模式
366            #[cfg(unix)]
367            {
368                let path = daemon_addr.strip_prefix("unix:").unwrap_or(&daemon_addr);
369                GsUsbUdpAdapter::new_uds(path).map_err(DriverError::Can)?
370            }
371            #[cfg(not(unix))]
372            {
373                return Err(DriverError::Can(CanError::Device(
374                    "Unix Domain Sockets are not supported on this platform. Please use UDP address format (e.g., 127.0.0.1:8888)".into(),
375                )));
376            }
377        } else {
378            // UDP 模式
379            GsUsbUdpAdapter::new_udp(&daemon_addr).map_err(DriverError::Can)?
380        };
381
382        // 连接到守护进程(使用空的过滤规则,接收所有帧)
383        can.connect(vec![]).map_err(DriverError::Can)?;
384
385        // 注意:GsUsbUdpAdapter 不支持 SplittableAdapter,因此使用单线程模式
386        // TODO: 实现双线程模式
387        let interface = daemon_addr.clone();
388        let bus_speed = self.baud_rate.unwrap_or(1_000_000);
389        Piper::new(can, self.pipeline_config.clone())
390            .map(|p| p.with_metadata(interface, bus_speed))
391            .map_err(DriverError::Can)
392    }
393}
394
395impl Default for PiperBuilder {
396    fn default() -> Self {
397        Self::new()
398    }
399}
400
401#[cfg(test)]
402mod tests {
403    use super::*;
404
405    #[test]
406    fn test_piper_builder_new() {
407        let builder = PiperBuilder::new();
408        assert_eq!(builder.interface, None);
409        assert_eq!(builder.baud_rate, None);
410        // 注意:不直接比较 pipeline_config,因为它没有实现 PartialEq
411        // 但可以通过 is_none() 检查
412        assert!(builder.pipeline_config.is_none());
413        assert_eq!(builder.daemon_addr, None);
414    }
415
416    #[test]
417    fn test_piper_builder_chain() {
418        let builder = PiperBuilder::new().interface("can0").baud_rate(500_000);
419
420        assert_eq!(builder.interface, Some("can0".to_string()));
421        assert_eq!(builder.baud_rate, Some(500_000));
422    }
423
424    #[test]
425    fn test_piper_builder_default() {
426        let builder = PiperBuilder::default();
427        assert_eq!(builder.interface, None);
428        assert_eq!(builder.baud_rate, None);
429    }
430
431    #[test]
432    fn test_piper_builder_pipeline_config() {
433        let config = PipelineConfig {
434            receive_timeout_ms: 5,
435            frame_group_timeout_ms: 20,
436            velocity_buffer_timeout_us: 10_000,
437        };
438        let builder = PiperBuilder::new().pipeline_config(config.clone());
439
440        // 验证 pipeline_config 已设置
441        assert!(builder.pipeline_config.is_some());
442        let stored_config = builder.pipeline_config.as_ref().unwrap();
443        assert_eq!(stored_config.receive_timeout_ms, 5);
444        assert_eq!(stored_config.frame_group_timeout_ms, 20);
445    }
446
447    #[test]
448    fn test_piper_builder_all_options() {
449        let config = PipelineConfig {
450            receive_timeout_ms: 3,
451            frame_group_timeout_ms: 15,
452            velocity_buffer_timeout_us: 10_000,
453        };
454        let builder =
455            PiperBuilder::new().interface("can1").baud_rate(250_000).pipeline_config(config);
456
457        assert_eq!(builder.interface, Some("can1".to_string()));
458        assert_eq!(builder.baud_rate, Some(250_000));
459        assert!(builder.pipeline_config.is_some());
460    }
461
462    #[test]
463    fn test_piper_builder_interface_chaining() {
464        let builder1 = PiperBuilder::new().interface("can0");
465        let builder2 = builder1.interface("can1");
466
467        // 验证最后一次设置生效
468        assert_eq!(builder2.interface, Some("can1".to_string()));
469    }
470
471    #[test]
472    fn test_piper_builder_receive_timeout_config() {
473        // 测试:PipelineConfig.receive_timeout_ms 应该被应用到 adapter
474        // 注意:这是一个编译时测试,实际运行时测试需要硬件设备
475        let config = PipelineConfig {
476            receive_timeout_ms: 5,
477            frame_group_timeout_ms: 20,
478            velocity_buffer_timeout_us: 10_000,
479        };
480        let builder = PiperBuilder::new().pipeline_config(config.clone());
481
482        // 验证配置被正确存储
483        assert!(builder.pipeline_config.is_some());
484        let stored_config = builder.pipeline_config.as_ref().unwrap();
485        assert_eq!(stored_config.receive_timeout_ms, 5);
486        assert_eq!(stored_config.frame_group_timeout_ms, 20);
487
488        // 验证默认配置
489        let default_config = PipelineConfig::default();
490        assert_eq!(default_config.receive_timeout_ms, 2);
491        assert_eq!(default_config.frame_group_timeout_ms, 10);
492    }
493
494    #[test]
495    fn test_piper_builder_baud_rate_chaining() {
496        let builder1 = PiperBuilder::new().baud_rate(1_000_000);
497        let builder2 = builder1.baud_rate(500_000);
498
499        // 验证最后一次设置生效
500        assert_eq!(builder2.baud_rate, Some(500_000));
501    }
502
503    #[test]
504    fn test_piper_builder_with_daemon_uds() {
505        let builder = PiperBuilder::new().with_daemon("/tmp/gs_usb_daemon.sock");
506        assert_eq!(
507            builder.daemon_addr,
508            Some("/tmp/gs_usb_daemon.sock".to_string())
509        );
510    }
511
512    #[test]
513    fn test_piper_builder_with_daemon_udp() {
514        let builder = PiperBuilder::new().with_daemon("127.0.0.1:8888");
515        assert_eq!(builder.daemon_addr, Some("127.0.0.1:8888".to_string()));
516    }
517
518    #[test]
519    fn test_piper_builder_with_daemon_chaining() {
520        let builder1 = PiperBuilder::new().with_daemon("/tmp/test1.sock");
521        let builder2 = builder1.with_daemon("127.0.0.1:8888");
522
523        // 验证最后一次设置生效
524        assert_eq!(builder2.daemon_addr, Some("127.0.0.1:8888".to_string()));
525    }
526
527    #[test]
528    fn test_piper_builder_daemon_and_interface() {
529        // 守护进程模式和 interface 可以同时设置(虽然 interface 在守护进程模式下会被忽略)
530        let builder =
531            PiperBuilder::new().with_daemon("/tmp/gs_usb_daemon.sock").interface("ABC123");
532
533        assert_eq!(
534            builder.daemon_addr,
535            Some("/tmp/gs_usb_daemon.sock".to_string())
536        );
537        assert_eq!(builder.interface, Some("ABC123".to_string()));
538    }
539
540    #[test]
541    fn test_piper_builder_driver_type() {
542        let builder1 = PiperBuilder::new();
543        assert!(matches!(builder1.driver_type, DriverType::Auto));
544
545        let builder2 = PiperBuilder::new().with_driver_type(DriverType::GsUsb);
546        assert!(matches!(builder2.driver_type, DriverType::GsUsb));
547
548        let builder3 = PiperBuilder::new().with_driver_type(DriverType::SocketCan);
549        assert!(matches!(builder3.driver_type, DriverType::SocketCan));
550    }
551}