Skip to content

SinnDevelopment/gohackrf

Repository files navigation

gohackrf

A complete, 1:1 cgo wrapper around libhackrf, the host library for Great Scott Gadgets' HackRF software defined radios.

Every public function, enum, struct, and constant in libhackrf/hackrf.h is exposed with idiomatic Go signatures: errors as error, output parameters as return values, C strings as string, and C callbacks as Go func values.

import hackrf "github.com/SinnDevelopment/gohackrf"

Requirements

You need libhackrf (and its headers) installed.

Platform Install
macOS (Homebrew) brew install hackrf
Debian / Ubuntu sudo apt install libhackrf-dev
Fedora sudo dnf install hackrf-devel
Arch sudo pacman -S hackrf

cgo must be enabled (CGO_ENABLED=1, the default). The build flags default to the standard Homebrew prefix on macOS and the system paths on Linux. If your install lives elsewhere, override the search paths:

export CGO_CFLAGS="-I/your/prefix/include"
export CGO_LDFLAGS="-L/your/prefix/lib -lhackrf"

Quick start

package main

import (
	"fmt"
	"log"
	"time"

	hackrf "github.com/SinnDevelopment/gohackrf"
)

func main() {
	if err := hackrf.Init(); err != nil {
		log.Fatal(err)
	}
	defer hackrf.Exit()

	dev, err := hackrf.Open()
	if err != nil {
		log.Fatal(err)
	}
	defer dev.Close()

	dev.SetFreq(100_000_000)      // 100 MHz
	dev.SetSampleRate(10_000_000) // 10 MS/s
	dev.SetLNAGain(16)
	dev.SetVGAGain(20)

	var total int
	done := make(chan struct{})
	dev.StartRX(func(t *hackrf.Transfer) int {
		// t.Buffer is interleaved 8-bit I/Q, valid only during this call.
		total += t.ValidLength
		if total >= 50_000_000 {
			close(done)
			return 1 // request no further transfers
		}
		return 0
	})

	select {
	case <-done:
	case <-time.After(10 * time.Second):
	}
	dev.StopRX()
	fmt.Println("received", total, "bytes")
}

See examples/hackrf_info for a port of the upstream hackrf_info tool, and the runnable Example* functions in example_test.go.

API overview

Area Examples
Library Init, Exit, LibraryVersion, LibraryRelease, ComputeBasebandFilterBW
Discovery / lifecycle ListDevices, DeviceList.Open/BusSharing/Free, Open, OpenBySerial, Device.Close
Device info BoardIDRead, VersionStringRead, USBAPIVersionRead, BoardPartIDSerialNoRead, BoardRevRead, SupportedPlatformRead, Reset, SetLEDs, SetUIEnable, SetUserBiasTOpts
RF configuration SetFreq, SetFreqExplicit, SetSampleRate, SetSampleRateManual, SetBasebandFilterBandwidth, SetLNAGain, SetVGAGain, SetTxVGAGain, SetAmpEnable, SetAntennaEnable, SetClkoutEnable, ClkinStatus, SetHWSyncMode
HackRF Pro SetP1Ctrl, SetP2Ctrl, SetClkinCtrl, SetNarrowbandFilter, SetFPGABitstream, FPGAReadRegister, FPGAWriteRegister
Streaming StartRX, StopRX, StartTX, StopTX, StartRXSweep, InitSweep, SetTxBlockCompleteCallback, EnableTxFlush, IsStreaming, SetTxUnderrunLimit, SetRxOverrunLimit, TransferBufferSize, TransferQueueDepth
Opera Cake GetOperacakeBoards, SetOperacakeMode, GetOperacakeMode, SetOperacakePorts, SetOperacakeDwellTimes, SetOperacakeFreqRanges, SetOperacakeRanges, OperacakeGPIOTest
Debug / firmware Max2837Read/Write, Max2831Read/Write, Si5351CRead/Write, RFFC5071Read/Write, SpiflashErase/Write/Read/Status/ClearStatus, CPLDWrite, M0State, ReadSelfTest, TestRTCOsc, ReadADC

Run go doc github.com/SinnDevelopment/gohackrf (or browse on pkg.go.dev) for the full reference.

Coverage note

All 89 public functions in hackrf.h are wrapped, except hackrf_cpld_checksum, which upstream gates behind the HACKRF_ISSUE_609_IS_FIXED macro and does not ship in released builds of libhackrf — wrapping it would break linking.

Callbacks and concurrency

Streaming callbacks (TransferCallback, BlockCompleteCallback, FlushCallback) run on libhackrf's internal libusb transfer thread, not on a goroutine you control. Per the libhackrf contract:

  • Do not call other hackrf.* functions from inside a callback. Signal your main goroutine (e.g. via a channel) and call StopRX / StopTX from there.
  • For TX, prefer signalling stop from the flush callback (EnableTxFlush) so the final samples are not dropped.
  • Transfer.Buffer aliases a C-owned buffer that is only valid during the callback. Copy out anything you need to keep.

A Device is not safe for concurrent control operations from multiple goroutines; serialize them.

Safety

User context is passed to C as an opaque runtime/cgo.Handle value (never a Go pointer), so the async callback boundary respects cgo's pointer-passing rules and the garbage collector. Each Device registers one handle, released by Close.

The debug/firmware functions access hardware directly. Misusing the SPI flash functions can soft-brick a device (recoverable via DFU) — see the upstream documentation before using them.

Testing

go test ./...

The test suite covers the no-hardware paths (versioning, enum/error names, filter-bandwidth math, device listing). With a HackRF connected, go test -v will additionally list the device under TestListDevices.

License

gohackrf is licensed under the MIT License.

This project is a wrapper around libhackrf, which is © Great Scott Gadgets, Jared Boone, and Benjamin Vernoux, and is distributed under the BSD 3-Clause License. gohackrf does not bundle libhackrf; you install the native library separately. MIT is compatible with libhackrf's BSD 3-Clause license. Note that the broader HackRF repository also contains GPLv2 components (the firmware and the hackrf-tools utilities) — this wrapper links only against the BSD-licensed libhackrf and does not depend on those.

About

Go wrapper around the libhackrf library.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages