-
-
Notifications
You must be signed in to change notification settings - Fork 595
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e521230
commit 1b27379
Showing
6 changed files
with
699 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
vendor/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
cmake_minimum_required(VERSION 3.13) | ||
project(kcsdr_source) | ||
|
||
file(GLOB SRC "src/*.cpp" "src/*.c") | ||
|
||
include(${SDRPP_MODULE_CMAKE}) | ||
|
||
target_link_directories(kcsdr_source PRIVATE "vendor/FTD3XXLibrary_1.3.0.10/x64/DLL") | ||
target_include_directories(kcsdr_source PRIVATE "vendor/FTD3XXLibrary_1.3.0.10") | ||
target_link_libraries(kcsdr_source PRIVATE FTD3XX) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
#include "kcsdr.h" | ||
#include <string.h> | ||
#include "../vendor/FTD3XXLibrary_1.3.0.10/FTD3XX.h" | ||
#include <stdio.h> | ||
#include <stddef.h> | ||
|
||
#define KCSDR_PKT_EMPTY_LEN 0x0C | ||
|
||
#define KCSDR_COMMAND_PIPE 0x02 | ||
#define KCSDR_RX_DATA_PIPE 0x83 | ||
#define KCSDR_TX_DATA_PIPE 0x03 | ||
|
||
struct kcsdr { | ||
FT_HANDLE ft; | ||
}; | ||
|
||
#pragma pack(push, 1) | ||
struct kcsdr_packet { | ||
uint8_t zeros0[4]; | ||
uint8_t length; | ||
uint8_t zeros1[2]; | ||
uint8_t hex_eighty; | ||
uint32_t command; | ||
uint8_t data[188]; | ||
}; | ||
typedef struct kcsdr_packet kcsdr_packet_t; | ||
#pragma pack(pop) | ||
|
||
enum kcsdr_command { | ||
CMD_NOT_USED_0x00 = 0x00, | ||
CMD_SET_PORT = 0x01, | ||
CMD_SET_FREQUENCY = 0x02, | ||
CMD_SET_ATTENUATION = 0x03, | ||
CMD_SET_AMPLIFIER = 0x04, | ||
CMD_SET_BANDWIDTH = 0x05, | ||
CMD_START = 0x06, | ||
CMD_STOP = 0x07, | ||
CMD_SET_EXT_AMP = 0x08, | ||
CMD_START_REMOTE = 0x09, | ||
CMD_STOP_REMOTE = 0x0A | ||
}; | ||
typedef enum kcsdr_command kcsdr_command_t; | ||
|
||
int kcsdr_send_command(kcsdr_t* dev, kcsdr_direction_t dir, kcsdr_command_t cmd, const uint8_t* data, int len) { | ||
Sleep(50); | ||
|
||
// Create an empty packet | ||
kcsdr_packet_t pkt; | ||
memset(&pkt, 0, sizeof(kcsdr_packet_t)); | ||
|
||
// Fill out the packet info | ||
pkt.length = len + KCSDR_PKT_EMPTY_LEN; | ||
pkt.hex_eighty = 0x80; // Whatever the fuck that is | ||
pkt.command = (uint32_t)cmd | (uint32_t)dir; | ||
|
||
// Copy the data if there is some | ||
if (len) { memcpy(pkt.data, data, len); } | ||
|
||
// Dump the bytes | ||
uint8_t* dump = (uint8_t*)&pkt; | ||
printf("Sending:"); | ||
for (int i = 0; i < pkt.length; i++) { | ||
printf(" %02X", dump[i]); | ||
} | ||
printf("\n"); | ||
|
||
// Send the command to endpoint 0 | ||
int sent; | ||
FT_STATUS err = FT_WritePipeEx(dev->ft, KCSDR_COMMAND_PIPE, (uint8_t*)&pkt, sizeof(kcsdr_packet_t), &sent, NULL); | ||
if (err != FT_OK) { | ||
return -err; | ||
} | ||
printf("Sent %d bytes (%d)\n", sent, err); | ||
|
||
Sleep(50); | ||
|
||
// Flush existing commands | ||
FT_FlushPipe(dev->ft, KCSDR_COMMAND_PIPE); | ||
|
||
return -(int)err; | ||
} | ||
|
||
int kcsdr_list_devices(kcsdr_info_t** devices) { | ||
// Generate a list of FTDI devices | ||
int ftdiDevCount = 0; | ||
FT_STATUS err = FT_CreateDeviceInfoList(&ftdiDevCount); | ||
if (err != FT_OK) { | ||
return -1; | ||
} | ||
|
||
// If no device was found, return nothing | ||
if (!ftdiDevCount) { | ||
*devices = NULL; | ||
return 0; | ||
} | ||
|
||
// Get said device list | ||
FT_DEVICE_LIST_INFO_NODE* list = malloc(ftdiDevCount * sizeof(FT_DEVICE_LIST_INFO_NODE)); | ||
err = FT_GetDeviceInfoList(list, &ftdiDevCount); | ||
if (err != FT_OK) { | ||
return -1; | ||
} | ||
|
||
// Allocate the device info list | ||
*devices = malloc(ftdiDevCount * sizeof(kcsdr_info_t)); | ||
|
||
// Find all KC908s | ||
int kcCount = 0; | ||
for (int i = 0; i < ftdiDevCount; i++) { | ||
strcpy((*devices)[kcCount++].serial, list[i].SerialNumber); | ||
} | ||
|
||
// Free the FTDI list | ||
free(list); | ||
|
||
return kcCount; | ||
} | ||
|
||
void kcsdr_free_device_list(kcsdr_info_t* devices) { | ||
// Free the list | ||
if (devices) { free(devices); } | ||
} | ||
|
||
int kcsdr_open(kcsdr_t** dev, const char* serial) { | ||
// Attempt to open the device using the serial number | ||
FT_HANDLE ft; | ||
FT_STATUS err = FT_Create(serial, FT_OPEN_BY_SERIAL_NUMBER, &ft); | ||
if (err != FT_OK) { | ||
return -1; | ||
} | ||
|
||
// Set the timeouts for the data pipes | ||
FT_SetPipeTimeout(ft, KCSDR_RX_DATA_PIPE, 1000); | ||
FT_SetPipeTimeout(ft, KCSDR_TX_DATA_PIPE, 1000); | ||
|
||
// Allocate the device object | ||
*dev = malloc(sizeof(kcsdr_t)); | ||
|
||
// Fill out the device object | ||
(*dev)->ft = ft; | ||
|
||
// Put device into remote control mode | ||
return kcsdr_send_command(*dev, KCSDR_DIR_RX, CMD_START_REMOTE, NULL, 0); | ||
} | ||
|
||
void kcsdr_close(kcsdr_t* dev) { | ||
// Put device back in normal mode | ||
kcsdr_send_command(dev, KCSDR_DIR_RX, CMD_STOP_REMOTE, NULL, 0); | ||
|
||
// Close the device | ||
FT_Close(dev->ft); | ||
|
||
// Free the device object | ||
free(dev); | ||
} | ||
|
||
int kcsdr_set_port(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t port) { | ||
// Send SET_PORT command | ||
return kcsdr_send_command(dev, dir, CMD_SET_PORT, &port, 1); | ||
} | ||
|
||
int kcsdr_set_frequency(kcsdr_t* dev, kcsdr_direction_t dir, uint64_t freq) { | ||
// Send SET_FREQUENCY command | ||
return kcsdr_send_command(dev, dir, CMD_SET_FREQUENCY, (uint8_t*)&freq, 8); | ||
} | ||
|
||
int kcsdr_set_attenuation(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t att) { | ||
// Send SET_ATTENUATION command | ||
return kcsdr_send_command(dev, dir, CMD_SET_ATTENUATION, &att, 1); | ||
} | ||
|
||
int kcsdr_set_amp_gain(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t gain) { | ||
// Send SET_AMPLIFIER command | ||
return kcsdr_send_command(dev, dir, CMD_SET_AMPLIFIER, &gain, 1); | ||
} | ||
|
||
int kcsdr_set_rx_ext_amp_gain(kcsdr_t* dev, uint8_t gain) { | ||
// Send CMD_SET_EXT_AMP command | ||
return kcsdr_send_command(dev, KCSDR_DIR_RX, CMD_SET_EXT_AMP, &gain, 1); | ||
} | ||
|
||
int kcsdr_set_samplerate(kcsdr_t* dev, kcsdr_direction_t dir, uint32_t samplerate) { | ||
// Set SET_BANDWIDTH command | ||
return kcsdr_send_command(dev, dir, CMD_SET_BANDWIDTH, (uint8_t*)&samplerate, 4); | ||
} | ||
|
||
int kcsdr_start(kcsdr_t* dev, kcsdr_direction_t dir) { | ||
// Send START command | ||
return kcsdr_send_command(dev, dir, CMD_START, NULL, 0); | ||
} | ||
|
||
int kcsdr_stop(kcsdr_t* dev, kcsdr_direction_t dir) { | ||
// Send STOP command | ||
return kcsdr_send_command(dev, dir, CMD_STOP, NULL, 0); | ||
} | ||
|
||
int kcsdr_rx(kcsdr_t* dev, int16_t* samples, int count) { | ||
// Receive samples (TODO: Endpoint might be 0x81) | ||
int received; | ||
FT_STATUS err = FT_ReadPipeEx(dev->ft, KCSDR_RX_DATA_PIPE, (uint8_t*)samples, count*2*sizeof(uint16_t), &received, NULL); | ||
return (err == FT_OK) ? received / (2*sizeof(uint16_t)) : -(int)err; | ||
} | ||
|
||
int kcsdr_tx(kcsdr_t* dev, const int16_t* samples, int count) { | ||
// Transmit samples | ||
int sent; | ||
FT_STATUS err = FT_WritePipeEx(dev->ft, KCSDR_TX_DATA_PIPE, (uint8_t*)samples, count*2*sizeof(uint16_t), &sent, NULL); | ||
return (err == FT_OK) ? sent / (2*sizeof(uint16_t)) : -(int)err; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
#pragma once | ||
#include <stdint.h> | ||
|
||
#define KCSDR_SERIAL_LEN 16 | ||
#define KCSDR_MAX_PORTS 6 | ||
|
||
// Detect C++ | ||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** | ||
* KCSDR Device. | ||
*/ | ||
struct kcsdr; | ||
typedef struct kcsdr kcsdr_t; | ||
|
||
/** | ||
* Device Information | ||
*/ | ||
struct kcsdr_info { | ||
char serial[KCSDR_SERIAL_LEN+1]; | ||
}; | ||
typedef struct kcsdr_info kcsdr_info_t; | ||
|
||
/** | ||
* RF Direction. | ||
*/ | ||
enum kcsdr_direction { | ||
KCSDR_DIR_RX = 0x00, | ||
KCSDR_DIR_TX = 0x80 | ||
}; | ||
typedef enum kcsdr_direction kcsdr_direction_t; | ||
|
||
/** | ||
* Get a list of KCSDR devices on the system. | ||
* @param devices Pointer to an array of device info. | ||
* @return Number of devices found or error code. | ||
*/ | ||
int kcsdr_list_devices(kcsdr_info_t** devices); | ||
|
||
/** | ||
* Free a device list returned by `kcsdr_list_devices()`. | ||
* @param devices Device list to free. | ||
*/ | ||
void kcsdr_free_device_list(kcsdr_info_t* devices); | ||
|
||
/** | ||
* Open a KCSDR device. | ||
* @param dev Newly open device. | ||
* @param serial Serial number of the device to open as returned in the device list. | ||
* @return 0 on success, error code otherwise. | ||
*/ | ||
int kcsdr_open(kcsdr_t** dev, const char* serial); | ||
|
||
/** | ||
* Close a KCSDR device. | ||
* @param dev Device to be closed. | ||
*/ | ||
void kcsdr_close(kcsdr_t* dev); | ||
|
||
/** | ||
* Select the RF port. | ||
* @param dev Device to control. | ||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX. | ||
* @param port RF port number to select. | ||
* @return 0 on success, error code otherwise. | ||
*/ | ||
int kcsdr_set_port(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t port); | ||
|
||
/** | ||
* Set the center frequency. | ||
* @param dev Device to control. | ||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX | ||
* @param freq Frequency in Hz. | ||
* @return 0 on success, error code otherwise. | ||
*/ | ||
int kcsdr_set_frequency(kcsdr_t* dev, kcsdr_direction_t dir, uint64_t freq); | ||
|
||
/** | ||
* Set the attenuation. | ||
* @param dev Device to control. | ||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX | ||
* @param samplerate Attenuation in dB. | ||
* @return 0 on success, error code otherwise. | ||
*/ | ||
int kcsdr_set_attenuation(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t att); | ||
|
||
/** | ||
* Set the internal amplifier gain. | ||
* @param dev Device to control. | ||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX | ||
* @param gain Gain in dB. | ||
* @return 0 on success, error code otherwise. | ||
*/ | ||
int kcsdr_set_amp_gain(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t gain); | ||
|
||
/** | ||
* Set the external amplifier gain. | ||
* @param dev Device to control. | ||
* @param gain Gain in dB. | ||
* @return 0 on success, error code otherwise. | ||
*/ | ||
int kcsdr_set_rx_ext_amp_gain(kcsdr_t* dev, uint8_t gain); | ||
|
||
/** | ||
* Set the samplerate. | ||
* @param dev Device to control. | ||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX | ||
* @param samplerate Samplerate in Hz. | ||
* @return 0 on success, error code otherwise. | ||
*/ | ||
int kcsdr_set_samplerate(kcsdr_t* dev, kcsdr_direction_t dir, uint32_t samplerate); | ||
|
||
/** | ||
* Start streaming samples. | ||
* @param dev Device to control. | ||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX. | ||
* @return 0 on success, error code otherwise. | ||
*/ | ||
int kcsdr_start(kcsdr_t* dev, kcsdr_direction_t dir); | ||
|
||
/** | ||
* Stop streaming samples. | ||
* @param dev Device to control. | ||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX. | ||
* @return 0 on success, error code otherwise. | ||
*/ | ||
int kcsdr_stop(kcsdr_t* dev, kcsdr_direction_t dir); | ||
|
||
/** | ||
* Receive a buffer of samples. | ||
* @param samples Sample buffer. | ||
* @param count Number of complex samples. | ||
* @return Number of samples received. | ||
*/ | ||
int kcsdr_rx(kcsdr_t* dev, int16_t* samples, int count); | ||
|
||
/** | ||
* Transmit a buffer of samples. | ||
* @param samples Sample buffer. | ||
* @param count Number of complex samples. | ||
* @return Number of samples transmitted. | ||
*/ | ||
int kcsdr_tx(kcsdr_t* dev, const int16_t* samples, int count); | ||
|
||
// Detect C++ | ||
#ifdef __cplusplus | ||
} | ||
#endif |
Oops, something went wrong.