mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-07-08 10:14:46 +02:00
add sddc source prototype + add new ATV decoder + fix windows builds
This commit is contained in:
116
source_modules/sddc_source/libsddc/src/fx3_boot.c
Normal file
116
source_modules/sddc_source/libsddc/src/fx3_boot.c
Normal file
@ -0,0 +1,116 @@
|
||||
#include "fx3_boot.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define FX3_TIMEOUT 1000
|
||||
#define FX3_VENDOR_REQUEST 0xA0
|
||||
#define FX3_MAX_BLOCK_SIZE 0x1000
|
||||
|
||||
int sddc_fx3_boot_mem_read(libusb_device_handle* dev, uint32_t addr, uint8_t* data, uint16_t len) {
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, FX3_VENDOR_REQUEST, addr & 0xFFFF, addr >> 16, data, len, FX3_TIMEOUT);
|
||||
}
|
||||
|
||||
int sddc_fx3_boot_mem_write(libusb_device_handle* dev, uint32_t addr, const uint8_t* data, uint16_t len) {
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, FX3_VENDOR_REQUEST, addr & 0xFFFF, addr >> 16, data, len, FX3_TIMEOUT);
|
||||
}
|
||||
|
||||
int sddc_fx3_boot_run(libusb_device_handle* dev, uint32_t entry) {
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, FX3_VENDOR_REQUEST, entry & 0xFFFF, entry >> 16, NULL, 0, FX3_TIMEOUT);
|
||||
}
|
||||
|
||||
int sddc_fx3_boot_upload_firmware(libusb_device_handle* dev, const char* path) {
|
||||
// Open the firmware image
|
||||
FILE* fw = fopen(path, "rb");
|
||||
if (!fw) {
|
||||
fprintf(stderr, "Failed to open firmware image\n");
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Read the signature
|
||||
char sign[2];
|
||||
int read = fread(sign, 2, 1, fw);
|
||||
if (read != 1) {
|
||||
fprintf(stderr, "Failed to read firmware image signature: %d\n", read);
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Check the signature
|
||||
if (sign[0] != 'C' || sign[1] != 'Y') {
|
||||
fprintf(stderr, "Firmware image has invalid signature\n");
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Skip useless metadata
|
||||
int err = fseek(fw, 2, SEEK_CUR);
|
||||
if (err) {
|
||||
fprintf(stderr, "Invalid firmware image: %d\n", err);
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Preallocate data buffer
|
||||
int bufferSize = 0x10000;
|
||||
uint8_t* buffer = malloc(bufferSize);
|
||||
|
||||
// Read every section
|
||||
while (1) {
|
||||
// Read the section size
|
||||
uint32_t sizeWords;
|
||||
read = fread(&sizeWords, sizeof(uint32_t), 1, fw);
|
||||
if (read != 1) {
|
||||
fprintf(stderr, "Invalid firmware image section size\n");
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
uint32_t size = sizeWords << 2;
|
||||
|
||||
// Read the section address
|
||||
uint32_t addr;
|
||||
read = fread(&addr, sizeof(uint32_t), 1, fw);
|
||||
if (read != 1) {
|
||||
fprintf(stderr, "Invalid firmware image section address\n");
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// If the section is a termination section, run the code at the given address
|
||||
if (!size) {
|
||||
sddc_fx3_boot_run(dev, addr);
|
||||
break;
|
||||
}
|
||||
|
||||
// Re-allocate buffer if needed
|
||||
if (size > bufferSize) {
|
||||
bufferSize = size;
|
||||
realloc(buffer, bufferSize);
|
||||
}
|
||||
|
||||
// Read the section data
|
||||
read = fread(buffer, 1, size, fw);
|
||||
if (read != size) {
|
||||
fprintf(stderr, "Failed to read section data: %d\n", read);
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Upload it to the chip
|
||||
for (int i = 0; i < size; i += FX3_MAX_BLOCK_SIZE) {
|
||||
int left = size - i;
|
||||
err = sddc_fx3_boot_mem_write(dev, addr + i, &buffer[i], (left > FX3_MAX_BLOCK_SIZE) ? FX3_MAX_BLOCK_SIZE : left);
|
||||
if (err < LIBUSB_SUCCESS) {
|
||||
fprintf(stderr, "Failed to write to device memory: %d\n", err);
|
||||
fclose(fw);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Checksum stuff and verification ideally
|
||||
|
||||
// Close the firmware image
|
||||
fclose(fw);
|
||||
|
||||
// Return successfully
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
39
source_modules/sddc_source/libsddc/src/fx3_boot.h
Normal file
39
source_modules/sddc_source/libsddc/src/fx3_boot.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include <libusb.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Read data from the device's memory.
|
||||
* @param dev Device to read data from.
|
||||
* @param addr Start address of the data in the device's memory.
|
||||
* @param data Buffer to write the data into.
|
||||
* @param len Number of bytes to read.
|
||||
* @return libusb error code.
|
||||
*/
|
||||
int sddc_fx3_boot_mem_read(libusb_device_handle* dev, uint32_t addr, uint8_t* data, uint16_t len);
|
||||
|
||||
/**
|
||||
* Write data to the device's memory.
|
||||
* @param dev Device to write data to.
|
||||
* @param addr Start address of the data in the device's memory.
|
||||
* @param data Buffer to write the data into.
|
||||
* @param len Number of bytes to read.
|
||||
* @return libusb error code.
|
||||
*/
|
||||
int sddc_fx3_boot_mem_write(libusb_device_handle* dev, uint32_t addr, const uint8_t* data, uint16_t len);
|
||||
|
||||
/**
|
||||
* Execute code on the device.
|
||||
* @param dev Device to execute code on.
|
||||
* @param entry Entry point of the code.
|
||||
* @return libusb error code.
|
||||
*/
|
||||
int sddc_fx3_boot_run(libusb_device_handle* dev, uint32_t entry);
|
||||
|
||||
/**
|
||||
* Parse, upload and execute a firmware image.
|
||||
* @param dev Device to upload the firmware to.
|
||||
* @param path Path to the firmware image.
|
||||
* @return libusb error code.
|
||||
*/
|
||||
int sddc_fx3_boot_upload_firmware(libusb_device_handle* dev, const char* path);
|
451
source_modules/sddc_source/libsddc/src/sddc.c
Normal file
451
source_modules/sddc_source/libsddc/src/sddc.c
Normal file
@ -0,0 +1,451 @@
|
||||
#include <sddc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <libusb.h>
|
||||
#include <stdio.h>
|
||||
#include "usb_interface.h"
|
||||
|
||||
struct sddc_dev {
|
||||
// USB handles
|
||||
struct libusb_device_handle* openDev;
|
||||
|
||||
// Device info
|
||||
sddc_devinfo_t info;
|
||||
|
||||
// Device state
|
||||
bool running;
|
||||
uint32_t samplerate;
|
||||
uint64_t tunerFreq;
|
||||
sddc_gpio_t gpioState;
|
||||
};
|
||||
|
||||
struct libusb_context* ctx = NULL;
|
||||
char* sddc_firmware_path = NULL;
|
||||
bool sddc_is_init = false;
|
||||
|
||||
void sddc_init() {
|
||||
// If already initialized, do nothing
|
||||
if (sddc_is_init) { return; }
|
||||
|
||||
// If the firmware isn't already found, find it
|
||||
if (!sddc_firmware_path) {
|
||||
// TODO: Find the firmware
|
||||
}
|
||||
|
||||
// Init libusb
|
||||
libusb_init(&ctx);
|
||||
}
|
||||
|
||||
const char* sddc_model_to_string(sddc_model_t model) {
|
||||
switch (model) {
|
||||
case SDDC_MODEL_BBRF103: return "BBRF103";
|
||||
case SDDC_MODEL_HF103: return "HF103";
|
||||
case SDDC_MODEL_RX888: return "RX888";
|
||||
case SDDC_MODEL_RX888_MK2: return "RX888 MK2";
|
||||
case SDDC_MODEL_RX999: return "RX999";
|
||||
case SDDC_MODEL_RXLUCY: return "RXLUCY";
|
||||
case SDDC_MODEL_RX888_MK3: return "RX888 MK3";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char* sddc_error_to_string(sddc_error_t error) {
|
||||
switch (error) {
|
||||
case SDDC_ERROR_NOT_IMPLEMENTED: return "Not Implemented";
|
||||
case SDDC_ERROR_FIRMWARE_UPLOAD_FAILED: return "Firmware Upload Failed";
|
||||
case SDDC_ERROR_NOT_FOUND: return "Not Found";
|
||||
case SDDC_ERROR_USB_ERROR: return "USB Error";
|
||||
case SDDC_ERROR_TIMEOUT: return "Timeout";
|
||||
case SDDC_SUCCESS: return "Success";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
sddc_error_t sddc_set_firmware_path(const char* path) {
|
||||
// Free the old path if it exists
|
||||
if (sddc_firmware_path) { free(sddc_firmware_path); }
|
||||
|
||||
// Allocate the new path
|
||||
sddc_firmware_path = malloc(strlen(path) + 1);
|
||||
|
||||
// Copy the new path
|
||||
strcpy(sddc_firmware_path, path);
|
||||
|
||||
// TODO: Check if the file path exists
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
int sddc_get_device_list(sddc_devinfo_t** dev_list) {
|
||||
// Initialize libsddc in case it isn't already
|
||||
sddc_init();
|
||||
|
||||
// Get a list of USB devices
|
||||
libusb_device** devices;
|
||||
int devCount = libusb_get_device_list(ctx, &devices);
|
||||
if (devCount < 0 || !devices) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Initialize all uninitialized devices
|
||||
bool uninit = false;
|
||||
for (int i = 0; i < devCount; i++) {
|
||||
// Get the device from the list
|
||||
libusb_device* dev = devices[i];
|
||||
|
||||
// Get the device descriptor. Fail silently on error as it might not even be a SDDC device.
|
||||
struct libusb_device_descriptor desc;
|
||||
int err = libusb_get_device_descriptor(dev, &desc);
|
||||
if (err != LIBUSB_SUCCESS) { continue; }
|
||||
|
||||
// If it's not an uninitialized device, go to next device
|
||||
if (desc.idVendor != SDDC_UNINIT_VID || desc.idProduct != SDDC_UNINIT_PID) { continue; }
|
||||
|
||||
// Initialize the device
|
||||
printf("Found uninitialized device, initializing...\n");
|
||||
// TODO: Check that the firmware path is valid
|
||||
sddc_error_t serr = sddc_init_device(dev, sddc_firmware_path);
|
||||
if (serr != SDDC_SUCCESS) { continue; }
|
||||
|
||||
// Set the flag to wait the devices to start up
|
||||
uninit = true;
|
||||
}
|
||||
|
||||
// If some uninitialized devices were found
|
||||
if (uninit) {
|
||||
// Free the device list
|
||||
libusb_free_device_list(devices, 1);
|
||||
|
||||
// Wait for the devices to show back up
|
||||
#ifdef _WIN32
|
||||
Sleep(SDDC_INIT_SEARCH_DELAY_MS);
|
||||
#else
|
||||
usleep(SDDC_INIT_SEARCH_DELAY_MS * 1000);
|
||||
#endif
|
||||
|
||||
// Attempt to list devices again
|
||||
devCount = libusb_get_device_list(ctx, &devices);
|
||||
if (devCount < 0 || !devices) { return SDDC_ERROR_USB_ERROR; }
|
||||
}
|
||||
|
||||
// Allocate the device list
|
||||
*dev_list = malloc(devCount * sizeof(sddc_devinfo_t));
|
||||
|
||||
// Check each device
|
||||
int found = 0;
|
||||
libusb_device_handle* openDev;
|
||||
for (int i = 0; i < devCount; i++) {
|
||||
// Get the device from the list
|
||||
libusb_device* dev = devices[i];
|
||||
|
||||
// Get the device descriptor. Fail silently on error as it might not even be a SDDC device.
|
||||
struct libusb_device_descriptor desc;
|
||||
int err = libusb_get_device_descriptor(dev, &desc);
|
||||
if (err != LIBUSB_SUCCESS) { continue; }
|
||||
|
||||
// If the device is not an SDDC device, go to next device
|
||||
if (desc.idVendor != SDDC_VID || desc.idProduct != SDDC_PID) { continue; }
|
||||
|
||||
// Open the device
|
||||
err = libusb_open(dev, &openDev);
|
||||
if (err != LIBUSB_SUCCESS) {
|
||||
fprintf(stderr, "Failed to open device: %d\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create entry
|
||||
sddc_devinfo_t* info = &((*dev_list)[found]);
|
||||
|
||||
// Get the serial number
|
||||
err = libusb_get_string_descriptor_ascii(openDev, desc.iSerialNumber, info->serial, SDDC_SERIAL_MAX_LEN-1);
|
||||
if (err < LIBUSB_SUCCESS) {
|
||||
printf("Failed to get descriptor: %d\n", err);
|
||||
libusb_close(openDev);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the hardware info
|
||||
sddc_hwinfo_t hwinfo;
|
||||
err = sddc_fx3_get_info(openDev, &hwinfo, 0);
|
||||
if (err < LIBUSB_SUCCESS) {
|
||||
printf("Failed to get device info: %d\n", err);
|
||||
libusb_close(openDev);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save the hardware info
|
||||
info->model = (sddc_model_t)hwinfo.model;
|
||||
info->firmwareMajor = hwinfo.firmwareConfigH;
|
||||
info->firmwareMinor = hwinfo.firmwareConfigL;
|
||||
|
||||
// Close the device
|
||||
libusb_close(openDev);
|
||||
|
||||
// Increment device counter
|
||||
found++;
|
||||
}
|
||||
|
||||
// Free the libusb device list
|
||||
libusb_free_device_list(devices, 1);
|
||||
|
||||
// Return the number of devices found
|
||||
return found;
|
||||
}
|
||||
|
||||
void sddc_free_device_list(sddc_devinfo_t* dev_list) {
|
||||
// Free the device list if it exists
|
||||
if (dev_list) { free(dev_list); };
|
||||
}
|
||||
|
||||
sddc_error_t sddc_open(const char* serial, sddc_dev_t** dev) {
|
||||
// Initialize libsddc in case it isn't already
|
||||
sddc_init();
|
||||
|
||||
// Get a list of USB devices
|
||||
libusb_device** devices;
|
||||
int devCount = libusb_get_device_list(ctx, &devices);
|
||||
if (devCount < 0 || !devices) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Initialize all uninitialized devices
|
||||
bool uninit = false;
|
||||
for (int i = 0; i < devCount; i++) {
|
||||
// Get the device from the list
|
||||
libusb_device* dev = devices[i];
|
||||
|
||||
// Get the device descriptor. Fail silently on error as it might not even be a SDDC device.
|
||||
struct libusb_device_descriptor desc;
|
||||
int err = libusb_get_device_descriptor(dev, &desc);
|
||||
if (err != LIBUSB_SUCCESS) { continue; }
|
||||
|
||||
// If it's not an uninitialized device, go to next device
|
||||
if (desc.idVendor != SDDC_UNINIT_VID || desc.idProduct != SDDC_UNINIT_PID) { continue; }
|
||||
|
||||
// Initialize the device
|
||||
printf("Found uninitialized device, initializing...\n");
|
||||
// TODO: Check that the firmware path is valid
|
||||
sddc_error_t serr = sddc_init_device(dev, sddc_firmware_path);
|
||||
if (serr != SDDC_SUCCESS) { continue; }
|
||||
|
||||
// Set the flag to wait the devices to start up
|
||||
uninit = true;
|
||||
}
|
||||
|
||||
// If some uninitialized devices were found
|
||||
if (uninit) {
|
||||
// Free the device list
|
||||
libusb_free_device_list(devices, 1);
|
||||
|
||||
// Wait for the devices to show back up
|
||||
#ifdef _WIN32
|
||||
Sleep(SDDC_INIT_SEARCH_DELAY_MS);
|
||||
#else
|
||||
usleep(SDDC_INIT_SEARCH_DELAY_MS * 1000);
|
||||
#endif
|
||||
|
||||
// Attempt to list devices again
|
||||
devCount = libusb_get_device_list(ctx, &devices);
|
||||
if (devCount < 0 || !devices) { return SDDC_ERROR_USB_ERROR; }
|
||||
}
|
||||
|
||||
// Search through all USB device
|
||||
bool found = false;
|
||||
libusb_device_handle* openDev;
|
||||
for (int i = 0; i < devCount; i++) {
|
||||
// Get the device from the list
|
||||
libusb_device* dev = devices[i];
|
||||
|
||||
// Get the device descriptor. Fail silently on error as it might not even be a SDDC device.
|
||||
struct libusb_device_descriptor desc;
|
||||
int err = libusb_get_device_descriptor(dev, &desc);
|
||||
if (err != LIBUSB_SUCCESS) { continue; }
|
||||
|
||||
// If the device is not an SDDC device, go to next device
|
||||
if (desc.idVendor != SDDC_VID || desc.idProduct != SDDC_PID) { continue; }
|
||||
|
||||
// Open the device
|
||||
err = libusb_open(dev, &openDev);
|
||||
if (err != LIBUSB_SUCCESS) {
|
||||
fprintf(stderr, "Failed to open device: %d\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the serial number
|
||||
char dserial[SDDC_SERIAL_MAX_LEN];
|
||||
err = libusb_get_string_descriptor_ascii(openDev, desc.iSerialNumber, dserial, SDDC_SERIAL_MAX_LEN-1);
|
||||
if (err < LIBUSB_SUCCESS) {
|
||||
printf("Failed to get descriptor: %d\n", err);
|
||||
libusb_close(openDev);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compare the serial number and give up if not a match
|
||||
if (strcmp(dserial, serial)) { continue; }
|
||||
|
||||
// Get the device info
|
||||
// TODO
|
||||
|
||||
// Set the found flag and stop searching
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Free the libusb device list
|
||||
libusb_free_device_list(devices, true);
|
||||
|
||||
// If the device was not found, give up
|
||||
if (!found) { return SDDC_ERROR_NOT_FOUND; }
|
||||
|
||||
// Claim the interface
|
||||
libusb_claim_interface(openDev, 0);
|
||||
|
||||
// Allocate the device object
|
||||
*dev = malloc(sizeof(sddc_dev_t));
|
||||
|
||||
// Initialize the device object
|
||||
(*dev)->openDev = openDev;
|
||||
//(*dev)->info = ; //TODO
|
||||
(*dev)->running = false;
|
||||
(*dev)->samplerate = 128e6;
|
||||
(*dev)->tunerFreq = 100e6;
|
||||
(*dev)->gpioState = SDDC_GPIO_SHUTDOWN | SDDC_GPIO_SEL0; // ADC shutdown and HF port selected
|
||||
|
||||
// Stop everything in case the device is partially started
|
||||
printf("Stopping...\n");
|
||||
sddc_stop(*dev);
|
||||
|
||||
// TODO: Setup all of the other state
|
||||
sddc_gpio_put(*dev, SDDC_GPIO_SEL0, false);
|
||||
sddc_gpio_put(*dev, SDDC_GPIO_SEL1, true);
|
||||
sddc_gpio_put(*dev, SDDC_GPIO_VHF_EN, true);
|
||||
sddc_tuner_start((*dev)->openDev, 16e6);
|
||||
sddc_tuner_tune((*dev)->openDev, 100e6);
|
||||
sddc_fx3_set_param((*dev)->openDev, SDDC_PARAM_R82XX_ATT, 15);
|
||||
sddc_fx3_set_param((*dev)->openDev, SDDC_PARAM_R83XX_VGA, 9);
|
||||
sddc_fx3_set_param((*dev)->openDev, SDDC_PARAM_AD8340_VGA, 5);
|
||||
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
void sddc_close(sddc_dev_t* dev) {
|
||||
// Stop everything
|
||||
sddc_stop(dev);
|
||||
|
||||
// Release the interface
|
||||
libusb_release_interface(dev->openDev, 0);
|
||||
|
||||
// Close the USB device
|
||||
libusb_close(dev->openDev);
|
||||
|
||||
// Free the device struct
|
||||
free(dev);
|
||||
}
|
||||
|
||||
sddc_range_t sddc_get_samplerate_range(sddc_dev_t* dev) {
|
||||
// All devices have the same samplerate range
|
||||
sddc_range_t range = { 8e6, 128e6, 0 };
|
||||
return range;
|
||||
}
|
||||
|
||||
int sddc_gpio_set(sddc_dev_t* dev, sddc_gpio_t gpios) {
|
||||
// Update the state
|
||||
dev->gpioState = gpios;
|
||||
|
||||
// Push to the device
|
||||
sddc_fx3_gpio(dev->openDev, gpios);
|
||||
}
|
||||
|
||||
int sddc_gpio_put(sddc_dev_t* dev, sddc_gpio_t gpios, bool value) {
|
||||
// Update the state of the given GPIOs only
|
||||
return sddc_gpio_set(dev, (dev->gpioState & (~gpios)) | (value ? gpios : 0));
|
||||
}
|
||||
|
||||
sddc_error_t sddc_set_samplerate(sddc_dev_t* dev, uint32_t samplerate) {
|
||||
// Update the state
|
||||
dev->samplerate = samplerate;
|
||||
|
||||
// If running, send the new sampling rate to the device
|
||||
if (dev->running) {
|
||||
int err = sddc_adc_set_samplerate(dev->openDev, samplerate);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
}
|
||||
|
||||
// Return successfully
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_set_dithering(sddc_dev_t* dev, bool enabled) {
|
||||
// Update the GPIOs according to the desired state
|
||||
int err = sddc_gpio_put(dev, SDDC_GPIO_DITHER, enabled);
|
||||
return (err < LIBUSB_SUCCESS) ? SDDC_ERROR_USB_ERROR : SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_set_randomizer(sddc_dev_t* dev, bool enabled) {
|
||||
// Update the GPIOs according to the desired state
|
||||
int err = sddc_gpio_put(dev, SDDC_GPIO_RANDOM, enabled);
|
||||
return (err < LIBUSB_SUCCESS) ? SDDC_ERROR_USB_ERROR : SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_set_tuner_frequency(sddc_dev_t* dev, uint64_t frequency) {
|
||||
// Update the state
|
||||
dev->tunerFreq = frequency;
|
||||
|
||||
// If running, send the new frequency to the device
|
||||
if (dev->running) {
|
||||
int err = sddc_tuner_tune(dev->openDev, frequency);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
}
|
||||
|
||||
// Return successfully
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_start(sddc_dev_t* dev) {
|
||||
// De-assert the shutdown pin
|
||||
int err = sddc_gpio_put(dev, SDDC_GPIO_SHUTDOWN, false);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Start the tuner (TODO: Check if in VHF mode)
|
||||
|
||||
// Start the ADC
|
||||
err = sddc_adc_set_samplerate(dev->openDev, dev->samplerate);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Start the FX3
|
||||
err = sddc_fx3_start(dev->openDev);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Update the state
|
||||
dev->running = true;
|
||||
|
||||
// Return successfully
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_stop(sddc_dev_t* dev) {
|
||||
// Stop the FX3
|
||||
int err = sddc_fx3_stop(dev->openDev);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Stop the tuner
|
||||
err = sddc_tuner_stop(dev->openDev);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Stop the ADC
|
||||
err = sddc_adc_set_samplerate(dev->openDev, 0);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Set the GPIOs for standby mode
|
||||
err = sddc_gpio_put(dev, SDDC_GPIO_SHUTDOWN, true);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Update the state
|
||||
dev->running = false;
|
||||
|
||||
// Return successfully
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_rx(sddc_dev_t* dev, int16_t* samples, int count) {
|
||||
// Read samples from the device
|
||||
int bytesRead = 0;
|
||||
int err = libusb_bulk_transfer(dev->openDev, LIBUSB_ENDPOINT_IN | 1, samples, count * sizeof(int16_t), &bytesRead, SDDC_TIMEOUT_MS);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
return SDDC_SUCCESS;
|
||||
}
|
92
source_modules/sddc_source/libsddc/src/usb_interface.c
Normal file
92
source_modules/sddc_source/libsddc/src/usb_interface.c
Normal file
@ -0,0 +1,92 @@
|
||||
#include "usb_interface.h"
|
||||
#include "fx3_boot.h"
|
||||
#include <stdio.h>
|
||||
|
||||
sddc_error_t sddc_init_device(libusb_device* dev, const char* firmware) {
|
||||
// Open the device
|
||||
libusb_device_handle* openDev;
|
||||
int err = libusb_open(dev, &openDev);
|
||||
if (err != LIBUSB_SUCCESS) {
|
||||
printf("Failed to open device: %d\n", err);
|
||||
return SDDC_ERROR_USB_ERROR;
|
||||
}
|
||||
|
||||
// Attempt to upload the firmware
|
||||
err = sddc_fx3_boot_upload_firmware(openDev, firmware);
|
||||
if (err) {
|
||||
fprintf(stderr, "Failed to upload firmware to uninitialized device\n");
|
||||
return SDDC_ERROR_FIRMWARE_UPLOAD_FAILED;
|
||||
}
|
||||
|
||||
// Close the device
|
||||
libusb_close(openDev);
|
||||
|
||||
// Return successfully
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
int sddc_fx3_start(libusb_device_handle* dev) {
|
||||
// Send the start command
|
||||
uint32_t dummy;
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_START, 0, 0, &dummy, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_stop(libusb_device_handle* dev) {
|
||||
// Send the stop command
|
||||
uint32_t dummy;
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_STOP, 0, 0, &dummy, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_get_info(libusb_device_handle* dev, sddc_hwinfo_t* info, char enableDebug) {
|
||||
// Fetch the info data
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_GET_INFO, enableDebug, 0, info, sizeof(sddc_hwinfo_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_gpio(libusb_device_handle* dev, sddc_gpio_t gpio) {
|
||||
// Send the GPIO state
|
||||
uint32_t dword = gpio;
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_GPIO, 0, 0, &dword, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_i2c_write(libusb_device_handle* dev, uint8_t addr, uint16_t reg, const uint8_t* data, uint16_t len) {
|
||||
// Send the I2C data
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_I2C_W, addr, reg, data, len, SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_i2c_read(libusb_device_handle* dev, uint8_t addr, uint16_t reg, const uint8_t* data, uint16_t len) {
|
||||
// Fetch the I2C data
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_I2C_R, addr, reg, data, len, SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_reset(libusb_device_handle* dev) {
|
||||
// Send the reset command
|
||||
uint32_t dummy;
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_RESET, 0, 0, &dummy, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_set_param(libusb_device_handle* dev, sddc_param_t param, uint16_t value) {
|
||||
// Send the parameter
|
||||
uint32_t dummy;
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_SET_PARAM, value, param, &dummy, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_adc_set_samplerate(libusb_device_handle* dev, uint32_t samplerate) {
|
||||
// Send the samplerate
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_ADC_SET_RATE, 0, 0, &samplerate, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_tuner_start(libusb_device_handle* dev, uint32_t refFreq) {
|
||||
// Send the reset command
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_TUNER_START, 0, 0, &refFreq, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_tuner_tune(libusb_device_handle* dev, uint64_t frequency) {
|
||||
// Send the reset command
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_TUNER_TUNE, 0, 0, &frequency, sizeof(uint64_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_tuner_stop(libusb_device_handle* dev) {
|
||||
// Send the reset command
|
||||
uint32_t dummy; // Because the shitty firmware absolute wants data to stop the tuner, this is dumb...
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_TUNER_STOP, 0, 0, &dummy, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
168
source_modules/sddc_source/libsddc/src/usb_interface.h
Normal file
168
source_modules/sddc_source/libsddc/src/usb_interface.h
Normal file
@ -0,0 +1,168 @@
|
||||
#pragma once
|
||||
#include <sddc.h>
|
||||
#include <stdint.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#define SDDC_UNINIT_VID 0x04B4
|
||||
#define SDDC_UNINIT_PID 0x00F3
|
||||
#define SDDC_VID 0x04B4
|
||||
#define SDDC_PID 0x00F1
|
||||
|
||||
#define SDDC_INIT_SEARCH_DELAY_MS 1000
|
||||
#define SDDC_TIMEOUT_MS 1000
|
||||
|
||||
enum sddc_command {
|
||||
SDDC_CMD_FX3_START = 0xAA,
|
||||
SDDC_CMD_FX3_STOP = 0xAB,
|
||||
SDDC_CMD_FX3_GET_INFO = 0xAC,
|
||||
SDDC_CMD_FX3_GPIO = 0xAD,
|
||||
SDDC_CMD_FX3_I2C_W = 0xAE,
|
||||
SDDC_CMD_FX3_I2C_R = 0xAF,
|
||||
SDDC_CMD_FX3_RESET = 0xB1,
|
||||
SDDC_CMD_FX3_SET_PARAM = 0xB6,
|
||||
SDDC_CMD_ADC_SET_RATE = 0xB2,
|
||||
SDDC_CMD_TUNER_START = 0xB4,
|
||||
SDDC_CMD_TUNER_TUNE = 0xB5,
|
||||
SDDC_CMD_TUNER_STOP = 0xB8,
|
||||
SDDC_CMD_READ_DEBUG = 0xBA
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct sddc_hwinfo {
|
||||
uint8_t model;
|
||||
uint8_t firmwareConfigH;
|
||||
uint8_t firmwareConfigL;
|
||||
uint8_t vendorRequestCount;
|
||||
};
|
||||
typedef struct sddc_hwinfo sddc_hwinfo_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
enum sddc_gpio {
|
||||
SDDC_GPIO_NONE = 0,
|
||||
SDDC_GPIO_ATT_LE = (1 << 0),
|
||||
SDDC_GPIO_ATT_CLK = (1 << 1),
|
||||
SDDC_GPIO_ATT_DATA = (1 << 2),
|
||||
SDDC_GPIO_SEL0 = (1 << 3),
|
||||
SDDC_GPIO_SEL1 = (1 << 4),
|
||||
SDDC_GPIO_SHUTDOWN = (1 << 5),
|
||||
SDDC_GPIO_DITHER = (1 << 6),
|
||||
SDDC_GPIO_RANDOM = (1 << 7),
|
||||
SDDC_GPIO_BIAST_HF = (1 << 8),
|
||||
SDDC_GPIO_BIAST_VHF = (1 << 9),
|
||||
SDDC_GPIO_LED_YELLOW = (1 << 10),
|
||||
SDDC_GPIO_LED_RED = (1 << 11),
|
||||
SDDC_GPIO_LED_BLUE = (1 << 12),
|
||||
SDDC_GPIO_ATT_SEL0 = (1 << 13),
|
||||
SDDC_GPIO_ATT_SEL1 = (1 << 14),
|
||||
SDDC_GPIO_VHF_EN = (1 << 15),
|
||||
SDDC_GPIO_PGA_EN = (1 << 16),
|
||||
SDDC_GPIO_ALL = ((1 << 17)-1)
|
||||
};
|
||||
typedef enum sddc_gpio sddc_gpio_t;
|
||||
|
||||
enum sddc_param {
|
||||
SDDC_PARAM_R82XX_ATT = 1,
|
||||
SDDC_PARAM_R83XX_VGA = 2,
|
||||
SDDC_PARAM_R83XX_SIDEBAND = 3,
|
||||
SDDC_PARAM_R83XX_HARMONIC = 4,
|
||||
SDDC_PARAM_DAT31_ATT = 10,
|
||||
SDDC_PARAM_AD8340_VGA = 11,
|
||||
SDDC_PARAM_PRESELECTOR = 12,
|
||||
SDDC_PARAM_VHF_ATT = 13
|
||||
};
|
||||
typedef enum sddc_param sddc_param_t;
|
||||
|
||||
/**
|
||||
* Initialize a device with a given firmware.
|
||||
* @param dev SDDC USB device entry to initialize.
|
||||
* @param firmware Path to the firmware image.
|
||||
*/
|
||||
sddc_error_t sddc_init_device(libusb_device* dev, const char* firmware);
|
||||
|
||||
/**
|
||||
* Start the FX3 streaming.
|
||||
* @param dev SDDC USB device.
|
||||
*/
|
||||
int sddc_fx3_start(libusb_device_handle* dev);
|
||||
|
||||
/**
|
||||
* Stop the FX3 streaming.
|
||||
* @param dev SDDC USB device.
|
||||
*/
|
||||
int sddc_fx3_stop(libusb_device_handle* dev);
|
||||
|
||||
/**
|
||||
* Get the hardware info of a device.
|
||||
* @param dev SDDC USB device.
|
||||
* @param info Hardware info struct to write the return info into.
|
||||
* @param enableDebug 1 to enable hardware debug mode, 0 otherwise.
|
||||
*/
|
||||
int sddc_fx3_get_info(libusb_device_handle* dev, sddc_hwinfo_t* info, char enableDebug);
|
||||
|
||||
/**
|
||||
* Set the state of the GPIO pins.
|
||||
* @param dev SDDC USB device.
|
||||
* @param gpio State of the GPIO pins.
|
||||
*/
|
||||
int sddc_fx3_gpio(libusb_device_handle* dev, sddc_gpio_t gpio);
|
||||
|
||||
/**
|
||||
* Write data to the I2C port.
|
||||
* @param dev SDDC USB device.
|
||||
* @param addr Address of the target I2C device.
|
||||
* @param reg Register to write data to.
|
||||
* @param data Data buffer to write.
|
||||
* @param len Number of bytes to write.
|
||||
*/
|
||||
int sddc_fx3_i2c_write(libusb_device_handle* dev, uint8_t addr, uint16_t reg, const uint8_t* data, uint16_t len);
|
||||
|
||||
/**
|
||||
* Read data from the I2C port.
|
||||
* @param dev SDDC USB device.
|
||||
* @param addr Address of the target I2C device.
|
||||
* @param reg Register to read data from.
|
||||
* @param data Data buffer to read data into.
|
||||
* @param len Number of bytes to read.
|
||||
*/
|
||||
int sddc_fx3_i2c_write(libusb_device_handle* dev, uint8_t addr, uint16_t reg, const uint8_t* data, uint16_t len);
|
||||
|
||||
/**
|
||||
* Reset the FX3 into bootloader mode.
|
||||
* @param dev SDDC USB device.
|
||||
*/
|
||||
int sddc_fx3_reset(libusb_device_handle* dev);
|
||||
|
||||
/**
|
||||
* Set a device parameter.
|
||||
* @param dev SDDC USB device.
|
||||
* @param arg Parameter to set.
|
||||
* @param value Value to set the parameter to.
|
||||
*/
|
||||
int sddc_fx3_set_param(libusb_device_handle* dev, sddc_param_t param, uint16_t value);
|
||||
|
||||
/**
|
||||
* Set the ADC sampling rate.
|
||||
* @param dev SDDC USB device.
|
||||
* @param samplerate Sampling rate. 0 to stop the ADC.
|
||||
*/
|
||||
int sddc_adc_set_samplerate(libusb_device_handle* dev, uint32_t samplerate);
|
||||
|
||||
/**
|
||||
* Start the tuner.
|
||||
* @param dev SDDC USB device.
|
||||
* @param frequency Initial LO frequency.
|
||||
*/
|
||||
int sddc_tuner_start(libusb_device_handle* dev, uint32_t refFreq);
|
||||
|
||||
/**
|
||||
* Set the tuner's LO frequency.
|
||||
* @param dev SDDC USB device.
|
||||
* @param frequency New LO frequency.
|
||||
*/
|
||||
int sddc_tuner_tune(libusb_device_handle* dev, uint64_t frequency);
|
||||
|
||||
/**
|
||||
* Stop the tuner.
|
||||
* @param dev SDDC USB device.
|
||||
*/
|
||||
int sddc_tuner_stop(libusb_device_handle* dev);
|
Reference in New Issue
Block a user