Add support for HackRF Pro (code name: Praline)

Co-authored-by: mndza <diego.hdmp@gmail.com>
Co-authored-by: Martin Ling <martin-git@earth.li>
Co-authored-by: Antoine van Gelder <antoine@greatscottgadgets.com>
This commit is contained in:
Michael Ossmann
2025-11-24 20:53:41 -05:00
parent 390837715b
commit 409acbc3c9
102 changed files with 10548 additions and 367 deletions

View File

@@ -32,6 +32,15 @@
#define REGISTER_INVALID 32767
enum parts {
PART_NONE = 0,
PART_MAX2837 = 1,
PART_SI5351C = 2,
PART_RFFC5072 = 3,
PART_MAX2831 = 4,
PART_GATEWARE = 5,
};
int parse_int(char* s, uint32_t* const value)
{
uint_fast8_t base = 10;
@@ -60,11 +69,30 @@ int parse_int(char* s, uint32_t* const value)
}
}
int max2837_read_register(hackrf_device* device, const uint16_t register_number)
int max283x_read_register(
hackrf_device* device,
const uint16_t register_number,
uint8_t part)
{
uint16_t register_value;
int result =
hackrf_max2837_read(device, (uint8_t) register_number, &register_value);
int result = HACKRF_SUCCESS;
switch (part) {
case PART_MAX2837:
result = hackrf_max2837_read(
device,
(uint8_t) register_number,
&register_value);
break;
case PART_MAX2831:
result = hackrf_max2831_read(
device,
(uint8_t) register_number,
&register_value);
break;
default:
return HACKRF_ERROR_INVALID_PARAM;
}
if (result == HACKRF_SUCCESS) {
printf("[%2d] -> 0x%03x\n", register_number, register_value);
@@ -76,13 +104,25 @@ int max2837_read_register(hackrf_device* device, const uint16_t register_number)
return result;
}
int max2837_read_registers(hackrf_device* device)
int max283x_read_registers(hackrf_device* device, uint8_t part)
{
uint16_t register_number;
uint16_t register_count;
int result = HACKRF_SUCCESS;
for (register_number = 0; register_number < 32; register_number++) {
result = max2837_read_register(device, register_number);
switch (part) {
case PART_MAX2837:
register_count = 32;
break;
case PART_MAX2831:
register_count = 16;
break;
default:
return HACKRF_ERROR_INVALID_PARAM;
}
for (register_number = 0; register_number < register_count; register_number++) {
result = max283x_read_register(device, register_number, part);
if (result != HACKRF_SUCCESS) {
break;
}
@@ -90,13 +130,30 @@ int max2837_read_registers(hackrf_device* device)
return result;
}
int max2837_write_register(
int max283x_write_register(
hackrf_device* device,
const uint16_t register_number,
const uint16_t register_value)
const uint16_t register_value,
uint8_t part)
{
int result = HACKRF_SUCCESS;
result = hackrf_max2837_write(device, (uint8_t) register_number, register_value);
switch (part) {
case PART_MAX2837:
result = hackrf_max2837_write(
device,
(uint8_t) register_number,
register_value);
break;
case PART_MAX2831:
result = hackrf_max2831_write(
device,
(uint8_t) register_number,
register_value);
break;
default:
return HACKRF_ERROR_INVALID_PARAM;
}
if (result == HACKRF_SUCCESS) {
printf("0x%03x -> [%2d]\n", register_value, register_number);
@@ -150,7 +207,7 @@ int si5351c_write_register(
if (result == HACKRF_SUCCESS) {
printf("0x%2x -> [%3d]\n", register_value, register_number);
} else {
printf("hackrf_max2837_write() failed: %s (%d)\n",
printf("hackrf_si5351c_write() failed: %s (%d)\n",
hackrf_error_name(result),
result);
}
@@ -360,22 +417,54 @@ int rffc5072_write_register(
return result;
}
enum parts {
PART_NONE = 0,
PART_MAX2837 = 1,
PART_SI5351C = 2,
PART_RFFC5072 = 3,
};
int fpga_spi_read_register(hackrf_device* device, const uint16_t register_number)
{
uint8_t register_value;
int result =
hackrf_fpga_spi_read(device, (uint8_t) register_number, &register_value);
if (result == HACKRF_SUCCESS) {
printf("[%2d] -> 0x%02x\n", register_number, register_value);
} else {
printf("hackrf_fpga_spi_read() failed: %s (%d)\n",
hackrf_error_name(result),
result);
}
return result;
}
int fpga_spi_write_register(
hackrf_device* device,
const uint16_t register_number,
const uint16_t register_value)
{
int result = HACKRF_SUCCESS;
result = hackrf_fpga_spi_write(device, (uint8_t) register_number, register_value);
if (result == HACKRF_SUCCESS) {
printf("0x%02x -> [%2d]\n", register_value, register_number);
} else {
printf("hackrf_fpga_spi_write() failed: %s (%d)\n",
hackrf_error_name(result),
result);
}
return result;
}
int read_register(hackrf_device* device, uint8_t part, const uint16_t register_number)
{
switch (part) {
case PART_MAX2837:
return max2837_read_register(device, register_number);
case PART_MAX2831:
return max283x_read_register(device, register_number, part);
case PART_SI5351C:
return si5351c_read_register(device, register_number);
case PART_RFFC5072:
return rffc5072_read_register(device, register_number);
case PART_GATEWARE:
return fpga_spi_read_register(device, register_number);
}
return HACKRF_ERROR_INVALID_PARAM;
}
@@ -384,7 +473,8 @@ int read_registers(hackrf_device* device, uint8_t part)
{
switch (part) {
case PART_MAX2837:
return max2837_read_registers(device);
case PART_MAX2831:
return max283x_read_registers(device, part);
case PART_SI5351C:
return si5351c_read_registers(device);
case PART_RFFC5072:
@@ -401,11 +491,18 @@ int write_register(
{
switch (part) {
case PART_MAX2837:
return max2837_write_register(device, register_number, register_value);
case PART_MAX2831:
return max283x_write_register(
device,
register_number,
register_value,
part);
case PART_SI5351C:
return si5351c_write_register(device, register_number, register_value);
case PART_RFFC5072:
return rffc5072_write_register(device, register_number, register_value);
case PART_GATEWARE:
return fpga_spi_write_register(device, register_number, register_value);
}
return HACKRF_ERROR_INVALID_PARAM;
}
@@ -465,19 +562,26 @@ static void usage()
printf("\t-w, --write <v>: write register specified by last -n argument with value <v>\n");
printf("\t-c, --config: print SI5351C multisynth configuration information\n");
printf("\t-d, --device <s>: specify a particular device by serial number\n");
printf("\t-m, --max2837: target MAX2837\n");
printf("\t-m, --max283x: target MAX283x\n");
printf("\t-s, --si5351c: target SI5351C\n");
printf("\t-f, --rffc5072: target RFFC5072\n");
printf("\t-g, --gateware: target gateware registers\n");
printf("\t-P, --fpga <n>: load the n-th bitstream to the FPGA\n");
printf("\t-1, --p1 <n>: P1 control\n");
printf("\t-2, --p2 <n>: P2 control\n");
printf("\t-C, --clkin <0/1>: CLKIN control (0 for P1_CLKIN, 1 for P22_CLKIN)\n");
printf("\t-N, --narrowband <0/1>: narrowband filter disable/enable\n");
printf("\t-S, --state: display M0 state\n");
printf("\t-T, --tx-underrun-limit <n>: set TX underrun limit in bytes (0 for no limit)\n");
printf("\t-R, --rx-overrun-limit <n>: set RX overrun limit in bytes (0 for no limit)\n");
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("\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");
printf("\thackrf_debug --rffc5072 -r # reads all rffc5072 registers\n");
printf("\thackrf_debug --max2837 -n 10 -w 22 # writes max2837 register 10 with 22 decimal\n");
printf("\thackrf_debug --max283x -n 10 -w 22 # writes max283x register 10 with 22 decimal\n");
printf("\thackrf_debug --state # displays M0 state\n");
}
@@ -489,19 +593,28 @@ static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{"max2837", no_argument, 0, 'm'},
{"max283x", no_argument, 0, 'm'},
{"si5351c", no_argument, 0, 's'},
{"rffc5072", no_argument, 0, 'f'},
{"gateware", no_argument, 0, 'g'},
{"fpga", required_argument, 0, 'P'},
{"p1", required_argument, 0, '1'},
{"p2", required_argument, 0, '2'},
{"clkin", required_argument, 0, 'C'},
{"narrowband", required_argument, 0, 'N'},
{"state", no_argument, 0, 'S'},
{"tx-underrun-limit", required_argument, 0, 'T'},
{"rx-overrun-limit", required_argument, 0, 'R'},
{"ui", required_argument, 0, 'u'},
{"leds", required_argument, 0, 'l'},
{"selftest", no_argument, 0, 't'},
{0, 0, 0, 0},
};
int main(int argc, char** argv)
{
int opt;
uint8_t board_id = BOARD_ID_UNDETECTED;
uint32_t register_number = REGISTER_INVALID;
uint32_t register_value;
hackrf_device* device = NULL;
@@ -518,8 +631,19 @@ int main(int argc, char** argv)
uint32_t led_state;
uint32_t tx_limit;
uint32_t rx_limit;
uint32_t p1_state;
uint32_t p2_state;
uint32_t clkin_state;
uint32_t narrowband_state;
uint32_t bitstream_index;
bool set_tx_limit = false;
bool set_rx_limit = false;
bool set_p1 = false;
bool set_p2 = false;
bool set_clkin = false;
bool set_narrowband = false;
bool set_fpga_bitstream = false;
bool read_selftest = false;
int result = hackrf_init();
if (result) {
@@ -532,7 +656,7 @@ int main(int argc, char** argv)
while ((opt = getopt_long(
argc,
argv,
"n:rw:d:cmsfST:R:h?u:l:",
"n:rw:d:cmsfg1:2:C:N:P:ST:R:h?u:l:t",
long_options,
&option_index)) != EOF) {
switch (opt) {
@@ -594,6 +718,39 @@ int main(int argc, char** argv)
part = PART_RFFC5072;
break;
case 'g':
if (part != PART_NONE) {
fprintf(stderr, "Only one part can be specified.'\n");
return EXIT_FAILURE;
}
part = PART_GATEWARE;
break;
case '1':
set_p1 = true;
result = parse_int(optarg, &p1_state);
break;
case '2':
set_p2 = true;
result = parse_int(optarg, &p2_state);
break;
case 'C':
set_clkin = true;
result = parse_int(optarg, &clkin_state);
break;
case 'N':
set_narrowband = true;
result = parse_int(optarg, &narrowband_state);
break;
case 'P':
set_fpga_bitstream = true;
result = parse_int(optarg, &bitstream_index);
break;
case 'u':
set_ui = true;
result = parse_int(optarg, &ui_enable);
@@ -603,6 +760,9 @@ int main(int argc, char** argv)
set_leds = true;
result = parse_int(optarg, &led_state);
break;
case 't':
read_selftest = true;
break;
case 'h':
case '?':
@@ -642,14 +802,16 @@ int main(int argc, char** argv)
}
if (!(write || read || dump_config || dump_state || set_tx_limit ||
set_rx_limit || set_ui || set_leds)) {
set_rx_limit || set_ui || set_leds || set_p1 || set_p2 || set_clkin ||
set_narrowband || set_fpga_bitstream || read_selftest)) {
fprintf(stderr, "Specify read, write, or config option.\n");
usage();
return EXIT_FAILURE;
}
if (part == PART_NONE && !set_ui && !dump_state && !set_tx_limit &&
!set_rx_limit && !set_leds) {
!set_rx_limit && !set_leds && !set_p1 && !set_p2 && !set_clkin &&
!set_narrowband && !set_fpga_bitstream && !read_selftest) {
fprintf(stderr, "Specify a part to read, write, or print config from.\n");
usage();
return EXIT_FAILURE;
@@ -663,6 +825,20 @@ int main(int argc, char** argv)
return EXIT_FAILURE;
}
if (part == PART_MAX2837) {
result = hackrf_board_id_read(device, &board_id);
if (result != HACKRF_SUCCESS) {
fprintf(stderr,
"hackrf_board_id_read() failed: %s (%d)\n",
hackrf_error_name(result),
result);
return EXIT_FAILURE;
}
if (board_id == BOARD_ID_PRALINE) {
part = PART_MAX2831;
}
}
if (write) {
result = write_register(device, part, register_number, register_value);
}
@@ -699,6 +875,56 @@ int main(int argc, char** argv)
}
}
if (set_p1) {
result = hackrf_set_p1_ctrl(device, p1_state);
if (result != HACKRF_SUCCESS) {
printf("hackrf_set_p1_ctrl() failed: %s (%d)\n",
hackrf_error_name(result),
result);
return EXIT_FAILURE;
}
}
if (set_p2) {
result = hackrf_set_p2_ctrl(device, p2_state);
if (result != HACKRF_SUCCESS) {
printf("hackrf_set_p2_ctrl() failed: %s (%d)\n",
hackrf_error_name(result),
result);
return EXIT_FAILURE;
}
}
if (set_clkin) {
result = hackrf_set_clkin_ctrl(device, clkin_state);
if (result != HACKRF_SUCCESS) {
printf("hackrf_set_clkin_ctrl() failed: %s (%d)\n",
hackrf_error_name(result),
result);
return EXIT_FAILURE;
}
}
if (set_narrowband) {
result = hackrf_set_narrowband_filter(device, narrowband_state);
if (result != HACKRF_SUCCESS) {
printf("hackrf_set_narrowband_filter() failed: %s (%d)\n",
hackrf_error_name(result),
result);
return EXIT_FAILURE;
}
}
if (set_fpga_bitstream) {
result = hackrf_set_fpga_bitstream(device, bitstream_index);
if (result != HACKRF_SUCCESS) {
printf("hackrf_set_fpga_bitstream() failed: %s (%d)\n",
hackrf_error_name(result),
result);
return EXIT_FAILURE;
}
}
if (dump_state) {
hackrf_m0_state state;
result = hackrf_get_m0_state(device, &state);
@@ -725,6 +951,19 @@ int main(int argc, char** argv)
result = hackrf_set_leds(device, led_state);
}
if (read_selftest) {
hackrf_selftest selftest;
result = hackrf_read_selftest(device, &selftest);
if (result != HACKRF_SUCCESS) {
printf("hackrf_read_selftest() failed: %s (%d)\n",
hackrf_error_name(result),
result);
return EXIT_FAILURE;
}
printf("Self-test result: %s\n", selftest.pass ? "PASS" : "FAIL");
printf("%s", selftest.msg);
}
result = hackrf_close(device);
if (result) {
printf("hackrf_close() failed: %s (%d)\n",