Skip to content

Commit

Permalink
Merge pull request #2365 from srcejon/usrp_gpio
Browse files Browse the repository at this point in the history
Add GPIO support for USRP devices
  • Loading branch information
f4exb authored Dec 25, 2024
2 parents 70d0901 + d3584f6 commit 51b540c
Show file tree
Hide file tree
Showing 21 changed files with 441 additions and 24 deletions.
18 changes: 12 additions & 6 deletions plugins/channelrx/remotetcpsink/remotetcpsinksink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -881,8 +881,8 @@ RemoteTCPProtocol::Device RemoteTCPSinkSink::getDevice()

void RemoteTCPSinkSink::acceptWebConnection()
{
QMutexLocker mutexLocker(&m_mutex);
QWebSocket *client = m_webSocketServer->nextPendingConnection();
QMutexLocker mutexLocker(&m_mutex);
QWebSocket *client = m_webSocketServer->nextPendingConnection();

connect(client, &QWebSocket::binaryMessageReceived, this, &RemoteTCPSinkSink::processCommand);
connect(client, &QWebSocket::disconnected, this, &RemoteTCPSinkSink::disconnected);
Expand All @@ -891,8 +891,11 @@ void RemoteTCPSinkSink::acceptWebConnection()
// https://bugreports.qt.io/browse/QTBUG-125874
QTimer::singleShot(200, this, [this, client] () {
QMutexLocker mutexLocker(&m_mutex);
m_clients.append(new WebSocket(client));
acceptConnection(m_clients.last());
if (client->isValid())
{
m_clients.append(new WebSocket(client));
acceptConnection(m_clients.last());
}
});
}

Expand All @@ -912,8 +915,11 @@ void RemoteTCPSinkSink::acceptTCPConnection()

QTimer::singleShot(200, this, [this, client] () {
QMutexLocker mutexLocker(&m_mutex);
m_clients.append(new TCPSocket(client));
acceptConnection(m_clients.last());
if (client->isValid())
{
m_clients.append(new TCPSocket(client));
acceptConnection(m_clients.last());
}
});
}

Expand Down
7 changes: 7 additions & 0 deletions plugins/samplesink/usrpoutput/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,10 @@ This label turns green when data has been transmitted to the device.
- **D**: turns red if stream experiences packet drop outs

The stream warning indicators are reset when the acquisition is started.

<h2>GPIOs</h2>

The USRP device settings supports 8-bit `gpioDir` and `gpioPins` settings. These can be set via the Web API or Simple PTT feature.
`gpioDir` can be set to 0 for default ATR (automatic transmit/receive) functionality or 1 for GPIO output.
On the b210, the GPIOs are on J504 header. Bit 0 corresponds to pin 1.
On other USRP devices, that may have multiple GPIO banks, these settings correspond to bank `FP0` (Front panel).
33 changes: 33 additions & 0 deletions plugins/samplesink/usrpoutput/usrpoutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,25 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, const QList<Q
}
}

if (settingsKeys.contains("gpioDir") || force)
{
if (m_deviceShared.m_deviceParams->getDevice())
{
m_deviceShared.m_deviceParams->getDevice()->set_gpio_attr("FP0", "CTRL", ~settings.m_gpioDir, 0xff); // 0 for GPIO, 1 for ATR
m_deviceShared.m_deviceParams->getDevice()->set_gpio_attr("FP0", "DDR", settings.m_gpioDir, 0xff); // 0 for input, 1 for output
qDebug() << "USRPOutput::applySettings: set GPIO dir to " << settings.m_gpioDir;
}
}

if (settingsKeys.contains("gpioPins") || force)
{
if (m_deviceShared.m_deviceParams->getDevice())
{
m_deviceShared.m_deviceParams->getDevice()->set_gpio_attr("FP0", "OUT", settings.m_gpioPins, 0xff);
qDebug() << "USRPOutput::applySettings: set GPIO pins to " << settings.m_gpioPins;
}
}

if (settingsKeys.contains("useReverseAPI"))
{
bool fullUpdate = (settingsKeys.contains("useReverseAPI") && settings.m_useReverseAPI) ||
Expand Down Expand Up @@ -1036,6 +1055,12 @@ void USRPOutput::webapiUpdateDeviceSettings(
if (deviceSettingsKeys.contains("transverterMode")) {
settings.m_transverterMode = response.getUsrpOutputSettings()->getTransverterMode() != 0;
}
if (deviceSettingsKeys.contains("gpioDir")) {
settings.m_gpioDir = response.getUsrpOutputSettings()->getGpioDir();
}
if (deviceSettingsKeys.contains("gpioPins")) {
settings.m_gpioPins = response.getUsrpOutputSettings()->getGpioPins();
}
if (deviceSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getUsrpOutputSettings()->getUseReverseApi() != 0;
}
Expand Down Expand Up @@ -1072,6 +1097,8 @@ void USRPOutput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& resp
response.getUsrpOutputSettings()->setLpfBw(settings.m_lpfBW);
response.getUsrpOutputSettings()->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency);
response.getUsrpOutputSettings()->setTransverterMode(settings.m_transverterMode ? 1 : 0);
response.getUsrpOutputSettings()->setGpioDir(settings.m_gpioDir);
response.getUsrpOutputSettings()->setGpioPins(settings.m_gpioPins);
response.getUsrpOutputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);

