mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-06-26 12:27:51 +02:00
bunch of bugfix and new features
This commit is contained in:
@ -18,7 +18,7 @@ else ()
|
||||
endif ()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(hermes_source PRIVATE wsock32 ws2_32)
|
||||
target_link_libraries(hermes_source PRIVATE wsock32 ws2_32 iphlpapi)
|
||||
endif()
|
||||
|
||||
# Install directives
|
||||
|
@ -20,11 +20,15 @@ namespace hermes {
|
||||
}
|
||||
|
||||
void Client::start() {
|
||||
sendMetisControl((MetisControl)(METIS_CTRL_IQ | METIS_CTRL_NO_WD));
|
||||
for (int i = 0; i < HERMES_METIS_REPEAT; i++) {
|
||||
sendMetisControl((MetisControl)(METIS_CTRL_IQ | METIS_CTRL_NO_WD));
|
||||
}
|
||||
}
|
||||
|
||||
void Client::stop() {
|
||||
sendMetisControl(METIS_CTRL_NONE);
|
||||
for (int i = 0; i < HERMES_METIS_REPEAT; i++) {
|
||||
sendMetisControl(METIS_CTRL_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::setSamplerate(HermesLiteSamplerate samplerate) {
|
||||
@ -32,13 +36,44 @@ namespace hermes {
|
||||
}
|
||||
|
||||
void Client::setFrequency(double freq) {
|
||||
this->freq = freq;
|
||||
writeReg(HL_REG_TX1_NCO_FREQ, freq);
|
||||
autoeFilters(freq);
|
||||
}
|
||||
|
||||
void Client::setGain(int gain) {
|
||||
writeReg(HL_REG_RX_LNA, gain | (1 << 6));
|
||||
}
|
||||
|
||||
void Client::autoeFilters(double freq) {
|
||||
uint8_t filt = (freq >= 3000000.0) ? (1 << 6) : 0;
|
||||
|
||||
if (freq <= 2000000.0) {
|
||||
filt |= (1 << 0);
|
||||
}
|
||||
else if (freq <= 4000000.0) {
|
||||
filt |= (1 << 1);
|
||||
}
|
||||
else if (freq <= 7300000.0) {
|
||||
filt |= (1 << 2);
|
||||
}
|
||||
else if (freq <= 14350000.0) {
|
||||
filt |= (1 << 3);
|
||||
}
|
||||
else if (freq <= 21450000.0) {
|
||||
filt |= (1 << 4);
|
||||
}
|
||||
else if (freq <= 29700000.0) {
|
||||
filt |= (1 << 5);
|
||||
}
|
||||
|
||||
// Write only if the config actually changed
|
||||
if (filt != lastFilt) {
|
||||
lastFilt = filt;
|
||||
writeI2C(I2C_PORT_2, 0x20, 0x0A, filt);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::sendMetisUSB(uint8_t endpoint, void* frame0, void* frame1) {
|
||||
// Build packet
|
||||
uint32_t seq = usbSeq++;
|
||||
@ -79,6 +114,8 @@ namespace hermes {
|
||||
|
||||
sendMetisUSB(2, frame);
|
||||
|
||||
// TODO: Wait for response
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -96,6 +133,15 @@ namespace hermes {
|
||||
sendMetisUSB(2, frame);
|
||||
}
|
||||
|
||||
void Client::writeI2C(I2CPort port, uint8_t addr, uint8_t reg, uint8_t data) {
|
||||
uint32_t wdata = data;
|
||||
wdata |= reg << 8;
|
||||
wdata |= (addr & 0x7F) << 16;
|
||||
wdata |= 1 << 23;
|
||||
wdata |= 0x06 << 24;
|
||||
writeReg(HL_REG_I2C_1 + port, wdata);
|
||||
}
|
||||
|
||||
void Client::worker() {
|
||||
uint8_t rbuf[2048];
|
||||
MetisUSBPacket* pkt = (MetisUSBPacket*)rbuf;
|
||||
@ -147,7 +193,7 @@ namespace hermes {
|
||||
}
|
||||
|
||||
std::vector<Info> discover() {
|
||||
auto sock = net::openudp("192.168.0.255", 1024);
|
||||
auto sock = net::openudp("0.0.0.0", 1024);
|
||||
|
||||
// Build discovery packet
|
||||
uint8_t discoveryPkt[64];
|
||||
@ -155,18 +201,23 @@ namespace hermes {
|
||||
*(uint16_t*)&discoveryPkt[0] = htons(HERMES_METIS_SIGNATURE);
|
||||
discoveryPkt[2] = METIS_PKT_DISCOVER;
|
||||
|
||||
// Get interface list
|
||||
auto ifaces = net::listInterfaces();
|
||||
|
||||
// Send the packet 5 times to make sure it's received
|
||||
for (int i = 0; i < HERMES_DISCOVER_REPEAT; i++) {
|
||||
sock->send(discoveryPkt, sizeof(discoveryPkt));
|
||||
for (const auto& [name, iface] : ifaces) {
|
||||
net::Address baddr(iface.broadcast, 1024);
|
||||
for (int i = 0; i < HERMES_METIS_REPEAT; i++) {
|
||||
sock->send(discoveryPkt, sizeof(discoveryPkt), &baddr);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Info> devices;
|
||||
|
||||
while (true) {
|
||||
// Wait for a response
|
||||
net::Address addr;
|
||||
uint8_t resp[1024];
|
||||
int len = sock->recv(resp, sizeof(resp), false, HERMES_DISCOVER_TIMEOUT, &addr);
|
||||
int len = sock->recv(resp, sizeof(resp), false, HERMES_METIS_TIMEOUT, &addr);
|
||||
|
||||
// Give up if timeout or error
|
||||
if (len <= 0) { break; }
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#define HERMES_DISCOVER_REPEAT 5
|
||||
#define HERMES_DISCOVER_TIMEOUT 1000
|
||||
#define HERMES_METIS_REPEAT 5
|
||||
#define HERMES_METIS_TIMEOUT 1000
|
||||
#define HERMES_METIS_SIGNATURE 0xEFFE
|
||||
#define HERMES_HPSDR_USB_SYNC 0x7F
|
||||
|
||||
@ -80,6 +80,11 @@ namespace hermes {
|
||||
HL_SAMP_RATE_384KHZ = 3
|
||||
};
|
||||
|
||||
enum I2CPort {
|
||||
I2C_PORT_1 = 0,
|
||||
I2C_PORT_2
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct HPSDRUSBHeader {
|
||||
uint8_t sync[3];
|
||||
@ -130,6 +135,7 @@ namespace hermes {
|
||||
void setSamplerate(HermesLiteSamplerate samplerate);
|
||||
void setFrequency(double freq);
|
||||
void setGain(int gain);
|
||||
void autoeFilters(double freq);
|
||||
|
||||
dsp::stream<dsp::complex_t> out;
|
||||
|
||||
@ -140,13 +146,19 @@ namespace hermes {
|
||||
uint32_t readReg(uint8_t addr);
|
||||
void writeReg(uint8_t addr, uint32_t val);
|
||||
|
||||
void writeI2C(I2CPort port, uint8_t addr, uint8_t reg, uint8_t data);
|
||||
|
||||
|
||||
|
||||
void worker();
|
||||
|
||||
bool open = true;
|
||||
double freq = 0;
|
||||
|
||||
std::thread workerThread;
|
||||
std::shared_ptr<net::Socket> sock;
|
||||
uint32_t usbSeq = 0;
|
||||
uint8_t lastFilt = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -48,15 +48,6 @@ public:
|
||||
handler.stopHandler = stop;
|
||||
handler.tuneHandler = tune;
|
||||
handler.stream = &stream;
|
||||
|
||||
// TODO: Move the refresh and first select to the select event instead
|
||||
refresh();
|
||||
|
||||
// Select device
|
||||
config.acquire();
|
||||
selectedMac = config.conf["device"];
|
||||
config.release();
|
||||
selectMac(selectedMac);
|
||||
|
||||
sigpath::sourceManager.registerSource("Hermes", &handler);
|
||||
}
|
||||
@ -132,6 +123,20 @@ private:
|
||||
|
||||
static void menuSelected(void* ctx) {
|
||||
HermesSourceModule* _this = (HermesSourceModule*)ctx;
|
||||
|
||||
if (_this->firstSelect) {
|
||||
_this->firstSelect = false;
|
||||
|
||||
// Refresh
|
||||
_this->refresh();
|
||||
|
||||
// Select device
|
||||
config.acquire();
|
||||
_this->selectedMac = config.conf["device"];
|
||||
config.release();
|
||||
_this->selectMac(_this->selectedMac);
|
||||
}
|
||||
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
spdlog::info("HermesSourceModule '{0}': Menu Select!", _this->name);
|
||||
}
|
||||
@ -257,6 +262,8 @@ private:
|
||||
int srId = 0;
|
||||
int gain = 0;
|
||||
|
||||
bool firstSelect = true;
|
||||
|
||||
std::shared_ptr<hermes::Client> dev;
|
||||
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "net.h"
|
||||
#include <string.h>
|
||||
#include <codecvt>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WOULD_BLOCK (WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
@ -246,6 +247,60 @@ namespace net {
|
||||
|
||||
// === Creation functions ===
|
||||
|
||||
std::map<std::string, InterfaceInfo> listInterfaces() {
|
||||
// Init library if needed
|
||||
init();
|
||||
|
||||
std::map<std::string, InterfaceInfo> ifaces;
|
||||
#ifdef _WIN32
|
||||
// Pre-allocate buffer
|
||||
ULONG size = sizeof(IP_ADAPTER_ADDRESSES);
|
||||
PIP_ADAPTER_ADDRESSES addresses = (PIP_ADAPTER_ADDRESSES)malloc(size);
|
||||
|
||||
// Reallocate to real size
|
||||
if (GetAdaptersAddresses(AF_INET, 0, NULL, addresses, &size) == ERROR_BUFFER_OVERFLOW) {
|
||||
addresses = (PIP_ADAPTER_ADDRESSES)realloc(addresses, size);
|
||||
if (GetAdaptersAddresses(AF_INET, 0, NULL, addresses, &size)) {
|
||||
throw std::exception("Could not list network interfaces");
|
||||
}
|
||||
}
|
||||
|
||||
// Save data
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> utfConv;
|
||||
for (auto iface = addresses; iface; iface = iface->Next) {
|
||||
InterfaceInfo info;
|
||||
auto ip = iface->FirstUnicastAddress;
|
||||
if (!ip || ip->Address.lpSockaddr->sa_family != AF_INET) { continue; }
|
||||
info.address = ntohl(*(uint32_t*)&ip->Address.lpSockaddr->sa_data[2]);
|
||||
info.netmask = ~((1 << (32 - ip->OnLinkPrefixLength)) - 1);
|
||||
info.broadcast = info.address | (~info.netmask);
|
||||
ifaces[utfConv.to_bytes(iface->FriendlyName)] = info;
|
||||
}
|
||||
|
||||
// Free tables
|
||||
free(addresses);
|
||||
#else
|
||||
// Get iface list
|
||||
struct ifaddrs* addresses = NULL;
|
||||
getifaddrs(&addresses);
|
||||
|
||||
// Save data
|
||||
for (auto iface = addresses; iface; iface = iface->ifa_next) {
|
||||
if (iface->ifa_addr->sa_family != AF_INET) { continue; }
|
||||
InterfaceInfo info;
|
||||
info.address = ntohl(*(uint32_t*)&iface->ifa_addr->sa_data[2]);
|
||||
info.netmask = ntohl(*(uint32_t*)&iface->ifa_netmask->sa_data[2]);
|
||||
info.broadcast = info.address | (~info.netmask);
|
||||
ifaces[iface->ifa_name] = info;
|
||||
}
|
||||
|
||||
// Free iface list
|
||||
freeifaddrs(addresses);
|
||||
#endif
|
||||
|
||||
return ifaces;
|
||||
}
|
||||
|
||||
std::shared_ptr<Listener> listen(const Address& addr) {
|
||||
// Init library if needed
|
||||
init();
|
||||
|
@ -2,10 +2,12 @@
|
||||
#include <stdint.h>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <WinSock2.h>
|
||||
#include <WS2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
@ -16,6 +18,7 @@
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <fcntl.h>
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
namespace net {
|
||||
@ -30,6 +33,12 @@ namespace net {
|
||||
class Socket;
|
||||
class Listener;
|
||||
|
||||
struct InterfaceInfo {
|
||||
IP_t address;
|
||||
IP_t netmask;
|
||||
IP_t broadcast;
|
||||
};
|
||||
|
||||
class Address {
|
||||
friend Socket;
|
||||
friend Listener;
|
||||
@ -198,6 +207,12 @@ namespace net {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a list of the network interface.
|
||||
* @return List of network interfaces and their addresses.
|
||||
*/
|
||||
std::map<std::string, InterfaceInfo> listInterfaces();
|
||||
|
||||
/**
|
||||
* Create TCP listener.
|
||||
* @param addr Address to listen on.
|
||||
|
@ -115,11 +115,9 @@ private:
|
||||
if (!_this->client) { return; }
|
||||
}
|
||||
|
||||
// TODO: Set configuration here
|
||||
if (_this->client) {
|
||||
_this->client->setFrequency(_this->freq);
|
||||
_this->client->start();
|
||||
}
|
||||
// Set configuration
|
||||
_this->client->setFrequency(_this->freq);
|
||||
_this->client->start();
|
||||
|
||||
_this->running = true;
|
||||
spdlog::info("SDRPPServerSourceModule '{0}': Start!", _this->name);
|
||||
|
@ -30,8 +30,6 @@ public:
|
||||
this->name = name;
|
||||
|
||||
sampleRate = 8000000.0;
|
||||
// TODO: REMOVE
|
||||
samplerates.define(8000000, "8MHz", 8000000.0);
|
||||
|
||||
handler.ctx = this;
|
||||
handler.selectHandler = menuSelected;
|
||||
@ -42,15 +40,6 @@ public:
|
||||
handler.tuneHandler = tune;
|
||||
handler.stream = &stream;
|
||||
|
||||
// List devices
|
||||
refresh();
|
||||
|
||||
// Select device
|
||||
config.acquire();
|
||||
selectedSer = config.conf["device"];
|
||||
config.release();
|
||||
select(selectedSer);
|
||||
|
||||
sigpath::sourceManager.registerSource("USRP", &handler);
|
||||
}
|
||||
|
||||
@ -212,6 +201,20 @@ private:
|
||||
|
||||
static void menuSelected(void* ctx) {
|
||||
USRPSourceModule* _this = (USRPSourceModule*)ctx;
|
||||
|
||||
if (_this->firstSelect) {
|
||||
_this->firstSelect = false;
|
||||
|
||||
// List devices
|
||||
_this->refresh();
|
||||
|
||||
// Select device
|
||||
config.acquire();
|
||||
_this->selectedSer = config.conf["device"];
|
||||
config.release();
|
||||
_this->select(_this->selectedSer);
|
||||
}
|
||||
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
spdlog::info("USRPSourceModule '{0}': Menu Select!", _this->name);
|
||||
}
|
||||
@ -406,6 +409,8 @@ private:
|
||||
uhd::usrp::multi_usrp::sptr dev;
|
||||
uhd::rx_streamer::sptr streamer;
|
||||
|
||||
bool firstSelect = true;
|
||||
|
||||
std::thread workerThread;
|
||||
|
||||
};
|
||||
|
Reference in New Issue
Block a user