-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdevice.go
More file actions
272 lines (243 loc) · 7.75 KB
/
Copy pathdevice.go
File metadata and controls
272 lines (243 loc) · 7.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
package hackrf
/*
#include <stdlib.h>
#include <libhackrf/hackrf.h>
*/
import "C"
import (
"runtime/cgo"
"unsafe"
)
// Device is a handle to an open HackRF device. It wraps an opaque
// hackrf_device. Create one with Open, OpenBySerial or DeviceList.Open, and
// release it with Close. A Device is not safe for concurrent use by multiple
// goroutines for control operations.
type Device struct {
device *C.hackrf_device
handle cgo.Handle
// Streaming callbacks, invoked from libhackrf's transfer thread. Only one
// transferCallback is active at a time (RX, TX, or sweep).
transferCallback TransferCallback
blockCompleteCallback BlockCompleteCallback
flushCallback FlushCallback
}
// newDevice wraps a freshly opened C device handle, registering a cgo.Handle
// used to route streaming callbacks back to this Device.
func newDevice(cdev *C.hackrf_device) *Device {
d := &Device{device: cdev}
d.handle = cgo.NewHandle(d)
return d
}
// DeviceInfo describes a single device listed in a DeviceList.
type DeviceInfo struct {
// SerialNumber is the device serial number. It may be empty if libhackrf
// could not read it.
SerialNumber string
// USBBoardID identifies the hardware by USB product ID.
USBBoardID USBBoardID
}
// DeviceList is the set of connected HackRF devices returned by ListDevices.
// It must be released with Free when no longer needed. Individual devices are
// opened with Open.
type DeviceList struct {
list *C.hackrf_device_list_t
// Devices is the list of connected HackRF devices.
Devices []DeviceInfo
// USBDeviceCount is the number of all queried USB devices (not just
// HackRFs).
USBDeviceCount int
}
// ListDevices returns the list of connected HackRF devices. The returned list
// must be released with DeviceList.Free.
func ListDevices() (*DeviceList, error) {
cl := C.hackrf_device_list()
if cl == nil {
return nil, ErrOther
}
dl := &DeviceList{
list: cl,
USBDeviceCount: int(cl.usb_devicecount),
}
n := int(cl.devicecount)
if n > 0 {
serials := unsafe.Slice(cl.serial_numbers, n)
ids := unsafe.Slice(cl.usb_board_ids, n)
dl.Devices = make([]DeviceInfo, n)
for i := 0; i < n; i++ {
var serial string
if serials[i] != nil {
serial = C.GoString(serials[i])
}
dl.Devices[i] = DeviceInfo{
SerialNumber: serial,
USBBoardID: USBBoardID(ids[i]),
}
}
}
return dl, nil
}
// Count returns the number of connected HackRF devices in the list.
func (dl *DeviceList) Count() int { return len(dl.Devices) }
// Open opens the device at the given index in the list.
func (dl *DeviceList) Open(idx int) (*Device, error) {
var cdev *C.hackrf_device
r := C.hackrf_device_list_open(dl.list, C.int(idx), &cdev)
if err := errorFrom(r); err != nil {
return nil, err
}
return newDevice(cdev), nil
}
// BusSharing returns the number of devices sharing the USB bus with the HackRF
// at the given index.
func (dl *DeviceList) BusSharing(idx int) (int, error) {
r := C.hackrf_device_list_bus_sharing(dl.list, C.int(idx))
if r < 0 {
return 0, Error(r)
}
return int(r), nil
}
// Free releases the device list. It is safe to call multiple times.
func (dl *DeviceList) Free() {
if dl.list != nil {
C.hackrf_device_list_free(dl.list)
dl.list = nil
}
}
// Open opens the first available HackRF device.
func Open() (*Device, error) {
var cdev *C.hackrf_device
if err := errorFrom(C.hackrf_open(&cdev)); err != nil {
return nil, err
}
return newDevice(cdev), nil
}
// OpenBySerial opens a HackRF device by serial number (a suffix match is
// accepted by libhackrf). An empty serial opens the first device found.
func OpenBySerial(serial string) (*Device, error) {
var cs *C.char
if serial != "" {
cs = C.CString(serial)
defer C.free(unsafe.Pointer(cs))
}
var cdev *C.hackrf_device
if err := errorFrom(C.hackrf_open_by_serial(cs, &cdev)); err != nil {
return nil, err
}
return newDevice(cdev), nil
}
// Close closes the device, terminating all transfers and resetting it to IDLE.
// It is safe to call multiple times.
func (d *Device) Close() error {
if d.device == nil {
return nil
}
err := errorFrom(C.hackrf_close(d.device))
d.device = nil
if d.handle != 0 {
d.handle.Delete()
d.handle = 0
}
return err
}
// TransferBufferSize returns the size in bytes of a single USB transfer buffer.
func (d *Device) TransferBufferSize() int {
return int(C.hackrf_get_transfer_buffer_size(d.device))
}
// TransferQueueDepth returns the total number of USB transfer buffers.
func (d *Device) TransferQueueDepth() uint32 {
return uint32(C.hackrf_get_transfer_queue_depth(d.device))
}
// BoardIDRead reads the board ID of the device.
func (d *Device) BoardIDRead() (BoardID, error) {
var v C.uint8_t
if err := errorFrom(C.hackrf_board_id_read(d.device, &v)); err != nil {
return 0, err
}
return BoardID(v), nil
}
// VersionStringRead reads the device firmware version string.
func (d *Device) VersionStringRead() (string, error) {
const length = 255
buf := make([]byte, length+1)
r := C.hackrf_version_string_read(d.device, (*C.char)(unsafe.Pointer(&buf[0])), length)
if err := errorFrom(r); err != nil {
return "", err
}
return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil
}
// USBAPIVersionRead reads the device USB API version as a 16-bit MM.mm value
// (major in the high byte, minor in the low byte).
func (d *Device) USBAPIVersionRead() (uint16, error) {
var v C.uint16_t
if err := errorFrom(C.hackrf_usb_api_version_read(d.device, &v)); err != nil {
return 0, err
}
return uint16(v), nil
}
// BoardPartIDSerialNoRead reads the MCU part ID and serial number.
func (d *Device) BoardPartIDSerialNoRead() (PartIDSerialNo, error) {
var c C.read_partid_serialno_t
if err := errorFrom(C.hackrf_board_partid_serialno_read(d.device, &c)); err != nil {
return PartIDSerialNo{}, err
}
var p PartIDSerialNo
for i := 0; i < 2; i++ {
p.PartID[i] = uint32(c.part_id[i])
}
for i := 0; i < 4; i++ {
p.SerialNo[i] = uint32(c.serial_no[i])
}
return p, nil
}
// BoardRevRead reads the board revision. Requires USB API version 0x0106+.
func (d *Device) BoardRevRead() (BoardRev, error) {
v := C.uint8_t(C.BOARD_REV_UNDETECTED)
if err := errorFrom(C.hackrf_board_rev_read(d.device, &v)); err != nil {
return 0, err
}
return BoardRev(v), nil
}
// SupportedPlatformRead reads the platform bitfield supported by the firmware
// (a combination of the Platform* constants). Requires USB API version 0x0106+.
func (d *Device) SupportedPlatformRead() (uint32, error) {
var v C.uint32_t
if err := errorFrom(C.hackrf_supported_platform_read(d.device, &v)); err != nil {
return 0, err
}
return uint32(v), nil
}
// Reset resets the device. Requires USB API version 0x0102+.
func (d *Device) Reset() error {
return errorFrom(C.hackrf_reset(d.device))
}
// SetLEDs overrides the device LEDs from a bitfield (bit 0 = first LED).
// Requires USB API version 0x0107+.
func (d *Device) SetLEDs(state uint8) error {
return errorFrom(C.hackrf_set_leds(d.device, C.uint8_t(state)))
}
// SetUIEnable enables or disables the display on display-equipped devices
// (Rad1o, PortaPack). Requires USB API version 0x0104+.
func (d *Device) SetUIEnable(enable bool) error {
return errorFrom(C.hackrf_set_ui_enable(d.device, boolToUint8(enable)))
}
// SetUserBiasTOpts configures bias-tee behavior when changing RF states.
func (d *Device) SetUserBiasTOpts(req BiasTUserSettingReq) error {
var c C.hackrf_bias_t_user_settting_req
c.tx = req.TX.toC()
c.rx = req.RX.toC()
c.off = req.Off.toC()
return errorFrom(C.hackrf_set_user_bias_t_opts(d.device, &c))
}
func (s BiasTUserSetting) toC() C.hackrf_bool_user_settting {
var c C.hackrf_bool_user_settting
c.do_update = C.bool(s.DoUpdate)
c.change_on_mode_entry = C.bool(s.ChangeOnModeEntry)
c.enabled = C.bool(s.Enabled)
return c
}
func boolToUint8(b bool) C.uint8_t {
if b {
return 1
}
return 0
}