if (response.getUsrpOutputSettings()->getReverseApiAddress()) {
Expand Down Expand Up @@ -1172,6 +1199,12 @@ void USRPOutput::webapiReverseSendSettings(const QList<QString>& deviceSettingsK
if (deviceSettingsKeys.contains("transverterMode") || force) {
swgUsrpOutputSettings->setTransverterMode(settings.m_transverterMode ? 1 : 0);
}
if (deviceSettingsKeys.contains("gpioDir") || force) {
swgUsrpOutputSettings->setGpioDir(settings.m_gpioDir);
}
if (deviceSettingsKeys.contains("gpioPins") || force) {
swgUsrpOutputSettings->setGpioPins(settings.m_gpioPins);
}

QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
.arg(settings.m_reverseAPIAddress)
Expand Down
20 changes: 20 additions & 0 deletions plugins/samplesink/usrpoutput/usrpoutputsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ void USRPOutputSettings::resetToDefaults()
m_clockSource = "internal";
m_transverterMode = false;
m_transverterDeltaFrequency = 0;
m_gpioDir = 0;
m_gpioPins = 0;
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
Expand All @@ -63,6 +65,8 @@ QByteArray USRPOutputSettings::serialize() const
s.writeU32(11, m_reverseAPIPort);
s.writeU32(12, m_reverseAPIDeviceIndex);
s.writeS32(13, m_loOffset);
s.writeU32(14, m_gpioDir);
s.writeU32(15, m_gpioPins);

return s.final();
}
Expand Down Expand Up @@ -102,6 +106,10 @@ bool USRPOutputSettings::deserialize(const QByteArray& data)
d.readU32(12, &uintval, 0);
m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval;
d.readS32(13, &m_loOffset, 0);
d.readU32(14, &uintval, 0);
m_gpioDir = uintval & 0xFF;
d.readU32(15, &uintval, 0);
m_gpioPins = uintval & 0xFF;

return true;
}
Expand Down Expand Up @@ -148,6 +156,12 @@ void USRPOutputSettings::applySettings(const QStringList& settingsKeys, const US
if (settingsKeys.contains("transverterDeltaFrequency")) {
m_transverterDeltaFrequency = settings.m_transverterDeltaFrequency;
}
if (settingsKeys.contains("gpioDir")) {
m_gpioDir = settings.m_gpioDir;
}
if (settingsKeys.contains("gpioPins")) {
m_gpioPins = settings.m_gpioPins;
}
if (settingsKeys.contains("useReverseAPI")) {
m_useReverseAPI = settings.m_useReverseAPI;
}
Expand Down Expand Up @@ -199,6 +213,12 @@ QString USRPOutputSettings::getDebugString(const QStringList& settingsKeys, bool
if (settingsKeys.contains("transverterDeltaFrequency") || force) {
ostr << " m_transverterDeltaFrequency: " << m_transverterDeltaFrequency;
}
if (settingsKeys.contains("gpioDir") || force) {
ostr << " m_gpioDir: " << (int) m_gpioDir;
}
if (settingsKeys.contains("gpioPins") || force) {
ostr << " m_gpioPins: " << (int) m_gpioPins;
}
if (settingsKeys.contains("useReverseAPI") || force) {
ostr << " m_useReverseAPI: " << m_useReverseAPI;
}
Expand Down
2 changes: 2 additions & 0 deletions plugins/samplesink/usrpoutput/usrpoutputsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ struct USRPOutputSettings
QString m_clockSource;
bool m_transverterMode;
qint64 m_transverterDeltaFrequency;
uint8_t m_gpioDir; //!< GPIO pin direction; 0 ATR (automatic transmit/receive), 1 output
uint8_t m_gpioPins; //!< GPIO pins levels for outputs
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
Expand Down
7 changes: 7 additions & 0 deletions plugins/samplesource/usrpinput/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,10 @@ On Ubuntu 20, the libuhd-dev package should be installed. The FPGA images then n
```shell
sudo /usr/lib/uhd/utils/uhd_images_downloader.py
```

<h2>GPIOs</h2>

The USRP device settings supports 8-bit `gpioDir` and `gpioPins` settings. These can be set via the Web API or Simple PTT feature.
`gpioDir` can be set to 0 for default ATR (automatic transmit/receive) functionality or 1 for GPIO output.
On the b210, the GPIOs are on J504 header. Bit 0 corresponds to pin 1.
On other USRP devices, that may have multiple GPIO banks, these settings correspond to bank `FP0` (Front panel).
33 changes: 33 additions & 0 deletions plugins/samplesource/usrpinput/usrpinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,25 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, const QList<QSt
}
}

