kenwood_thd75/transport/mod.rs
1//! Async transport trait and implementations for radio communication.
2//!
3//! The TH-D75 communicates over USB CDC ACM (Communications Device Class
4//! Abstract Control Model) which presents as a standard serial port, and
5//! Bluetooth SPP (Serial Port Profile) via RFCOMM.
6//!
7//! # Bluetooth (per Operating Tips §5.12)
8//!
9//! - Bluetooth version 3.0, Class 2 (range ~10m)
10//! - Profiles: HSP (Headset Profile) + SPP (Serial Port Profile)
11//! - No BLE (Bluetooth Low Energy) and no HFP (Hands-Free Profile)
12//! - BT headset provides mic + earphone for voice; PTT remains on the
13//! radio body (no BT PTT except via VOX)
14//! - Menu No. 112: BT microphone sensitivity adjustment
15//! - When a BT headset is connected, audio is NOT routed to the USB
16//! port or external speaker jack
17//! - Menu No. 933: view/manage connected BT devices
18//!
19//! # USB (per Operating Tips §5.13)
20//!
21//! - CDC virtual COM port (same driver as TH-D74, available at kenwood.com)
22//! - USB audio output: 48 kHz / 16-bit / mono, output only (same as speaker
23//! output). Adjustable via Menu No. 91A.
24//! - USB Mass Storage: Menu No. 980 (Windows only for mass storage feature)
25//!
26//! Implementations:
27//! - [`SerialTransport`] — USB serial connections (and BT via `/dev/cu.*`)
28//! - [`BluetoothTransport`] — Native macOS `IOBluetooth` RFCOMM (macOS only)
29//! - [`MockTransport`] — Programmed exchanges for testing
30//!
31//! On macOS, prefer [`BluetoothTransport`] over [`SerialTransport`] for BT
32//! connections. The macOS serial port driver has a bug where closing and
33//! reopening `/dev/cu.TH-D75` kills the RFCOMM channel permanently.
34//! [`BluetoothTransport`] talks directly to the RFCOMM channel via
35//! `IOBluetooth` and can be closed and reopened without issues.
36
37#[cfg(any(target_os = "macos", doc))]
38pub mod bluetooth;
39pub mod either;
40pub mod mmdvm_adapter;
41pub mod mock;
42pub mod serial;
43
44#[cfg(any(target_os = "macos", doc))]
45pub use bluetooth::BluetoothTransport;
46pub use either::EitherTransport;
47pub use mmdvm_adapter::MmdvmTransportAdapter;
48pub use mock::MockTransport;
49pub use serial::SerialTransport;
50
51use std::future::Future;
52
53use crate::error::TransportError;
54
55/// Async transport for communicating with the radio.
56///
57/// Implemented for USB serial (CDC ACM), Bluetooth SPP (Serial Port
58/// Profile), and mock (testing).
59pub trait Transport: Send + Sync {
60 /// Send raw bytes to the radio.
61 fn write(&mut self, data: &[u8]) -> impl Future<Output = Result<(), TransportError>> + Send;
62
63 /// Read available bytes into buffer, return count of bytes read.
64 fn read(
65 &mut self,
66 buf: &mut [u8],
67 ) -> impl Future<Output = Result<usize, TransportError>> + Send;
68
69 /// Close the connection.
70 fn close(&mut self) -> impl Future<Output = Result<(), TransportError>> + Send;
71
72 /// Change the transport baud rate.
73 ///
74 /// Used when switching between CAT mode (115200 baud over CDC ACM)
75 /// and programming mode (9600 baud for the entire session). No-op
76 /// for transports that do not support baud rate changes (e.g., mock).
77 ///
78 /// # Errors
79 ///
80 /// Returns [`TransportError::Open`] if the baud rate cannot be applied.
81 fn set_baud_rate(&mut self, _baud: u32) -> Result<(), TransportError> {
82 Ok(())
83 }
84}