mirror of
https://github.com/greatscottgadgets/hackrf.git
synced 2026-03-03 05:55:18 +01:00
Merge pull request #1608 from greatscottgadgets/fix-selftests
Fix self-tests
This commit is contained in:
45
firmware/common/adc.c
Normal file
45
firmware/common/adc.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2025 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
#include <libopencm3/lpc43xx/adc.h>
|
||||
#include <libopencm3/lpc43xx/scu.h>
|
||||
|
||||
uint16_t adc_read(uint8_t pin)
|
||||
{
|
||||
bool alt_pin = (pin & 0x80);
|
||||
pin &= ~0x80;
|
||||
uint8_t pin_mask = (1 << pin);
|
||||
if (alt_pin) {
|
||||
SCU_ENAIO0 |= pin_mask;
|
||||
} else {
|
||||
SCU_ENAIO0 &= ~pin_mask;
|
||||
}
|
||||
ADC0_CR = ADC_CR_SEL(pin_mask) | ADC_CR_CLKDIV(45) | ADC_CR_PDN | ADC_CR_START(1);
|
||||
while (!(ADC0_GDR & ADC_DR_DONE) || (((ADC0_GDR >> 24) & 0x7) != pin))
|
||||
;
|
||||
return (ADC0_GDR >> 6) & 0x03FF;
|
||||
}
|
||||
|
||||
void adc_off(void)
|
||||
{
|
||||
ADC0_CR = 0;
|
||||
}
|
||||
30
firmware/common/adc.h
Normal file
30
firmware/common/adc.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2025 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ADC_H__
|
||||
#define __ADC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t adc_read(uint8_t pin);
|
||||
void adc_off(void);
|
||||
|
||||
#endif // __ADC_H__
|
||||
@@ -39,12 +39,10 @@
|
||||
#include "ice40_spi.h"
|
||||
#include "platform_detect.h"
|
||||
#include "clkin.h"
|
||||
#include "selftest.h"
|
||||
#include <libopencm3/lpc43xx/cgu.h>
|
||||
#include <libopencm3/lpc43xx/ccu.h>
|
||||
#include <libopencm3/lpc43xx/scu.h>
|
||||
#include <libopencm3/lpc43xx/ssp.h>
|
||||
#include <libopencm3/lpc43xx/creg.h>
|
||||
|
||||
#if (defined HACKRF_ONE || defined PRALINE)
|
||||
#include "portapack.h"
|
||||
@@ -898,29 +896,6 @@ void cpu_clock_init(void)
|
||||
CGU_BASE_SSP1_CLK =
|
||||
CGU_BASE_SSP1_CLK_AUTOBLOCK(1) | CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
#ifndef RAD1O
|
||||
/* Enable 32kHz oscillator */
|
||||
CREG_CREG0 &= ~(CREG_CREG0_PD32KHZ | CREG_CREG0_RESET32KHZ);
|
||||
CREG_CREG0 |= CREG_CREG0_EN32KHZ;
|
||||
|
||||
/* Allow 1ms to start up. */
|
||||
delay_us_at_mhz(1000, 204);
|
||||
|
||||
/* Use frequency monitor to check 32kHz oscillator is running. */
|
||||
CGU_FREQ_MON = CGU_FREQ_MON_RCNT(511) | CGU_FREQ_MON_CLK_SEL(CGU_SRC_32K);
|
||||
CGU_FREQ_MON |= CGU_FREQ_MON_MEAS_MASK;
|
||||
while (CGU_FREQ_MON & CGU_FREQ_MON_MEAS_MASK)
|
||||
;
|
||||
uint32_t count =
|
||||
(CGU_FREQ_MON & CGU_FREQ_MON_FCNT_MASK) >> CGU_FREQ_MON_FCNT_SHIFT;
|
||||
// We should see a single count, because 511 cycles of the 12MHz internal
|
||||
// RC oscillator corresponds to 1.39 cycles of the 32768Hz clock.
|
||||
selftest.rtc_osc_ok = (count == 1);
|
||||
if (!selftest.rtc_osc_ok) {
|
||||
selftest.report.pass = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE)
|
||||
/* Disable unused clocks */
|
||||
/* Start with PLLs */
|
||||
@@ -954,7 +929,7 @@ void cpu_clock_init(void)
|
||||
CCU1_CLK_APB1_CAN1_CFG = 0;
|
||||
CCU1_CLK_APB1_I2S_CFG = 0;
|
||||
CCU1_CLK_APB1_MOTOCONPWM_CFG = 0;
|
||||
CCU1_CLK_APB3_ADC0_CFG = 0;
|
||||
//CCU1_CLK_APB3_ADC0_CFG = 0;
|
||||
CCU1_CLK_APB3_ADC1_CFG = 0;
|
||||
CCU1_CLK_APB3_CAN0_CFG = 0;
|
||||
CCU1_CLK_APB3_DAC_CFG = 0;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "max2831.h"
|
||||
#include "max2831_regs.def" // private register def macros
|
||||
#include "selftest.h"
|
||||
#include "adc.h"
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
@@ -66,26 +67,6 @@ static void max2831_init(max2831_driver_t* const drv)
|
||||
|
||||
/* Write default register values to chip. */
|
||||
max2831_regs_commit(drv);
|
||||
|
||||
/* Disable lock detect output. */
|
||||
set_MAX2831_LOCK_DETECT_OUTPUT_EN(drv, false);
|
||||
max2831_regs_commit(drv);
|
||||
|
||||
// Read state of lock detect pin.
|
||||
bool initial = gpio_read(drv->gpio_ld);
|
||||
|
||||
// Enable lock detect output.
|
||||
set_MAX2831_LOCK_DETECT_OUTPUT_EN(drv, true);
|
||||
max2831_regs_commit(drv);
|
||||
|
||||
// Read new state of lock detect pin.
|
||||
bool new = gpio_read(drv->gpio_ld);
|
||||
|
||||
// If the pin state changed, we know our writes are working.
|
||||
selftest.max2831_ld_test_ok = initial != new;
|
||||
if (!selftest.max2831_ld_test_ok) {
|
||||
selftest.report.pass = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -181,6 +162,34 @@ void max2831_start(max2831_driver_t* const drv)
|
||||
{
|
||||
max2831_regs_commit(drv);
|
||||
max2831_set_mode(drv, MAX2831_MODE_STANDBY);
|
||||
|
||||
/* Read RSSI with ADC. */
|
||||
uint16_t rssi_1 = selftest.max2831_mux_rssi_1 = adc_read(1);
|
||||
|
||||
/* Switch to temperature sensor. */
|
||||
set_MAX2831_RSSI_MUX(drv, MAX2831_RSSI_MUX_TEMP);
|
||||
max2831_regs_commit(drv);
|
||||
|
||||
/* Read temperature. */
|
||||
uint16_t temp = selftest.max2831_mux_temp = adc_read(1);
|
||||
|
||||
/* Switch back to RSSI. */
|
||||
set_MAX2831_RSSI_MUX(drv, MAX2831_RSSI_MUX_RSSI);
|
||||
max2831_regs_commit(drv);
|
||||
|
||||
/* Read RSSI again. */
|
||||
uint16_t rssi_2 = selftest.max2831_mux_rssi_2 = adc_read(1);
|
||||
|
||||
/* If the ADC results are as expected, we know our writes are working. */
|
||||
bool rssi_1_good = (rssi_1 < 10);
|
||||
bool rssi_2_good = (rssi_2 < 10);
|
||||
bool temp_good = (temp > 100) && (temp < 500); // -40 to +85C
|
||||
|
||||
selftest.max2831_mux_test_ok = rssi_1_good & rssi_2_good & temp_good;
|
||||
|
||||
if (!selftest.max2831_mux_test_ok) {
|
||||
selftest.report.pass = false;
|
||||
}
|
||||
}
|
||||
|
||||
void max2831_tx(max2831_driver_t* const drv)
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
#include "firmware_info.h"
|
||||
#include "gpio_lpc.h"
|
||||
#include "hackrf_core.h"
|
||||
#include "adc.h"
|
||||
|
||||
#include <libopencm3/lpc43xx/scu.h>
|
||||
#include <libopencm3/lpc43xx/adc.h>
|
||||
|
||||
static board_id_t platform = BOARD_ID_UNDETECTED;
|
||||
static board_rev_t revision = BOARD_REV_UNDETECTED;
|
||||
@@ -64,23 +64,6 @@ static struct gpio_t gpio_led1 = GPIO(2, 1);
|
||||
static struct gpio_t gpio_led2 = GPIO(2, 2);
|
||||
static struct gpio_t gpio_led3 = GPIO(2, 8);
|
||||
|
||||
/*
|
||||
* Return 10-bit ADC result.
|
||||
*/
|
||||
uint16_t adc_read(uint8_t pin)
|
||||
{
|
||||
pin &= 0x7;
|
||||
uint8_t pin_mask = (1 << pin);
|
||||
ADC0_CR = ADC_CR_SEL(pin_mask) | ADC_CR_CLKDIV(45) | ADC_CR_PDN | ADC_CR_START(1);
|
||||
while (!(ADC0_GDR & ADC_DR_DONE) || (((ADC0_GDR >> 24) & 0x7) != pin)) {}
|
||||
return (ADC0_GDR >> 6) & 0x03FF;
|
||||
}
|
||||
|
||||
void adc_off(void)
|
||||
{
|
||||
ADC0_CR = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Starting with r6, HackRF One has pin straps on ADC pins that indicate
|
||||
* hardware revision. Those pins were unconnected prior to r6, so we test for
|
||||
|
||||
@@ -71,7 +71,7 @@ static const uint16_t rffc5071_regs_default[RFFC5071_NUM_REGS] = {
|
||||
0x0000, /* 1A */
|
||||
0x0000, /* 1B */
|
||||
0xc840, /* 1C */
|
||||
0x1000, /* 1D */
|
||||
0x0000, /* 1D, readsel = 0b0000 */
|
||||
0x0005,
|
||||
/* 1E */};
|
||||
|
||||
@@ -81,13 +81,13 @@ void rffc5071_init(rffc5071_driver_t* const drv)
|
||||
memcpy(drv->regs, rffc5071_regs_default, sizeof(drv->regs));
|
||||
drv->regs_dirty = 0x7fffffff;
|
||||
|
||||
selftest.mixer_id = rffc5071_reg_read(drv, RFFC5071_READBACK_REG);
|
||||
if ((selftest.mixer_id >> 3) != 2031) {
|
||||
selftest.report.pass = false;
|
||||
}
|
||||
|
||||
/* Write default register values to chip. */
|
||||
rffc5071_regs_commit(drv);
|
||||
|
||||
selftest.mixer_id = rffc5071_reg_read(drv, RFFC5071_READBACK_REG);
|
||||
if ((selftest.mixer_id >> 3) != 4416) {
|
||||
selftest.report.pass = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -28,7 +28,10 @@
|
||||
typedef struct {
|
||||
uint16_t mixer_id;
|
||||
#ifdef PRALINE
|
||||
bool max2831_ld_test_ok;
|
||||
uint16_t max2831_mux_rssi_1;
|
||||
uint16_t max2831_mux_temp;
|
||||
uint16_t max2831_mux_rssi_2;
|
||||
bool max2831_mux_test_ok;
|
||||
#else
|
||||
uint16_t max283x_readback_bad_value;
|
||||
uint16_t max283x_readback_expected_value;
|
||||
@@ -37,9 +40,6 @@ typedef struct {
|
||||
#endif
|
||||
uint8_t si5351_rev_id;
|
||||
bool si5351_readback_ok;
|
||||
#ifndef RAD1O
|
||||
bool rtc_osc_ok;
|
||||
#endif
|
||||
#ifdef PRALINE
|
||||
bool sgpio_rx_ok;
|
||||
bool xcvr_loopback_ok;
|
||||
|
||||
@@ -191,6 +191,7 @@ macro(DeclareTargets)
|
||||
${PATH_HACKRF_FIRMWARE_COMMON}/radio.c
|
||||
${PATH_HACKRF_FIRMWARE_COMMON}/selftest.c
|
||||
${PATH_HACKRF_FIRMWARE_COMMON}/m0_state.c
|
||||
${PATH_HACKRF_FIRMWARE_COMMON}/adc.c
|
||||
)
|
||||
|
||||
if(BOARD STREQUAL "RAD1O")
|
||||
|
||||
@@ -62,6 +62,7 @@ set(SRC_M4
|
||||
usb_api_sweep.c
|
||||
usb_api_selftest.c
|
||||
usb_api_ui.c
|
||||
usb_api_adc.c
|
||||
"${PATH_HACKRF_FIRMWARE_COMMON}/usb_queue.c"
|
||||
"${PATH_HACKRF_FIRMWARE_COMMON}/fault_handler.c"
|
||||
"${PATH_HACKRF_FIRMWARE_COMMON}/cpld_jtag.c"
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "usb_api_operacake.h"
|
||||
#include "usb_api_praline.h"
|
||||
#include "usb_api_selftest.h"
|
||||
#include "usb_api_adc.h"
|
||||
#include "operacake.h"
|
||||
#include "usb_api_sweep.h"
|
||||
#include "usb_api_transceiver.h"
|
||||
@@ -148,6 +149,7 @@ static usb_request_handler_fn vendor_request_handler[] = {
|
||||
NULL,
|
||||
#endif
|
||||
usb_vendor_request_read_selftest,
|
||||
usb_vendor_request_adc_read,
|
||||
};
|
||||
|
||||
static const uint32_t vendor_request_handler_count =
|
||||
|
||||
49
firmware/hackrf_usb/usb_api_adc.c
Normal file
49
firmware/hackrf_usb/usb_api_adc.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <usb_queue.h>
|
||||
#include "adc.h"
|
||||
#include "usb_api_adc.h"
|
||||
|
||||
usb_request_status_t usb_vendor_request_adc_read(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage)
|
||||
{
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
if ((endpoint->setup.index & ~0x80) > 7) {
|
||||
return USB_REQUEST_STATUS_STALL;
|
||||
}
|
||||
uint16_t value = adc_read(endpoint->setup.index);
|
||||
adc_off();
|
||||
endpoint->buffer[0] = value & 0xff;
|
||||
endpoint->buffer[1] = value >> 8;
|
||||
usb_transfer_schedule_block(
|
||||
endpoint->in,
|
||||
&endpoint->buffer,
|
||||
2,
|
||||
NULL,
|
||||
NULL);
|
||||
usb_transfer_schedule_ack(endpoint->out);
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
32
firmware/hackrf_usb/usb_api_adc.h
Normal file
32
firmware/hackrf_usb/usb_api_adc.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2025 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __USB_API_ADC_H__
|
||||
#define __USB_API_ADC_H__
|
||||
|
||||
#include <usb_type.h>
|
||||
#include <usb_request.h>
|
||||
|
||||
usb_request_status_t usb_vendor_request_adc_read(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage);
|
||||
|
||||
#endif // __USB_API_ADC_H__
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <usb_queue.h>
|
||||
#include <libopencm3/lpc43xx/cgu.h>
|
||||
#include "usb_api_selftest.h"
|
||||
#include "selftest.h"
|
||||
#include "platform_detect.h"
|
||||
@@ -74,8 +73,8 @@ void generate_selftest_report(void)
|
||||
append(&s, &c, selftest.si5351_readback_ok ? "OK" : "FAIL");
|
||||
append(&s, &c, "\n");
|
||||
#ifdef PRALINE
|
||||
append(&s, &c, "Transceiver: MAX2831, LD pin test: ");
|
||||
append(&s, &c, selftest.max2831_ld_test_ok ? "PASS" : "FAIL");
|
||||
append(&s, &c, "Transceiver: MAX2831, RSSI mux test: ");
|
||||
append(&s, &c, selftest.max2831_mux_test_ok ? "PASS" : "FAIL");
|
||||
append(&s, &c, "\n");
|
||||
#else
|
||||
append(&s, &c, "Transceiver: ");
|
||||
@@ -95,11 +94,6 @@ void generate_selftest_report(void)
|
||||
}
|
||||
append(&s, &c, "\n");
|
||||
#endif
|
||||
#ifndef RAD1O
|
||||
append(&s, &c, "32kHz oscillator: ");
|
||||
append(&s, &c, selftest.rtc_osc_ok ? "PASS" : "FAIL");
|
||||
append(&s, &c, "\n");
|
||||
#endif
|
||||
#ifdef PRALINE
|
||||
append(&s, &c, "SGPIO RX test: ");
|
||||
append(&s, &c, selftest.sgpio_rx_ok ? "PASS" : "FAIL");
|
||||
|
||||
@@ -577,6 +577,7 @@ static void usage()
|
||||
printf("\t-u, --ui <1/0>: enable/disable UI\n");
|
||||
printf("\t-l, --leds <state>: configure LED state (0 for all off, 1 for default)\n");
|
||||
printf("\t-t, --selftest: read self-test report\n");
|
||||
printf("\t-a, --adc <channel>: read value from an ADC channel. Add 0x80 for alternate pin\n");
|
||||
printf("\nExamples:\n");
|
||||
printf("\thackrf_debug --si5351c -n 0 -r # reads from si5351c register 0\n");
|
||||
printf("\thackrf_debug --si5351c -c # displays si5351c multisynth configuration\n");
|
||||
@@ -608,6 +609,7 @@ static struct option long_options[] = {
|
||||
{"ui", required_argument, 0, 'u'},
|
||||
{"leds", required_argument, 0, 'l'},
|
||||
{"selftest", no_argument, 0, 't'},
|
||||
{"adc", required_argument, 0, 'a'},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
@@ -636,6 +638,7 @@ int main(int argc, char** argv)
|
||||
uint32_t clkin_state;
|
||||
uint32_t narrowband_state;
|
||||
uint32_t bitstream_index;
|
||||
uint32_t adc_channel;
|
||||
bool set_tx_limit = false;
|
||||
bool set_rx_limit = false;
|
||||
bool set_p1 = false;
|
||||
@@ -644,6 +647,7 @@ int main(int argc, char** argv)
|
||||
bool set_narrowband = false;
|
||||
bool set_fpga_bitstream = false;
|
||||
bool read_selftest = false;
|
||||
bool read_adc = false;
|
||||
|
||||
int result = hackrf_init();
|
||||
if (result) {
|
||||
@@ -656,7 +660,7 @@ int main(int argc, char** argv)
|
||||
while ((opt = getopt_long(
|
||||
argc,
|
||||
argv,
|
||||
"n:rw:d:cmsfg1:2:C:N:P:ST:R:h?u:l:t",
|
||||
"n:rw:d:cmsfg1:2:C:N:P:ST:R:h?u:l:ta:",
|
||||
long_options,
|
||||
&option_index)) != EOF) {
|
||||
switch (opt) {
|
||||
@@ -764,6 +768,11 @@ int main(int argc, char** argv)
|
||||
read_selftest = true;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
read_adc = true;
|
||||
result = parse_int(optarg, &adc_channel);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case '?':
|
||||
usage();
|
||||
@@ -803,7 +812,7 @@ int main(int argc, char** argv)
|
||||
|
||||
if (!(write || read || dump_config || dump_state || set_tx_limit ||
|
||||
set_rx_limit || set_ui || set_leds || set_p1 || set_p2 || set_clkin ||
|
||||
set_narrowband || set_fpga_bitstream || read_selftest)) {
|
||||
set_narrowband || set_fpga_bitstream || read_selftest || read_adc)) {
|
||||
fprintf(stderr, "Specify read, write, or config option.\n");
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
@@ -811,7 +820,7 @@ int main(int argc, char** argv)
|
||||
|
||||
if (part == PART_NONE && !set_ui && !dump_state && !set_tx_limit &&
|
||||
!set_rx_limit && !set_leds && !set_p1 && !set_p2 && !set_clkin &&
|
||||
!set_narrowband && !set_fpga_bitstream && !read_selftest) {
|
||||
!set_narrowband && !set_fpga_bitstream && !read_selftest && !read_adc) {
|
||||
fprintf(stderr, "Specify a part to read, write, or print config from.\n");
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
@@ -964,6 +973,21 @@ int main(int argc, char** argv)
|
||||
printf("%s", selftest.msg);
|
||||
}
|
||||
|
||||
if (read_adc) {
|
||||
uint16_t value;
|
||||
result = hackrf_read_adc(device, adc_channel, &value);
|
||||
if (result != HACKRF_SUCCESS) {
|
||||
printf("hackrf_read_adc() failed: %s (%d)\n",
|
||||
hackrf_error_name(result),
|
||||
result);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("ADC0_%d (%s pin): %d\n",
|
||||
adc_channel & 0x7,
|
||||
adc_channel & 0x80 ? "alternate" : "dedicated",
|
||||
value);
|
||||
}
|
||||
|
||||
result = hackrf_close(device);
|
||||
if (result) {
|
||||
printf("hackrf_close() failed: %s (%d)\n",
|
||||
|
||||
@@ -109,6 +109,7 @@ typedef enum {
|
||||
HACKRF_VENDOR_REQUEST_SET_FPGA_BITSTREAM = 54,
|
||||
HACKRF_VENDOR_REQUEST_CLKIN_CTRL = 55,
|
||||
HACKRF_VENDOR_REQUEST_READ_SELFTEST = 56,
|
||||
HACKRF_VENDOR_REQUEST_READ_ADC = 57,
|
||||
} hackrf_vendor_request;
|
||||
|
||||
#define USB_CONFIG_STANDARD 0x1
|
||||
@@ -1244,6 +1245,35 @@ int ADDCALL hackrf_read_selftest(hackrf_device* device, hackrf_selftest* selftes
|
||||
}
|
||||
}
|
||||
|
||||
int ADDCALL hackrf_read_adc(hackrf_device* device, uint8_t adc_channel, uint16_t* value)
|
||||
{
|
||||
USB_API_REQUIRED(device, 0x0109);
|
||||
|
||||
int result;
|
||||
|
||||
if ((adc_channel & ~0x80) > 7) {
|
||||
return HACKRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
result = libusb_control_transfer(
|
||||
device->usb_device,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
HACKRF_VENDOR_REQUEST_READ_ADC,
|
||||
0,
|
||||
adc_channel,
|
||||
(unsigned char*) value,
|
||||
2,
|
||||
0);
|
||||
|
||||
if (result < 2) {
|
||||
last_libusb_error = result;
|
||||
return HACKRF_ERROR_LIBUSB;
|
||||
} else {
|
||||
*value = FROM_LE16(*value);
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
int ADDCALL hackrf_get_m0_state(hackrf_device* device, hackrf_m0_state* state)
|
||||
{
|
||||
USB_API_REQUIRED(device, 0x0106)
|
||||
|
||||
@@ -1354,6 +1354,20 @@ extern ADDAPI int ADDCALL hackrf_read_selftest(
|
||||
hackrf_device* device,
|
||||
hackrf_selftest* value);
|
||||
|
||||
/**
|
||||
* Read a value from an ADC channel
|
||||
*
|
||||
* @param[in] device device to query
|
||||
* @param[in] adc_channel ADC channel, e.g. 0 for ADC0_0. Add 0x80 to use an alternate pin.
|
||||
* @param[out] value Value read from ADC.
|
||||
* @return @ref HACKRF_SUCCESS on success or @ref hackrf_error variant
|
||||
* @ingroup debug
|
||||
*/
|
||||
extern ADDAPI int ADDCALL hackrf_read_adc(
|
||||
hackrf_device* device,
|
||||
uint8_t adc_channel,
|
||||
uint16_t* value);
|
||||
|
||||
/**
|
||||
* Set transmit underrun limit
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user