中文 | English
ATCP is a pure C99, zero-dependency audio-channel data communication protocol stack library. It establishes a bidirectional data link between a PC and an MCU over a standard 3.5 mm audio interface (Speaker Out / Mic In), enabling covert communication that bypasses the network layer.
┌─────────────────┐ 3.5mm Audio Cable ┌─────────────────┐
│ Host (PC) │ ◄─────────────────────────► │ Device (MCU) │
│ │ Speaker Out ──► ADC In │ │
│ │ Mic In ◄── DAC Out │ │
└─────────────────┘ └─────────────────┘
- Zero Dependencies — Pure C99; embeddable on any platform (bare-metal / RTOS / desktop)
- Bidirectional — Downlink: differential stereo OFDM + adaptive QAM (QPSK–256-QAM); Uplink: mono fixed QPSK
- Dual Reliability — Reed-Solomon FEC + sliding-window ARQ with selective retransmission, AIMD congestion window, and RTT-based adaptive timeout
- Adaptive Rate — Real-time SNR-driven QAM order switching (automatic up/down-grade) with peer notification via rate-change frames
- Auto Reconnect & Self-Healing — Heartbeat-based disconnection detection, exponential-backoff reconnection, and runtime modulation fallback on link degradation
- High Throughput — ~90% effective data ratio in streaming mode; up to ~95 kbps downlink
- Optimized Hot Path — Precomputed FFT twiddle tables and QAM constellation lookup tables; cached training waveforms
- Adaptive Handshake — 4-phase negotiation of sample rate, QAM order, etc., with real link-quality (SNR) assessment and automatic fallback
- Non-blocking API — Event-driven design; all operations are asynchronous
- Cross-platform — Windows / Linux / STM32 / ESP32 and more
┌───────────────────────────────┐
│ Application Layer │ User code (file transfer, command control, encryption, etc.)
├───────────────────────────────┤
│ Link Layer │ Handshake, heartbeat/auto-reconnect, framing, ARQ (AIMD + adaptive timeout)
├───────────────────────────────┤
│ Coding Layer │ RS FEC encoding/decoding, CRC32 checksum
├───────────────────────────────┤
│ Modulation Layer │ OFDM + M-QAM, frame sync, channel estimation
├───────────────────────────────┤
│ Physical Layer │ Differential signaling, AGC, CFO/SFO compensation
└───────────────────────────────┘
- CMake >= 3.10
- C99-compatible compiler (MSVC / GCC / Clang)
# Shared library (default)
cmake -B build
cmake --build build --config Release
# Static library (recommended for embedded)
cmake -B build -DBUILD_SHARED_LIBS=OFF
cmake --build build --config Release| CMake Option | Default | Description |
|---|---|---|
BUILD_SHARED_LIBS |
ON |
ON = shared library, OFF = static library |
BUILD_TESTS |
ON |
Whether to build unit tests |
Static library users should define
ATCP_STATICin their compile options to suppress DLL export decorations.
#include <atcp/atcp.h>
/* 1. Implement platform callbacks */
int my_audio_write(const float *samples, int n, int ch, void *ud) { /* write to speaker */ return n; }
int my_audio_read(float *samples, int n, int ch, void *ud) { /* read from mic */ return n; }
uint32_t my_get_time_ms(void *ud) { return get_system_time_ms(); }
int main(void) {
/* 2. Configure platform callbacks */
atcp_platform_t platform = {0};
platform.audio_write = my_audio_write;
platform.audio_read = my_audio_read;
platform.get_time_ms = my_get_time_ms;
/* 3. Create instance (NULL = use default config) */
atcp_instance_t *inst = atcp_create(NULL, &platform);
/* 4. Initiate connection */
atcp_connect(inst);
/* 5. Main loop (recommended 10-15 ms interval) */
while (1) {
atcp_tick(inst);
if (atcp_get_state(inst) == ATCP_STATE_CONNECTED) {
const uint8_t msg[] = "Hello MCU!";
atcp_send(inst, msg, sizeof(msg));
uint8_t buf[256];
size_t received = 0;
if (atcp_recv(inst, buf, sizeof(buf), &received) == ATCP_OK) {
/* process received data */
}
}
}
atcp_destroy(inst);
return 0;
}| Function | Description |
|---|---|
atcp_create(config, platform) |
Create an instance; pass NULL for config to use defaults |
atcp_destroy(inst) |
Destroy instance and release all resources |
atcp_connect(inst) |
Initiate connection (active side), non-blocking |
atcp_accept(inst) |
Wait for connection (passive side), non-blocking |
atcp_disconnect(inst) |
Disconnect |
atcp_send(inst, data, len) |
Send data, non-blocking |
atcp_recv(inst, buf, len, &received) |
Receive data |
atcp_tick(inst) |
Drive the protocol stack (audio I/O, frame sync, demodulation, ARQ, heartbeat) |
atcp_get_state(inst) |
Get current connection state (incl. ATCP_STATE_RECONNECTING) |
atcp_get_stats(inst) |
Get statistics (BER, SNR, throughput, RTT, reconnect count, link quality, etc.) |
atcp_get_link_quality(inst) |
Get composite link-quality score (0–100) |
atcp_reset(inst) |
Reset instance back to IDLE (reconnectable without destroy/recreate) |
atcp_get_audio_buf_size(inst) |
Get required audio buffer size (number of floats) |
ATCP/
├── CMakeLists.txt # Top-level build config
├── lib/ # Core C protocol stack library
│ ├── CMakeLists.txt # Library build config
│ ├── USER_GUIDE.md # User guide
│ ├── DEVELOPER_GUIDE.md # Developer guide
│ ├── include/atcp/ # Public headers
│ │ ├── atcp.h # Unified API entry point
│ │ ├── types.h # Type definitions, status codes
│ │ ├── config.h # Configuration struct & defaults
│ │ └── platform.h # Platform abstraction callbacks
│ ├── src/
│ │ ├── atcp.c # API implementation (integration layer)
│ │ ├── common/ # FFT, complex math, ring buffer, PRNG
│ │ ├── physical/ # Differential coding, AGC, CFO/SFO compensation
│ │ ├── modulation/ # OFDM, QAM, training sequences, frame sync, channel estimation
│ │ ├── coding/ # RS FEC, CRC32, GF(256)
│ │ └── link/ # Framing, handshake, ARQ, ACK, heartbeat
│ └── tests/ # Unit tests & integration tests
└── simulator/ # C# simulator + WPF control center
├── ATCP.Simulator.sln # Visual Studio solution
├── SimCommon/ # Shared lib: P/Invoke, TCP audio transport, channel model,
│ # reusable engines, PRBS/FFT, cross-process telemetry
├── SimControlCenter/ # WPF unified control center (GUI)
├── SimUpper/ # Host simulator (console, reuses engine)
├── SimMiddleware/ # Relay + channel-impairment injection
└── SimLower/ # Device simulator (console, reuses engine)
Using ATCP requires implementing three callbacks in atcp_platform_t:
| Callback | Description |
|---|---|
audio_write |
Write audio samples to the output device (Speaker / DAC) |
audio_read |
Read audio samples from the input device (Mic / ADC) |
get_time_ms |
Return current system time in milliseconds |
| Platform | audio_write / audio_read | get_time_ms |
|---|---|---|
| Windows | WASAPI / PortAudio | GetTickCount() |
| Linux | ALSA / PulseAudio | clock_gettime() |
| STM32 | DMA + DAC/ADC | HAL_GetTick() |
| ESP32 | I2S Driver | esp_timer_get_time() / 1000 |
ATCP includes a C# simulation suite that emulates the audio channel over TCP, enabling protocol-stack validation and channel-impairment experiments without real hardware. It ships with a WPF unified control center (GUI) alongside the standalone console tools.
| Component | Description |
|---|---|
| SimControlCenter | WPF unified control center. Three tabs: Link Monitor (state / signal strength / RTT / throughput / BER / link quality with live charts), Channel Simulation (live impairment sliders + waveform & spectrum), Performance Test (PRBS + SNR sweep, CSV export). Hosts the middleware in-process and launches host/device as isolated child processes. |
| SimUpper | Host simulator — initiates connection, sends/receives data (text-echo or PRBS mode) |
| SimMiddleware | Relay + channel-impairment injection between host and device |
| SimLower | Device simulator — accepts connection, echo / PRBS verification |
| SimCommon | Shared library — P/Invoke wrappers, TCP audio transport, reusable engines, channel model, PRBS/FFT, cross-process telemetry |
The middleware interprets the byte stream as float32 audio waveforms and applies a configurable physical-layer channel:
- AWGN — target-SNR-driven Gaussian noise
- Multipath / frequency-selective fading — configurable tapped-delay-line FIR
- Slow fading — Rayleigh / Rician envelope (Doppler / K-factor)
- Phase noise & clock jitter — fractional-delay resampling (ppm / σ°)
- Amplitude distortion — tanh soft-clip + gain + DC offset
- AGC — ported from
agc.c(attack/release peak tracking) - High-precision oversampling — 1/2/4× internal processing
- Presets: Clean / MildIndoor / UrbanMultipath / Harsh
# 1. Build the core library first (produces atcp.dll)
cmake -B build && cmake --build build --config Release
# 2. Build the simulator suite
dotnet build simulator/ATCP.Simulator.sln -c Release
# 3a. GUI: run SimControlCenter and click Start
# (hosts the middleware in-process, launches SimUpper/SimLower as child processes)
# 3b. Or run the three consoles separately (start middleware first):
# SimMiddleware [--preset=Clean|MildIndoor|UrbanMultipath|Harsh] [--snr=<dB>]
# SimUpper [host] [--prbs]
# SimLower [host] [--prbs]Note: The ATCP core is single-instance / single-process by design (e.g. a global FFT plan), so the GUI runs the host and device as separate processes and hosts the impairment-free middleware in-process for visualization. The simulator depends on
atcp.dll; build the core library first.
- User Guide — Build steps, full API reference, configuration parameters
- Developer Guide — Architecture design, module details, coding standards, extension guide
See the LICENSE file.