hackrf.js
Version:
Control HackRF devices from Node.js
738 lines • 27.5 kB
JavaScript
"use strict";
/**
* Main module, contains the USB interfacing code
* and user-facing API
*/
/** */
Object.defineProperty(exports, "__esModule", { value: true });
exports.HackrfDevice = exports.open = exports.listDevices = exports.defaultStreamOptions = void 0;
const util_1 = require("util");
const usb_1 = require("usb");
const constants_1 = require("./constants");
const util_2 = require("./util");
exports.defaultStreamOptions = {
transferCount: 4,
transferBufferSize: 262144,
};
// promisifiable + cancellable version of transfer
function transfer(endpoint, timeout, buffer) {
let transfer;
const promise = util_1.promisify(cb => transfer =
endpoint.makeTransfer(0, (error, _, length) => cb(error, length)).submit(buffer))();
return { promise: promise, cancel: () => transfer.cancel() };
}
async function poll(endpoint, callback, options) {
const opts = { ...exports.defaultStreamOptions, ...options };
const isOut = endpoint instanceof usb_1.InEndpoint;
const transfers = Array(opts.transferCount);
const buffers = [...transfers].map(() => Buffer.alloc(opts.transferBufferSize));
const arrays = buffers.map(b => new Int8Array(b.buffer, b.byteOffset, b.byteLength));
const submit = (i) => transfers[i] = transfer(endpoint, 0, buffers[i]);
const work = (async () => {
// Prepare
for (let i = 0; i < transfers.length; i++) {
if (isOut && callback(arrays[i]) === false)
return;
submit(i);
}
// Loop
while (true) {
const [length, i] = await Promise.race(transfers.map((x, i) => x.promise.then(length => [length, i])));
// FIXME: can length be smaller for isOut?
if (callback(isOut ? arrays[i] : arrays[i].subarray(0, length)) === false)
return;
submit(i);
}
})();
return transfers.reduce((p, x) => isOut ? p.then(() => x === null || x === void 0 ? void 0 : x.promise.then()) : p.finally(x === null || x === void 0 ? void 0 : x.cancel), work);
}
// libusb is not well-designed for the manual configuration case,
// and we need to use internals. See tessel/node-usb#377 for context
const getActiveConfig = (device) => device.__getConfigDescriptor().bConfigurationValue;
function detachKernelDrivers(handle) {
const { bNumInterfaces } = handle.__getConfigDescriptor();
for (let num = 0; num < bNumInterfaces; num++) {
let active;
try {
active = handle.__isKernelDriverActive(num);
}
catch (e) {
if (e instanceof usb_1.LibUSBException && e.errno === usb_1.LIBUSB_ERROR_NOT_SUPPORTED)
return;
throw e;
}
if (active)
handle.__detachKernelDriver(num);
}
}
function isValidDevice(device) {
const { idVendor, idProduct } = device.deviceDescriptor;
return idVendor === constants_1.USB_HACKRF_VID &&
Object.hasOwnProperty.call(constants_1.UsbBoardId, idProduct);
}
/**
* Return info about each HackRF device present.
*/
async function* listDevices() {
for (const device of usb_1.getDeviceList().filter(isValidDevice)) {
const { idProduct, iSerialNumber } = device.deviceDescriptor;
const info = { device, usbBoardId: idProduct };
if (iSerialNumber > 0) {
try {
device.open(false);
info.serialNumber = await util_1.promisify(cb => device.getStringDescriptor(iSerialNumber, cb))();
}
catch (e) {
}
finally {
device.close();
}
}
yield info;
}
}
exports.listDevices = listDevices;
/**
* Open the first device whose serial number ends with the passed suffix.
* If no suffix is passed, open the first device.
*
* @param serialNumber Serial number suffix to match
*/
async function open(serialNumber) {
var _a;
if (serialNumber) {
for await (const info of listDevices()) {
if ((_a = info.serialNumber) === null || _a === void 0 ? void 0 : _a.endsWith(serialNumber))
return HackrfDevice.open(info.device);
}
}
else {
const device = usb_1.findByIds(constants_1.USB_HACKRF_VID, constants_1.UsbBoardId.HACKRF_ONE) ||
usb_1.findByIds(constants_1.USB_HACKRF_VID, constants_1.UsbBoardId.JAWBREAKER) ||
usb_1.findByIds(constants_1.USB_HACKRF_VID, constants_1.UsbBoardId.RAD1O);
if (device)
return HackrfDevice.open(device);
}
throw new util_2.HackrfError(constants_1.ErrorCode.NOT_FOUND);
}
exports.open = open;
/**
* Reference to an open HackRF device
*
* This is mostly a direct API to the USB interface. Call
* [[close]] when no longer needed.
*
* Keep in mind some methods require a certain API version
* to be implemented by your device's firmware; this is noted
* in their documentation, and an `USB_API_VERSION` error will
* be thrown if you attempt to use them. [[usbApiVersion]]
* returns the version implemented by the firmware. It's
* strongly recommended to upgrade your device's firmware to
* the latest version to avoid problems and glitches.
*
* This API does strict validation of passed integers (they
* should be integers and be in-range). Gains, in particular,
* will be *rejected* instead of rounded down to the nearest
* step.
*/
class HackrfDevice {
constructor(handle, iface) {
this._open = true;
// DATA TRANSFERS
this._streaming = false;
this._stopRequested = false;
this.handle = handle;
this.iface = iface;
this.outEndpoint = iface.endpoint(2 | usb_1.LIBUSB_ENDPOINT_OUT);
if (this.outEndpoint.transferType !== usb_1.LIBUSB_TRANSFER_TYPE_BULK)
throw new util_2.HackrfError(constants_1.ErrorCode.LIBUSB);
this.inEndpoint = iface.endpoint(1 | usb_1.LIBUSB_ENDPOINT_IN);
if (this.inEndpoint.transferType !== usb_1.LIBUSB_TRANSFER_TYPE_BULK)
throw new util_2.HackrfError(constants_1.ErrorCode.LIBUSB);
}
/**
* Open the passed USB device
*
* This function does **not** validate the device,
* it's recommended to use the `open` module function
* instead of this function directly.
*
* @param device USB device (must not be open)
* @category Main
*/
static async open(device) {
device.open(false);
// FIXME: disabled because usb's API won't let us
// if (getActiveConfig(device) !== USB_CONFIG_STANDARD) {
detachKernelDrivers(device);
await util_1.promisify(cb => device.setConfiguration(constants_1.USB_CONFIG_STANDARD, cb))();
// }
detachKernelDrivers(device);
const iface = device.interface(0);
iface.claim();
try {
if (getActiveConfig(device) !== constants_1.USB_CONFIG_STANDARD)
throw new util_2.HackrfError(constants_1.ErrorCode.LIBUSB);
return new HackrfDevice(device, iface);
}
catch (e) {
await util_1.promisify(cb => iface.release(cb))();
device.close();
throw e;
}
}
get open() {
return this._open;
}
/**
* Release resources and close the USB device
*
* Unless the device is used until process exit, this **must** be
* called once when it's no longer needed.
*
* There must be no pending promises or an active stream when
* calling this. After return, no more methods should be called
* on this object.
*
* @category Main
*/
async close() {
await util_1.promisify(cb => this.iface.release(cb))();
this.handle.close();
this._open = false;
}
/**
* Version of the USB API implemented by the device's firmware
*
* In `0xAABB` form (`AA` = major, `BB` = minor).
*/
get usbApiVersion() {
return this.handle.deviceDescriptor.bcdDevice;
}
usbApiRequired(version) {
if (this.usbApiVersion < version)
throw new util_2.HackrfError(constants_1.ErrorCode.USB_API_VERSION);
}
// CONTROL TRANSFERS
controlTransferIn(bRequest, wValue, wIndex, length) {
return util_1.promisify(cb => this.handle.controlTransfer(usb_1.LIBUSB_ENDPOINT_IN | usb_1.LIBUSB_REQUEST_TYPE_VENDOR | usb_1.LIBUSB_RECIPIENT_DEVICE, bRequest, wValue, wIndex, length, cb))();
}
controlTransferOut(bRequest, wValue, wIndex, data = Buffer.alloc(0)) {
return util_1.promisify(cb => this.handle.controlTransfer(usb_1.LIBUSB_ENDPOINT_OUT | usb_1.LIBUSB_REQUEST_TYPE_VENDOR | usb_1.LIBUSB_RECIPIENT_DEVICE, bRequest, wValue, wIndex, data, cb))();
}
async setTransceiverMode(value) {
await this.controlTransferOut(constants_1.VendorRequest.SET_TRANSCEIVER_MODE, value, 0);
}
/**
* Query the firmware version
*
* @category Device info
*/
async getVersionString() {
const buf = await this.controlTransferIn(constants_1.VendorRequest.VERSION_STRING_READ, 0, 0, 255);
return buf.toString('utf-8');
}
/**
* @category Device info
*/
async getBoardId() {
const buf = await this.controlTransferIn(constants_1.VendorRequest.BOARD_ID_READ, 0, 0, 1);
return util_2.checkInLength(buf, 1).readUInt8();
}
/**
* @category Device info
*/
async getBoardPartIdSerialNo() {
const buf = await this.controlTransferIn(constants_1.VendorRequest.BOARD_PARTID_SERIALNO_READ, 0, 0, 24);
util_2.checkInLength(buf, 24);
const u32 = [0, 1, 2, 3, 4, 5].map(x => buf.readUInt32LE(x * 4));
return {
partId: u32.slice(0, 2),
serialNo: u32.slice(2, 6),
};
}
/**
* @category IC
*/
async max2837_read(register) {
const buf = await this.controlTransferIn(constants_1.VendorRequest.MAX2837_READ, 0, util_2.checkMax2837Reg(register), 2);
return util_2.checkInLength(buf, 2).readUInt16LE();
}
/**
* @category IC
*/
async max2837_write(register, value) {
await this.controlTransferOut(constants_1.VendorRequest.MAX2837_WRITE, util_2.checkMax2837Value(value), util_2.checkMax2837Reg(register));
}
/**
* @category IC
*/
async si5351c_read(register) {
const buf = await this.controlTransferIn(constants_1.VendorRequest.SI5351C_READ, 0, util_2.checkSi5351cReg(register), 1);
return util_2.checkInLength(buf, 1).readUInt8();
}
/**
* @category IC
*/
async si5351c_write(register, value) {
await this.controlTransferOut(constants_1.VendorRequest.SI5351C_WRITE, util_2.checkSi5351cValue(value), util_2.checkSi5351cReg(register));
}
/**
* @category IC
*/
async rffc5071_read(register) {
const buf = await this.controlTransferIn(constants_1.VendorRequest.RFFC5071_READ, 0, util_2.checkRffc5071Reg(register), 2);
return util_2.checkInLength(buf, 2).readUInt16LE();
}
/**
* @category IC
*/
async rffc5071_write(register, value) {
await this.controlTransferOut(constants_1.VendorRequest.RFFC5071_WRITE, util_2.checkRffc5071Value(value), util_2.checkRffc5071Reg(register));
}
/**
* @category Flash & CPLD
*/
async spiflash_erase() {
await this.controlTransferOut(constants_1.VendorRequest.SPIFLASH_ERASE, 0, 0);
}
/**
* @category Flash & CPLD
*/
async spiflash_write(address, data) {
util_2.checkSpiflashAddress(address);
await this.controlTransferOut(constants_1.VendorRequest.SPIFLASH_WRITE, address >>> 16, address & 0xFFFF, data);
}
/**
* @category Flash & CPLD
*/
async spiflash_read(address, length) {
util_2.checkSpiflashAddress(address);
const buf = await this.controlTransferIn(constants_1.VendorRequest.SPIFLASH_READ, address >>> 16, address & 0xFFFF, length);
return util_2.checkInLength(buf, length);
}
/**
* TODO
*
* Requires USB API 1.3.
*
* @category Flash & CPLD
*/
async spiflash_getStatus() {
this.usbApiRequired(0x0103);
const buf = await this.controlTransferIn(constants_1.VendorRequest.SPIFLASH_STATUS, 0, 0, 2);
return util_2.checkInLength(buf, 1); // FIXME
}
/**
* TODO
*
* Requires USB API 1.3.
*
* @category Flash & CPLD
*/
async spiflash_clearStatus() {
this.usbApiRequired(0x0103);
await this.controlTransferOut(constants_1.VendorRequest.SPIFLASH_CLEAR_STATUS, 0, 0);
}
/**
* Set baseband filter bandwidth in Hz
*
* Possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz
*
* @category Radio control
*/
async setBasebandFilterBandwidth(freqHz) {
util_2.checkBasebandFilterBw(util_2.checkU32(freqHz));
await this.controlTransferOut(constants_1.VendorRequest.BASEBAND_FILTER_BANDWIDTH_SET, freqHz & 0xffff, freqHz >>> 16);
}
/**
* Set the tuning frequency
*
* @category Radio control
*/
async setFrequency(freqHz) {
util_2.checkFreq(freqHz);
// convert Freq Hz 64bits to Freq MHz (32bits) & Freq Hz (32bits)
const FREQ_ONE_MHZ = 1000 * 1000;
const data = Buffer.alloc(8);
data.writeUInt32LE(freqHz / FREQ_ONE_MHZ, 0);
data.writeUInt32LE(freqHz % FREQ_ONE_MHZ, 4);
await this.controlTransferOut(constants_1.VendorRequest.SET_FREQ, 0, 0, data);
}
/**
* Set the tuning frequency (raw version)
*
* @param iFreqHz intermediate frequency
* @param loFreqHz front-end local oscillator frequency
* @param path image rejection filter path
* @category Radio control
*/
async setFrequencyExplicit(iFreqHz, loFreqHz, path) {
util_2.checkIFreq(iFreqHz);
if (path !== constants_1.RfPathFilter.BYPASS)
util_2.checkLoFreq(loFreqHz);
if (util_2.checkU32(path) > 2)
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
const data = Buffer.alloc(8 + 8 + 1);
data.writeBigUInt64LE(BigInt(iFreqHz), 0);
data.writeBigUInt64LE(BigInt(loFreqHz), 8);
data.writeUInt8(path, 16);
await this.controlTransferOut(constants_1.VendorRequest.SET_FREQ_EXPLICIT, 0, 0, data);
}
/**
* Set the sample rate (raw version)
*
* You should probably use [[setSampleRate]] instead of this
* function.
*
* For anti-aliasing, the baseband filter bandwidth is automatically set to the
* widest available setting that is no more than 75% of the sample rate. This
* happens every time the sample rate is set. If you want to override the
* baseband filter selection, you must do so after setting the sample rate.
*
* 2-20Mhz - as a fraction, i.e. freq 20000000 divider 2 -> 10Mhz
*
* @category Radio control
*/
async setSampleRateManual(freqHz, divider) {
const data = Buffer.alloc(8);
data.writeUInt32LE(freqHz, 0);
data.writeUInt32LE(divider, 4);
await this.controlTransferOut(constants_1.VendorRequest.SAMPLE_RATE_SET, 0, 0, data);
}
/**
* Set the sample rate
*
* For anti-aliasing, the baseband filter bandwidth is automatically set to the
* widest available setting that is no more than 75% of the sample rate. This
* happens every time the sample rate is set. If you want to override the
* baseband filter selection, you must do so after setting the sample rate.
*
* @param freqHz frequency in Hz, 2-20MHz (double)
*
* @category Radio control
*/
async setSampleRate(freqHz) {
return this.setSampleRateManual(...util_2.calcSampleRate(freqHz));
}
/**
* Enable / disable RX/TX RF external amplifier
*
* @category Radio control
*/
async setAmpEnable(value) {
await this.controlTransferOut(constants_1.VendorRequest.AMP_ENABLE, Number(value), 0);
}
/**
* Set RX LNA (IF) gain, 0-40dB in 8dB steps
*
* @category Radio control
*/
async setLnaGain(gainDb) {
if (util_2.checkU32(gainDb) > 40 || gainDb % 8)
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
const buf = await this.controlTransferIn(constants_1.VendorRequest.SET_LNA_GAIN, 0, gainDb, 1);
if (buf.length != 1 || !buf.readUInt8())
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
}
/**
* Set RX VGA (baseband) gain, 0-62dB in 2dB steps
*
* @category Radio control
*/
async setVgaGain(gainDb) {
if (util_2.checkU32(gainDb) > 62 || gainDb % 2)
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
const buf = await this.controlTransferIn(constants_1.VendorRequest.SET_VGA_GAIN, 0, gainDb, 1);
if (buf.length != 1 || !buf.readUInt8())
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
}
/**
* Set TX VGA (IF) gain, 0-47dB in 1dB steps
*
* @category Radio control
*/
async setTxVgaGain(gainDb) {
if (util_2.checkU32(gainDb) > 47)
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
const buf = await this.controlTransferIn(constants_1.VendorRequest.SET_TXVGA_GAIN, 0, gainDb, 1);
if (buf.length != 1 || !buf.readUInt8())
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
}
/**
* Antenna port power control
*
* @category Radio control
*/
async setAntennaEnable(value) {
await this.controlTransferOut(constants_1.VendorRequest.ANTENNA_ENABLE, Number(value), 0);
}
/**
* Enable / disable hardware sync
*
* Multiple boards can be made to syncronize
* their USB transfers through a GPIO connection
* between them.
*
* Requires USB API 1.2.
*
* @category Radio control
*/
async setHwSyncMode(value) {
this.usbApiRequired(0x0102);
await this.controlTransferOut(constants_1.VendorRequest.SET_HW_SYNC_MODE, Number(value), 0);
}
/**
* Reset the device
*
* Requires USB API 1.2.
*
* @category Main
*/
async reset() {
this.usbApiRequired(0x0102);
await this.controlTransferOut(constants_1.VendorRequest.RESET, 0, 0);
}
/**
* Initialize sweep mode
*
* Requires USB API 1.2.
*
* @param ranges is a list of `[start, stop]` pairs of frequencies in MHz,
* no more than [[MAX_SWEEP_RANGES]] entries.
* @param numBytes the number of sample bytes to capture after each tuning.
* @param stepWidth the width in Hz of the tuning step.
* @param offset number of Hz added to every tuning frequency.
* Use to select center frequency based on the expected usable bandwidth.
* @category Radio control
*/
async initSweep(ranges, numBytes, stepWidth, offset, style) {
this.usbApiRequired(0x0102);
if (!(ranges.length >= 1 && ranges.length <= constants_1.MAX_SWEEP_RANGES))
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
if (numBytes % constants_1.BYTES_PER_BLOCK || numBytes < constants_1.BYTES_PER_BLOCK)
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
if (stepWidth < 1)
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
if (util_2.checkU32(style) > 1)
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
const data = Buffer.alloc(9 + ranges.length * 4);
data.writeUInt32LE(util_2.checkU32(stepWidth), 0);
data.writeUInt32LE(util_2.checkU32(offset), 4);
data.writeUInt8(style, 8);
ranges.forEach(([start, stop], i) => {
data.writeUInt16LE(util_2.checkU16(start), 9 + i * 4);
data.writeUInt16LE(util_2.checkU16(stop), 9 + i * 4 + 2);
});
util_2.checkU32(numBytes);
await this.controlTransferOut(constants_1.VendorRequest.INIT_SWEEP, numBytes & 0xffff, (numBytes >>> 16) & 0xffff, data);
}
/**
* Retrieve list of Opera Cake board addresses (uint8, terminated by 0)
*
* Requires USB API 1.2.
*
* @category Opera Cake
*/
async getOperacakeBoards() {
this.usbApiRequired(0x0102);
const buf = await this.controlTransferIn(constants_1.VendorRequest.OPERACAKE_GET_BOARDS, 0, 0, 8);
return Array.from(util_2.checkInLength(buf, 8));
}
/**
* Set Opera Cake ports
*
* Requires USB API 1.2.
*
* @category Opera Cake
*/
async setOperacakePorts(address, portA, portB) {
this.usbApiRequired(0x0102);
if (util_2.checkU32(portA) > constants_1.OperacakePorts.PB4 || util_2.checkU32(portB) > constants_1.OperacakePorts.PB4)
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
// Check which side PA and PB are on
if ((portA <= constants_1.OperacakePorts.PA4 && portB <= constants_1.OperacakePorts.PA4) ||
(portA > constants_1.OperacakePorts.PA4 && portB > constants_1.OperacakePorts.PA4))
throw new util_2.HackrfError(constants_1.ErrorCode.INVALID_PARAM);
await this.controlTransferOut(constants_1.VendorRequest.OPERACAKE_SET_PORTS, util_2.checkU8(address), portA | (portB << 8));
}
/**
* Set Opera Cake [frequency-antenna ranges](https://github.com/mossmann/hackrf/wiki/Opera-Cake#opera-glasses)
*
* Requires USB API 1.3.
*
* @category Opera Cake
*/
async setOperacakeRanges(ranges) {
this.usbApiRequired(0x0103);
await this.controlTransferOut(constants_1.VendorRequest.OPERACAKE_SET_RANGES, 0, 0, ranges);
}
/**
* Test GPIO functionality of an Opera Cake
*
* Returns test result (uint16)
*
* Requires USB API 1.3.
*
* @category Opera Cake
*/
async operacakeGpioTest(address) {
this.usbApiRequired(0x0103);
const buf = await this.controlTransferIn(constants_1.VendorRequest.OPERACAKE_GPIO_TEST, address, 0, 2);
return util_2.checkInLength(buf, 1); // FIXME
}
/**
* Enable / disable clock output through CLKOUT
*
* Requires USB API 1.3.
*
* @category Radio control
*/
async setClkoutEnable(value) {
this.usbApiRequired(0x0103);
await this.controlTransferOut(constants_1.VendorRequest.CLKOUT_ENABLE, Number(value), 0);
}
// Disabled for now, see https://github.com/mossmann/hackrf/issues/609
// /**
// * Returns crc32 (uint32)
// *
// * Requires USB API 1.3.
// *
// * @category Flash & CPLD
// */
// async cpld_checksum() {
// this.usbApiRequired(0x0103)
// const buf = await this.controlTransferIn(VendorRequest.CPLD_CHECKSUM, 0, 0, 4)
// return checkInLength(buf, 4).readUInt32LE()
// }
/**
* Enable / disable PortaPack display
*
* Requires USB API 1.4.
*
* @category Radio control
*/
async setUiEnable(value) {
this.usbApiRequired(0x0104);
await this.controlTransferOut(constants_1.VendorRequest.UI_ENABLE, Number(value), 0);
}
/**
* Returns `true` if there's an active stream.
*/
get streaming() {
return this._streaming;
}
async _lockStream(callback) {
if (this._streaming)
throw new util_2.HackrfError(constants_1.ErrorCode.BUSY);
try {
this._streaming = true;
await callback();
}
finally {
this._streaming = false;
}
}
/**
* Requests stopping the active stream (if there is one)
*
* Calling this has the same effect as returning `false`
* the next time the callback gets called. Note that the
* stream doesn't finish instantly, you still need to
* wait for the promise to end. This is merely a convenience
* function.
*
* @category Main
*/
requestStop() {
// this waits till the next callback; for RX we could do a bit better
this._stopRequested = true;
}
async _stream(mode, endpoint, callback, options) {
await this._lockStream(async () => {
this._stopRequested = false;
try {
await this.setTransceiverMode(mode);
await poll(endpoint, array => {
if (this._stopRequested)
return false;
callback(array);
}, options);
}
finally {
await this.setTransceiverMode(constants_1.TransceiverMode.OFF);
}
});
}
/**
* Put the radio in TX mode and stream I/Q samples
*
* The supplied callback will be regularly called with an
* `Int8Array` buffer to fill before return. Every two
* values of the buffer form an I/Q sample. Different
* buffers may be passed or reused, so avoid storing
* references to them after return.
*
* To request ending the stream, return `false` from the
* callback or use [[requestStop]].
*
* This throws if there's another stream in progress.
*
* @category Main
*/
async transmit(callback, options) {
await this._stream(constants_1.TransceiverMode.TRANSMIT, this.outEndpoint, callback, options);
}
/**
* Put the radio in RX mode and stream I/Q samples
*
* The supplied callback will be regularly called with an
* `Int8Array` buffer. Every two values of the buffer
* form a received I/Q sample. The buffer may be overwritten
* later, so avoid storing any reference to it; instead
* make a copy of the data if needed.
*
* To request ending the stream, return `false` from the
* callback or use [[requestStop]].
*
* This throws if there's another stream in progress.
*
* @category Main
*/
async receive(callback, options) {
await this._stream(constants_1.TransceiverMode.RECEIVE, this.inEndpoint, callback, options);
}
/**
* Put the radio in sweep RX mode and stream I/Q samples
*
* Like [[receive]], but with frequency sweep active.
* You should call [[initSweep]] first.
*
* Requires USB API 1.4.
*
* @category Main
*/
async sweepReceive(callback, options) {
this.usbApiRequired(0x0104);
await this._stream(constants_1.TransceiverMode.RX_SWEEP, this.inEndpoint, callback, options);
}
/**
* Put the radio in CPLD firmware upgrade mode and
* write the payload
*
* This throws if there's another stream in progress.
*
* The device will need to be reset after this.
*
* @category Flash & CPLD
*/
async cpld_write(data, chunkSize = 512) {
await this._lockStream(async () => {
await this.setTransceiverMode(constants_1.TransceiverMode.CPLD_UPDATE);
for (let i = 0; i < data.length; i += chunkSize)
await util_1.promisify(cb => this.outEndpoint.transfer(data.subarray(i, i + chunkSize), cb))();
});
}
}
exports.HackrfDevice = HackrfDevice;
//# sourceMappingURL=interface.js.map