if (settingsKeys.contains("gpioDir") || force)
{
if (m_deviceShared.m_deviceParams->getDevice())
{
m_deviceShared.m_deviceParams->getDevice()->set_gpio_attr("FP0", "CTRL", ~settings.m_gpioDir, 0xff); // 0 for GPIO, 1 for ATR
m_deviceShared.m_deviceParams->getDevice()->set_gpio_attr("FP0", "DDR", settings.m_gpioDir, 0xff); // 0 for input, 1 for output
qDebug() << "USRPInput::applySettings: set GPIO dir to " << settings.m_gpioDir;
}
}

if (settingsKeys.contains("gpioPins") || force)
{
if (m_deviceShared.m_deviceParams->getDevice())
{
m_deviceShared.m_deviceParams->getDevice()->set_gpio_attr("FP0", "OUT", settings.m_gpioPins, 0xff);
qDebug() << "USRPInput::applySettings: set GPIO pins to " << settings.m_gpioPins;
}
}

if (settingsKeys.contains("useReverseAPI"))
{
bool fullUpdate = (settingsKeys.contains("useReverseAPI") && settings.m_useReverseAPI) ||
Expand Down Expand Up @@ -1162,6 +1181,12 @@ void USRPInput::webapiUpdateDeviceSettings(
if (deviceSettingsKeys.contains("transverterMode")) {
settings.m_transverterMode = response.getUsrpInputSettings()->getTransverterMode() != 0;
}
if (deviceSettingsKeys.contains("gpioDir")) {
settings.m_gpioDir = response.getUsrpInputSettings()->getGpioDir();
}
if (deviceSettingsKeys.contains("gpioPins")) {
settings.m_gpioPins = response.getUsrpInputSettings()->getGpioPins();
}
if (deviceSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getUsrpInputSettings()->getUseReverseApi() != 0;
}
Expand Down Expand Up @@ -1191,6 +1216,8 @@ void USRPInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& respo
response.getUsrpInputSettings()->setLpfBw(settings.m_lpfBW);
response.getUsrpInputSettings()->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency);
response.getUsrpInputSettings()->setTransverterMode(settings.m_transverterMode ? 1 : 0);
response.getUsrpInputSettings()->setGpioDir(settings.m_gpioDir);
response.getUsrpInputSettings()->setGpioPins(settings.m_gpioPins);
response.getUsrpInputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);

