Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GPIO support for USRP devices #2365

Merged
merged 5 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading