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"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"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.
| 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.
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.
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 callStopRX/StopTXfrom there. - For TX, prefer signalling stop from the flush callback
(
EnableTxFlush) so the final samples are not dropped. Transfer.Bufferaliases 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.
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.
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.
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.