if (response.getUsrpInputSettings()->getReverseApiAddress()) {
Expand Down Expand Up @@ -1311,6 +1338,12 @@ void USRPInput::webapiReverseSendSettings(const QList<QString>& deviceSettingsKe
if (deviceSettingsKeys.contains("transverterMode") || force) {
swgUsrpInputSettings->setTransverterMode(settings.m_transverterMode ? 1 : 0);
}
if (deviceSettingsKeys.contains("gpioDir") || force) {
swgUsrpInputSettings->setGpioDir(settings.m_gpioDir);
}
if (deviceSettingsKeys.contains("gpioPins") || force) {
swgUsrpInputSettings->setGpioPins(settings.m_gpioPins);
}

QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
.arg(settings.m_reverseAPIAddress)
Expand Down
20 changes: 20 additions & 0 deletions plugins/samplesource/usrpinput/usrpinputsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ void USRPInputSettings::resetToDefaults()
m_replayLength = 20.0f;
m_replayStep = 5.0f;
m_replayLoop = false;
m_gpioDir = 0;
m_gpioPins = 0;
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
Expand Down Expand Up @@ -76,6 +78,8 @@ QByteArray USRPInputSettings::serialize() const
s.writeFloat(18, m_replayLength);
s.writeFloat(19, m_replayStep);
s.writeBool(20, m_replayLoop);
s.writeU32(21, m_gpioDir);
s.writeU32(22, m_gpioPins);

return s.final();
}
Expand Down Expand Up @@ -124,6 +128,10 @@ bool USRPInputSettings::deserialize(const QByteArray& data)
d.readFloat(18, &m_replayLength, 20.0f);
d.readFloat(19, &m_replayStep, 5.0f);
d.readBool(20, &m_replayLoop, false);
d.readU32(21, &uintval, 0);
m_gpioDir = uintval & 0xFF;
d.readU32(22, &uintval, 0);
m_gpioPins = uintval & 0xFF;

return true;
}
Expand Down Expand Up @@ -191,6 +199,12 @@ void USRPInputSettings::applySettings(const QStringList& settingsKeys, const USR
if (settingsKeys.contains("replayLoop")) {
m_replayLoop = settings.m_replayLoop;
}
if (settingsKeys.contains("gpioDir")) {
m_gpioDir = settings.m_gpioDir;
}
if (settingsKeys.contains("gpioPins")) {
m_gpioPins = settings.m_gpioPins;
}
if (settingsKeys.contains("useReverseAPI")) {
m_useReverseAPI = settings.m_useReverseAPI;
}
Expand Down Expand Up @@ -263,6 +277,12 @@ QString USRPInputSettings::getDebugString(const QStringList& settingsKeys, bool
if (settingsKeys.contains("replayLoop") || force) {
ostr << " m_replayLoop: " << m_replayLoop;
}
if (settingsKeys.contains("gpioDir") || force) {
ostr << " m_gpioDir: " << (int) m_gpioDir;
}
if (settingsKeys.contains("gpioPins") || force) {
ostr << " m_gpioPins: " << (int) m_gpioPins;
}
if (settingsKeys.contains("useReverseAPI") || force) {
ostr << " m_useReverseAPI: " << m_useReverseAPI;
}
Expand Down
4 changes: 3 additions & 1 deletion plugins/samplesource/usrpinput/usrpinputsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,12 @@ struct USRPInputSettings
QString m_clockSource;
bool m_transverterMode;
qint64 m_transverterDeltaFrequency;
float m_replayOffset; //!< Replay offset in seconds
float m_replayOffset; //!< Replay offset in seconds
float m_replayLength; //!< Replay buffer size in seconds
float m_replayStep; //!< Replay forward/back step size in seconds
bool m_replayLoop; //!< Replay buffer repeatedly without recording new data
uint8_t m_gpioDir; //!< GPIO pin direction; 0 ATR (automatic transmit/receive), 1 output
uint8_t m_gpioPins; //!< GPIO pins levels for outputs
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
Expand Down
12 changes: 9 additions & 3 deletions sdrbase/channel/channelwebapiutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1319,9 +1319,15 @@ bool ChannelWebAPIUtils::patchDeviceSetting(unsigned int deviceIndex, const QStr
SWGSDRangel::SWGErrorResponse errorResponse2;
delete jsonObj;

DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource();

httpRC = source->webapiSettingsPutPatch(false, deviceSettingsKeys, deviceSettingsResponse, *errorResponse2.getMessage());
if (DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource()) {
httpRC = source->webapiSettingsPutPatch(false, deviceSettingsKeys, deviceSettingsResponse, *errorResponse2.getMessage());
} else if (DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink()) {
httpRC = sink->webapiSettingsPutPatch(false, deviceSettingsKeys, deviceSettingsResponse, *errorResponse2.getMessage());
} else if (DeviceSampleMIMO *mimo = deviceSet->m_deviceAPI->getSampleMIMO()) {
httpRC = mimo->webapiSettingsPutPatch(false, deviceSettingsKeys, deviceSettingsResponse, *errorResponse2.getMessage());
} else {
httpRC = 404;
}

if (httpRC/100 == 2)
{
Expand Down
30 changes: 29 additions & 1 deletion sdrbase/resources/webapi/doc/html2/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13451,6 +13451,18 @@
"properties" : {
"sampleRate" : {
"type" : "integer"
},
"latitude" : {
"type" : "number",
"format" : "float"
},
"longitude" : {
"type" : "number",
"format" : "float"
},
"altitude" : {
"type" : "number",
"format" : "float"
}
},
"description" : "RemoteTCPInput"
Expand Down Expand Up @@ -16824,6 +16836,14 @@
"type" : "integer",
"format" : "int64"
},
"gpioDir" : {
"type" : "integer",
"format" : "int8"
},
"gpioPins" : {
"type" : "integer",
"format" : "int8"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
Expand Down Expand Up @@ -16893,6 +16913,14 @@
"type" : "integer",
"format" : "int64"
},
"gpioDir" : {
"type" : "integer",
"format" : "int8"
},
"gpioPins" : {
"type" : "integer",
"format" : "int8"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
Expand Down Expand Up @@ -59441,7 +59469,7 @@ <h3> Status: 501 - Function not implemented </h3>
</div>
<div id="generator">
<div class="content">
Generated 2024-07-16T23:20:27.082+02:00
Generated 2024-12-24T11:56:24.260+01:00
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit 51b540c

Please sign in to comment.