Add USB vendor request to read M0 state, and host support for doing so.
This adds a `hackrf_debug [-S|--state]` option, and the necessary plumbing to libhackrf and the M4 firmware to support it. The USB API and libhackrf versions are bumped to reflect the changes.
This commit is contained in:
@ -35,6 +35,7 @@ set(SRC_M4
|
|||||||
hackrf_usb.c
|
hackrf_usb.c
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/tuning.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/tuning.c"
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/streaming.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/streaming.c"
|
||||||
|
m0_state.c
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/usb.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/usb.c"
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/usb_request.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/usb_request.c"
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/usb_standard_request.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/usb_standard_request.c"
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include "usb_api_transceiver.h"
|
#include "usb_api_transceiver.h"
|
||||||
#include "usb_api_ui.h"
|
#include "usb_api_ui.h"
|
||||||
#include "usb_bulk_buffer.h"
|
#include "usb_bulk_buffer.h"
|
||||||
|
#include "m0_state.h"
|
||||||
#include "cpld_xc2c.h"
|
#include "cpld_xc2c.h"
|
||||||
#include "portapack.h"
|
#include "portapack.h"
|
||||||
|
|
||||||
@ -114,6 +115,7 @@ static usb_request_handler_fn vendor_request_handler[] = {
|
|||||||
usb_vendor_request_operacake_set_mode,
|
usb_vendor_request_operacake_set_mode,
|
||||||
usb_vendor_request_operacake_get_mode,
|
usb_vendor_request_operacake_get_mode,
|
||||||
usb_vendor_request_operacake_set_dwell_times,
|
usb_vendor_request_operacake_set_dwell_times,
|
||||||
|
usb_vendor_request_get_m0_state,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t vendor_request_handler_count =
|
static const uint32_t vendor_request_handler_count =
|
||||||
|
44
firmware/hackrf_usb/m0_state.c
Normal file
44
firmware/hackrf_usb/m0_state.c
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 Great Scott Gadgets
|
||||||
|
*
|
||||||
|
* 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 "m0_state.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <usb_request.h>
|
||||||
|
#include <usb_queue.h>
|
||||||
|
|
||||||
|
usb_request_status_t usb_vendor_request_get_m0_state(
|
||||||
|
usb_endpoint_t* const endpoint,
|
||||||
|
const usb_transfer_stage_t stage
|
||||||
|
) {
|
||||||
|
if( stage == USB_TRANSFER_STAGE_SETUP )
|
||||||
|
{
|
||||||
|
usb_transfer_schedule_block(
|
||||||
|
endpoint->in,
|
||||||
|
(void*) &m0_state,
|
||||||
|
sizeof(m0_state),
|
||||||
|
NULL, NULL);
|
||||||
|
usb_transfer_schedule_ack(endpoint->out);
|
||||||
|
return USB_REQUEST_STATUS_OK;
|
||||||
|
} else {
|
||||||
|
return USB_REQUEST_STATUS_OK;
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,9 @@
|
|||||||
#ifndef __M0_STATE_H__
|
#ifndef __M0_STATE_H__
|
||||||
#define __M0_STATE_H__
|
#define __M0_STATE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <usb_request.h>
|
||||||
|
|
||||||
struct m0_state {
|
struct m0_state {
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t tx;
|
uint32_t tx;
|
||||||
@ -33,4 +36,7 @@ struct m0_state {
|
|||||||
*/
|
*/
|
||||||
extern volatile struct m0_state m0_state;
|
extern volatile struct m0_state m0_state;
|
||||||
|
|
||||||
|
usb_request_status_t usb_vendor_request_get_m0_state(
|
||||||
|
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||||
|
|
||||||
#endif/*__M0_STATE_H__*/
|
#endif/*__M0_STATE_H__*/
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
#define USB_PRODUCT_ID (0xFFFF)
|
#define USB_PRODUCT_ID (0xFFFF)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define USB_API_VERSION (0x0105)
|
#define USB_API_VERSION (0x0106)
|
||||||
|
|
||||||
#define USB_WORD(x) (x & 0xFF), ((x >> 8) & 0xFF)
|
#define USB_WORD(x) (x & 0xFF), ((x >> 8) & 0xFF)
|
||||||
|
|
||||||
|
@ -377,6 +377,12 @@ int write_register(hackrf_device* device, uint8_t part,
|
|||||||
return HACKRF_ERROR_INVALID_PARAM;
|
return HACKRF_ERROR_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_state(hackrf_m0_state *state) {
|
||||||
|
printf("M0 state:\n");
|
||||||
|
printf("Offset: %u bytes\n", state->offset);
|
||||||
|
printf("TX: %u\n", state->tx);
|
||||||
|
}
|
||||||
|
|
||||||
static void usage() {
|
static void usage() {
|
||||||
printf("\nUsage:\n");
|
printf("\nUsage:\n");
|
||||||
printf("\t-h, --help: this help\n");
|
printf("\t-h, --help: this help\n");
|
||||||
@ -388,12 +394,14 @@ static void usage() {
|
|||||||
printf("\t-m, --max2837: target MAX2837\n");
|
printf("\t-m, --max2837: target MAX2837\n");
|
||||||
printf("\t-s, --si5351c: target SI5351C\n");
|
printf("\t-s, --si5351c: target SI5351C\n");
|
||||||
printf("\t-f, --rffc5072: target RFFC5072\n");
|
printf("\t-f, --rffc5072: target RFFC5072\n");
|
||||||
|
printf("\t-S, --state: display M0 state\n");
|
||||||
printf("\t-u, --ui <1/0>: enable/disable UI\n");
|
printf("\t-u, --ui <1/0>: enable/disable UI\n");
|
||||||
printf("\nExamples:\n");
|
printf("\nExamples:\n");
|
||||||
printf("\thackrf_debug --si5351c -n 0 -r # reads from si5351c register 0\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 --si5351c -c # displays si5351c multisynth configuration\n");
|
||||||
printf("\thackrf_debug --rffc5072 -r # reads all rffc5072 registers\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 --max2837 -n 10 -w 22 # writes max2837 register 10 with 22 decimal\n");
|
||||||
|
printf("\thackrf_debug --state # displays M0 state\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
@ -406,6 +414,7 @@ static struct option long_options[] = {
|
|||||||
{ "max2837", no_argument, 0, 'm' },
|
{ "max2837", no_argument, 0, 'm' },
|
||||||
{ "si5351c", no_argument, 0, 's' },
|
{ "si5351c", no_argument, 0, 's' },
|
||||||
{ "rffc5072", no_argument, 0, 'f' },
|
{ "rffc5072", no_argument, 0, 'f' },
|
||||||
|
{ "state", no_argument, 0, 'S' },
|
||||||
{ "ui", required_argument, 0, 'u' },
|
{ "ui", required_argument, 0, 'u' },
|
||||||
{ 0, 0, 0, 0 },
|
{ 0, 0, 0, 0 },
|
||||||
};
|
};
|
||||||
@ -419,6 +428,7 @@ int main(int argc, char** argv) {
|
|||||||
bool read = false;
|
bool read = false;
|
||||||
bool write = false;
|
bool write = false;
|
||||||
bool dump_config = false;
|
bool dump_config = false;
|
||||||
|
bool dump_state = false;
|
||||||
uint8_t part = PART_NONE;
|
uint8_t part = PART_NONE;
|
||||||
const char* serial_number = NULL;
|
const char* serial_number = NULL;
|
||||||
bool set_ui = false;
|
bool set_ui = false;
|
||||||
@ -430,7 +440,7 @@ int main(int argc, char** argv) {
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
while( (opt = getopt_long(argc, argv, "n:rw:d:cmsfh?u:", long_options, &option_index)) != EOF ) {
|
while( (opt = getopt_long(argc, argv, "n:rw:d:cmsfSh?u:", long_options, &option_index)) != EOF ) {
|
||||||
switch( opt ) {
|
switch( opt ) {
|
||||||
case 'n':
|
case 'n':
|
||||||
result = parse_int(optarg, ®ister_number);
|
result = parse_int(optarg, ®ister_number);
|
||||||
@ -449,6 +459,10 @@ int main(int argc, char** argv) {
|
|||||||
dump_config = true;
|
dump_config = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'S':
|
||||||
|
dump_state = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
serial_number = optarg;
|
serial_number = optarg;
|
||||||
break;
|
break;
|
||||||
@ -517,13 +531,13 @@ int main(int argc, char** argv) {
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(write || read || dump_config || set_ui)) {
|
if(!(write || read || dump_config || dump_state || set_ui)) {
|
||||||
fprintf(stderr, "Specify read, write, or config option.\n");
|
fprintf(stderr, "Specify read, write, or config option.\n");
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(part == PART_NONE && !set_ui) {
|
if(part == PART_NONE && !set_ui && !dump_state) {
|
||||||
fprintf(stderr, "Specify a part to read, write, or print config from.\n");
|
fprintf(stderr, "Specify a part to read, write, or print config from.\n");
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -551,6 +565,16 @@ int main(int argc, char** argv) {
|
|||||||
si5351c_read_configuration(device);
|
si5351c_read_configuration(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(dump_state) {
|
||||||
|
hackrf_m0_state state;
|
||||||
|
result = hackrf_get_m0_state(device, &state);
|
||||||
|
if(result != HACKRF_SUCCESS) {
|
||||||
|
printf("hackrf_get_m0_state() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
print_state(&state);
|
||||||
|
}
|
||||||
|
|
||||||
if(set_ui) {
|
if(set_ui) {
|
||||||
result = hackrf_set_ui_enable(device, ui_enable);
|
result = hackrf_set_ui_enable(device, ui_enable);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
project(libhackrf C)
|
project(libhackrf C)
|
||||||
set(MAJOR_VERSION 0)
|
set(MAJOR_VERSION 0)
|
||||||
set(MINOR_VERSION 6)
|
set(MINOR_VERSION 7)
|
||||||
set(PACKAGE libhackrf)
|
set(PACKAGE libhackrf)
|
||||||
set(VERSION_STRING ${MAJOR_VERSION}.${MINOR_VERSION})
|
set(VERSION_STRING ${MAJOR_VERSION}.${MINOR_VERSION})
|
||||||
set(VERSION ${VERSION_STRING})
|
set(VERSION ${VERSION_STRING})
|
||||||
|
@ -92,6 +92,7 @@ typedef enum {
|
|||||||
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_MODE = 38,
|
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_MODE = 38,
|
||||||
HACKRF_VENDOR_REQUEST_OPERACAKE_GET_MODE = 39,
|
HACKRF_VENDOR_REQUEST_OPERACAKE_GET_MODE = 39,
|
||||||
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_DWELL_TIMES = 40,
|
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_DWELL_TIMES = 40,
|
||||||
|
HACKRF_VENDOR_REQUEST_GET_M0_STATE = 41,
|
||||||
} hackrf_vendor_request;
|
} hackrf_vendor_request;
|
||||||
|
|
||||||
#define USB_CONFIG_STANDARD 0x1
|
#define USB_CONFIG_STANDARD 0x1
|
||||||
@ -1007,6 +1008,31 @@ int ADDCALL hackrf_rffc5071_write(hackrf_device* device, uint8_t register_number
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ADDCALL hackrf_get_m0_state(hackrf_device* device, hackrf_m0_state* state)
|
||||||
|
{
|
||||||
|
USB_API_REQUIRED(device, 0x0106)
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = libusb_control_transfer(
|
||||||
|
device->usb_device,
|
||||||
|
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||||
|
HACKRF_VENDOR_REQUEST_GET_M0_STATE,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(unsigned char*)state,
|
||||||
|
sizeof(hackrf_m0_state),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if( result < sizeof(hackrf_m0_state) )
|
||||||
|
{
|
||||||
|
last_libusb_error = result;
|
||||||
|
return HACKRF_ERROR_LIBUSB;
|
||||||
|
} else {
|
||||||
|
return HACKRF_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int ADDCALL hackrf_spiflash_erase(hackrf_device* device)
|
int ADDCALL hackrf_spiflash_erase(hackrf_device* device)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
@ -155,6 +155,14 @@ typedef struct {
|
|||||||
uint8_t port;
|
uint8_t port;
|
||||||
} hackrf_operacake_freq_range;
|
} hackrf_operacake_freq_range;
|
||||||
|
|
||||||
|
/** State of the SGPIO loop running on the M0 core. */
|
||||||
|
typedef struct {
|
||||||
|
/** Current offset in the buffer. */
|
||||||
|
uint32_t offset;
|
||||||
|
/** TX flag. */
|
||||||
|
uint32_t tx;
|
||||||
|
} hackrf_m0_state;
|
||||||
|
|
||||||
struct hackrf_device_list {
|
struct hackrf_device_list {
|
||||||
char **serial_numbers;
|
char **serial_numbers;
|
||||||
enum hackrf_usb_board_id *usb_board_ids;
|
enum hackrf_usb_board_id *usb_board_ids;
|
||||||
@ -193,6 +201,8 @@ extern ADDAPI int ADDCALL hackrf_stop_rx(hackrf_device* device);
|
|||||||
extern ADDAPI int ADDCALL hackrf_start_tx(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* tx_ctx);
|
extern ADDAPI int ADDCALL hackrf_start_tx(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* tx_ctx);
|
||||||
extern ADDAPI int ADDCALL hackrf_stop_tx(hackrf_device* device);
|
extern ADDAPI int ADDCALL hackrf_stop_tx(hackrf_device* device);
|
||||||
|
|
||||||
|
extern ADDAPI int ADDCALL hackrf_get_m0_state(hackrf_device* device, hackrf_m0_state* value);
|
||||||
|
|
||||||
/* return HACKRF_TRUE if success */
|
/* return HACKRF_TRUE if success */
|
||||||
extern ADDAPI int ADDCALL hackrf_is_streaming(hackrf_device* device);
|
extern ADDAPI int ADDCALL hackrf_is_streaming(hackrf_device* device);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user