kenwood_thd75/lib.rs
1#![deny(unsafe_code)]
2//! Async Rust library for controlling the Kenwood TH-D75 transceiver via
3//! CAT (Computer Aided Transceiver) -- the serial command protocol Kenwood
4//! uses for remote radio control.
5//!
6//! This library supports all 55 CAT commands over USB serial or Bluetooth
7//! SPP connections. Command definitions and validation rules are based on
8//! analysis of TH-D75 firmware v1.03.000.
9//!
10//! # TH-D75 overview (per User Manual Chapter 28)
11//!
12//! - **Models**: TH-D75A (144/220/430 MHz tribander, Americas) and
13//! TH-D75E (144/430 MHz dual bander, Europe/UK).
14//! - **TX power**: 5 W / 2 W / 0.5 W / 0.05 W (4 steps).
15//! - **Modulation**: FM, NFM, DV (D-STAR GMSK), AM, LSB, USB, CW, WFM.
16//! - **Frequency stability**: +/-2.0 ppm.
17//! - **Operating temperature**: -20 to +60 C (-10 to +50 C with KNB-75LA).
18//! - **Receiver**: Band A double superheterodyne (1st IF 57.15 MHz,
19//! 2nd IF 450 kHz); Band B double/triple superheterodyne (1st IF
20//! 58.05 MHz, 2nd IF 450 kHz, 3rd IF 10.8 kHz for SSB/CW/AM).
21//! - **Audio output**: 400 mW or more at 8 ohm (7.4 V, 10% distortion).
22//! - **Memory**: 1000 channels, 1500 repeater lists, 30 hotspot lists.
23//! - **Weatherproof**: IP54/55.
24//! - **Bluetooth**: 3.0, Class 2, HSP + SPP profiles.
25//! - **GPS**: built-in receiver, TTFF cold ~40s / hot ~5s, 10 m accuracy.
26//! - **microSD**: 2-32 GB (FAT32), for config, recordings, GPS logs.
27//!
28//! # Usage
29//!
30//! ```rust,no_run
31//! use kenwood_thd75::transport::SerialTransport;
32//! use kenwood_thd75::radio::Radio;
33//! use kenwood_thd75::types::Band;
34//!
35//! # async fn example() -> Result<(), kenwood_thd75::error::Error> {
36//! // Connect over USB serial.
37//! let transport = SerialTransport::open("/dev/cu.usbmodem1234", 115_200)?;
38//! let mut radio = Radio::connect(transport).await?;
39//!
40//! // Verify the radio identity.
41//! let info = radio.identify().await?;
42//! println!("Connected to: {}", info.model);
43//!
44//! // Read the current frequency on Band A.
45//! let channel = radio.get_frequency(Band::A).await?;
46//! println!("RX frequency: {} Hz", channel.rx_frequency.as_hz());
47//!
48//! // Disconnect cleanly.
49//! radio.disconnect().await?;
50//! # Ok(())
51//! # }
52//! ```
53//!
54//! # Modules
55//!
56//! - [`types`] — Validated newtypes for frequencies, tones, modes, and channels.
57//! - [`protocol`] — Pure-logic CAT command codec (serialize / parse).
58//! - [`transport`] — Async I/O trait and serial / mock implementations.
59//! - [`radio`] — High-level async API wrapping the protocol and transport layers.
60//! - [`aprs`] — KISS TNC framing, AX.25 packet parsing, and APRS position decoding.
61//! - [`mmdvm`] — MMDVM serial protocol codec, D-STAR header, and slow data decoder.
62//! - [`error`] — Error types for transport, protocol, and validation failures.
63
64pub mod aprs;
65pub mod error;
66pub mod memory;
67pub mod mmdvm;
68pub mod protocol;
69pub mod radio;
70pub mod sdcard;
71pub mod transport;
72pub mod types;
73
74// Convenience re-exports for the most commonly used types.
75pub use error::Error;
76pub use radio::Radio;
77pub use radio::programming::McpSpeed;
78#[cfg(target_os = "macos")]
79pub use transport::BluetoothTransport;
80pub use transport::{EitherTransport, MockTransport, SerialTransport, Transport};
81
82// Memory image re-exports.
83pub use memory::{MemoryError, MemoryImage};
84
85// Generic crate re-exports at crate root for consumer convenience.
86//
87// These let existing downstream code keep using `kenwood_thd75::AprsClient`,
88// `kenwood_thd75::KissFrame`, etc. without importing the generic crates
89// directly. The items themselves live in `kiss-tnc`, `ax25-codec`, `aprs`,
90// and `aprs-is`; inside this crate, use those crate paths directly rather
91// than routing through these re-exports.
92pub use ::aprs::{
93 AprsData, AprsDataExtension, AprsError, AprsItem, AprsMessage, AprsMessenger, AprsObject,
94 AprsPosition, AprsQuery, AprsStatus, AprsTelemetry, AprsWeather, DigiAction, DigipeaterConfig,
95 Phg, SmartBeaconing, SmartBeaconingConfig, StationEntry, StationList, build_aprs_item,
96 build_aprs_message, build_aprs_mice, build_aprs_object, build_aprs_position_compressed,
97 build_aprs_position_report, build_aprs_status, build_aprs_weather,
98 build_query_response_position, parse_aprs_extensions,
99};
100pub use aprs_is::{
101 AprsIsClient, AprsIsConfig, AprsIsError, AprsIsEvent, aprs_is_passcode, build_login_string,
102 format_is_packet, parse_is_line,
103};
104pub use ax25_codec::{Ax25Address, Ax25Error, Ax25Packet};
105pub use kiss_tnc::{KissError, KissFrame};
106
107// D75-specific re-exports.
108pub use aprs::client::{AprsClient, AprsClientConfig, AprsEvent};
109
110// KISS session re-export.
111pub use radio::kiss_session::KissSession;
112
113// MMDVM session re-export.
114pub use radio::mmdvm_session::MmdvmSession;
115
116// MMDVM gateway re-exports. Raw codec types live in mmdvm-core; the
117// async event loop lives in mmdvm. The types re-exported here
118// compose those crates into the D-STAR-specific surface
119// TH-D75 consumers use.
120pub use mmdvm::{
121 DStarEvent, DStarGateway, DStarGatewayConfig, LastHeardEntry, MmdvmError, ModemMode,
122 ModemStatus, NakReason, ReconnectPolicy,
123};
124
125// SD card re-exports.
126pub use sdcard::SdCardError;
127pub use sdcard::config::{ConfigHeader, write_d75};