Skip to content
shorekeeperPublic

About

Data-driven transceiver control engine, C ABI library, and serial port multiplexing daemon, primarily targeting the Xiegu G90.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

Detent

Transceiver control library, serial multiplexing service, and command analysis toolset.

Developed primarily for the Xiegu G90 transceiver. Detent executes protocol definitions parsed from INI data files rather than hardcoded routines. It is not a complete drop-in replacement for OmniRig.

Platform support is strictly limited to Windows. Requests regarding Linux compatibility, support, or ports will be ignored and redirected to the depths of the freedesktop ABI.

Diagram

Architecture

Detent isolates protocol definitions from application logic. Transceiver command sets, reply validation masks, field offsets, and timing constraints are defined in standalone description files.

The codebase compiles to:

  • detent.lib / detent.dll: C-compatible shared and static libraries along with the native Rust crate.
  • detentd: Standalone sharing service allowing multiple client processes to multiplex access to a single serial port.
  • detent-capture: Diagnostic utility to sweep, log, diff, and generate description files from hardware exchanges.

C ABI Design

  • Foreign calls: No callbacks into client code. Device events accumulate in a thread-safe ring buffer drained on demand by the caller.
  • Exception boundary: Internal panics are intercepted at the ABI boundary and returned as negative DetentResult error codes.
  • Extensibility: Structures use Vulkan-style extensible chains (sType tag and pNext pointer). Unrecognized structure tags are skipped.
  • Memory isolation: Handles (DetentInstance, DetentDevice) are opaque pointers tagged internally to prevent use-after-free conditions.

Subsystems

1. Engine and Polling Loop

The core engine (detent::engine) does not spawn internal threads by default. It can be advanced manually within a host application frame loop or wrapped inside a dedicated background worker thread (detent::worker).

  • State model: Tracks frequency, VFO registers, split status, transmit state, RIT/XIT offsets, and modulation modes. Unread parameters remain explicitly undefined (None) rather than defaulting to zero.
  • Scheduling: Prioritizes initialization commands, followed by pending user writes, followed by round-robin status polling. High-velocity parameters (frequency, PTT) are polled every pass; static conditions (mode) are throttled.
  • Stream matching: Uses bitmasked pattern recognition across a sliding byte buffer. Unrelated bus traffic or delayed echo replies are stepped over without stalling the link.

2. Transceiver Multiplexer (detentd)

Serial ports cannot be accessed concurrently by separate programs. detentd opens the hardware COM port, executes the protocol engine, and serves client instances over a local Windows Named Pipe (\\.\pipe\detent-{user}-{port}).

  • Concurrent sessions: Multiplexes read status to all connected clients while serializing write commands.
  • Conflict resolution: Write collisions resolve on an arrival-time basis; the resulting state is broadcast to all attached processes.
  • Port retention: Stays active for a configurable linger window (default 30 seconds) after the last client detaches to eliminate re-initialization overhead during application restarts.
  • Auto-start: Clients can launch the daemon process on demand if the pipe endpoint is not detected.

3. Protocol Discovery (detent-capture)

A CLI utility used to inspect unknown transceivers or verify command timings:

  • Frame inspection: Measures turnaround latency, inter-byte delays, and half-duplex command echo.
  • Range sweep: Probes single-byte and multi-byte subcommand ranges, identifying acknowledged (0xFB), rejected (0xFA), or silent commands.
  • State diffing: Compares command spaces between physical states (e.g. before and after toggling an attenuator) to locate specific control bytes.
  • Section drafting: Generates draft INI profile sections directly from live replies, masking data bytes while preserving framing patterns.

Profile Description Format

Profiles are standard INI files defining sequences and expected packet formats.

; Example Xiegu G90 profile definition
[pmFreq]
Command = FEFE88E0.05.0000000000.FD
Value = 5|5|vfBcdLU|1|0
ReplyLength = 17
Validate = FEFE88E0050000000000FD.FEFEE088FBFD

[STATUS1]
Command = FEFE88E0.03.FD
ReplyLength = 17
Validate = FEFE88E003FD.FEFEE088.03.0000000000.FD
Value1 = 11|5|vfBcdLU|1|0|pmFreq

[DETENT]
TimeoutMs = 200
MaxPollHz = 8
GapMs = 10

Format Features

  • Command formatting: Raw hexadecimal notation, space-separated, dot-separated, or literal ASCII wrapped in parentheses ((FA00000000000;)).
  • Validation: Single-string bitmasks (where 00 denotes an unconstrained data byte) or explicit two-string mask/value pairs (mask|value).
  • Encodings: vfText, vfTextUD, vfBinL, vfBinB, vfBcdLU, vfBcdBU, vfBcdLS, vfBcdBS, vfDPIcom, and vfYaesu.

C API Integration Example

#include <stdio.h>
#include "detent/detent.h"

int main() {
    DetentInstanceCreateInfo create_info = {0};
    create_info.sType = DETENT_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    create_info.pProfileDirectory = "./rigs";

    DetentInstance instance = NULL;
    if (detentCreateInstance(&create_info, &instance) != DETENT_SUCCESS) {
        return 1;
    }

    DetentSerialTransport serial = {0};
    serial.sType = DETENT_STRUCTURE_TYPE_SERIAL_TRANSPORT;
    serial.pPortName = "COM5";
    serial.baud = 19200;
    serial.dataBits = 8;
    serial.stopBits = 1;
    serial.parity = DETENT_PARITY_NONE;

    DetentDeviceOpenInfo open_info = {0};
    open_info.sType = DETENT_STRUCTURE_TYPE_DEVICE_OPEN_INFO;
    open_info.pNext = &serial;
    open_info.pProfileName = "g90-detent";

    DetentDevice device = NULL;
    if (detentOpenDevice(instance, &open_info, &device) == DETENT_SUCCESS) {
        // Poll events or write values
        detentSetFrequency(device, 14025000);
        detentCloseDevice(device);
    }

    detentDestroyInstance(instance);
    return 0;
}

Building

Requires a standard Rust toolchain. Compiling C examples requires MSVC or Clang.

# Build Rust crate and C libraries (detent.lib, detent.dll)
cargo build --release

# Build daemon and capture tool
cargo build --release --bin detentd --bin detent-capture

# Run unit and integration tests
cargo test

License

This software is released under the Zero-Clause BSD (0BSD) License. Refer to the LICENSE file for details.

About

Data-driven transceiver control engine, C ABI library, and serial port multiplexing daemon, primarily targeting the Xiegu G90.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages