rtl-sdr-scanner-cpp icon indicating copy to clipboard operation
rtl-sdr-scanner-cpp copied to clipboard

gnuradio branch bug

Open Klammraute opened this issue 1 year ago • 6 comments

Tested your GNURadio branch, and I have to say, it's significantly ahead of the others in terms of performance. Reception and detection are spot on, but I identified an issue in multi-range handling.

If multiple ranges are set per stick (e.g., 143-145, 145-147) or if a single wide range is used (e.g., 143-147), the system fails to initiate recording.

thank you for your work!

Klammraute avatar Dec 23 '24 22:12 Klammraute

I’ve got the same problem here. Fresh Ubuntu install and using docker. I added a very small range 153 to 154 sample rate 2400000. And I was able to get a recording but when expanding to 140 to 160 samples are taken but no recordings. The only other thing I changed setting the transmission group size to 1000. Other than that amazing software I’m finding frequencies around my small town I never knew were there.

K1NJS avatar Jan 10 '25 23:01 K1NJS

Same problem here with gnuradio branch - no recordings if multiple ranges defined in config. Haven't yet tested wider single range.

mainframe avatar May 02 '25 12:05 mainframe

Take the following with the grain of salt - yet it may point to the possible root cause for described symptom:

The bug appears to be in the multiple frequency ranges handling logic. When there are multiple frequency ranges, the code is waiting on m_notification.wait() which is a blocking call.

In the Notification<T> class implementation in notification.h:

T wait() {
  std::unique_lock<std::mutex> lock(m_mutex);
  m_cv.wait(lock, [this]() { return m_value.has_value(); });
  T value = std::move(m_value.value());
  m_value = std::nullopt;
  return value;
}

The wait() method blocks until a notification is received. When scanning multiple frequency ranges, if no transmission is detected in the current range, the thread will be stuck waiting for a notification that might never come before it's time to move to the next range. The fix would be to modify the Notification class to support a timed wait or implement a non-blocking check in the scanner loop.

Potential solution:

  1. Add a timed wait method to the Notification class
template <typename T>
std::optional<T> wait_for(std::chrono::milliseconds timeout) {
  std::unique_lock<std::mutex> lock(m_mutex);
  if (m_cv.wait_for(lock, timeout, [this]() { return m_value.has_value(); })) {
    T value = std::move(m_value.value());
    m_value = std::nullopt;
    return value;
  }
  return std::nullopt;
}
  1. Modify the Scanner::worker() method to use a timed wait
void Scanner::worker() {
  Logger::info(LABEL, "thread started");
  if (m_ranges.empty()) {
    Logger::warn(LABEL, "empty scanned ranges");
  } else if (m_ranges.size() == 1) {
    m_device.setFrequencyRange(m_ranges.front());
    while (m_isRunning) {
      m_device.updateRecordings(m_notification.wait());
    }
  } else {
    while (m_isRunning) {
      for (const auto& range : m_ranges) {
        m_device.setFrequencyRange(range);

        const auto startScanningTime = getTime();
        bool isRecording = false;
        
        while ((getTime() <= startScanningTime + RANGE_SCANNING_TIME || isRecording) && m_isRunning) {
          // Wait with timeout instead of blocking indefinitely
          auto result = m_notification.wait_for(std::chrono::milliseconds(100));
          
          if (result) {
            // We got a notification
            const auto& notification = *result;
            isRecording = !notification.empty();
            m_device.updateRecordings(notification);
          } else {
            // Timeout - no transmission detected in this interval
            m_device.updateRecordings({});
          }
        }
        
        if (!m_isRunning) {
          break;
        }
      }
    }
  }
  Logger::info(LABEL, "thread stopped");
}

mainframe avatar May 02 '25 13:05 mainframe

Take the following with the grain of salt - yet it may point to the possible root cause for described symptom:

The bug appears to be in the multiple frequency ranges handling logic. When there are multiple frequency ranges, the code is waiting on m_notification.wait() which is a blocking call.

In the Notification class implementation in notification.h:

T wait() { std::unique_lockstd::mutex lock(m_mutex); m_cv.wait(lock, this { return m_value.has_value(); }); T value = std::move(m_value.value()); m_value = std::nullopt; return value; }

The wait() method blocks until a notification is received. When scanning multiple frequency ranges, if no transmission is detected in the current range, the thread will be stuck waiting for a notification that might never come before it's time to move to the next range. The fix would be to modify the Notification class to support a timed wait or implement a non-blocking check in the scanner loop.

Potential solution:

1. Add a timed wait method to the Notification class

template <typename T> std::optional<T> wait_for(std::chrono::milliseconds timeout) { std::unique_lockstd::mutex lock(m_mutex); if (m_cv.wait_for(lock, timeout, this { return m_value.has_value(); })) { T value = std::move(m_value.value()); m_value = std::nullopt; return value; } return std::nullopt; }

2. Modify the Scanner::worker() method to use a timed wait

void Scanner::worker() { Logger::info(LABEL, "thread started"); if (m_ranges.empty()) { Logger::warn(LABEL, "empty scanned ranges"); } else if (m_ranges.size() == 1) { m_device.setFrequencyRange(m_ranges.front()); while (m_isRunning) { m_device.updateRecordings(m_notification.wait()); } } else { while (m_isRunning) { for (const auto& range : m_ranges) { m_device.setFrequencyRange(range);

    const auto startScanningTime = getTime();
    bool isRecording = false;
    
    while ((getTime() <= startScanningTime + RANGE_SCANNING_TIME || isRecording) && m_isRunning) {
      // Wait with timeout instead of blocking indefinitely
      auto result = m_notification.wait_for(std::chrono::milliseconds(100));
      
      if (result) {
        // We got a notification
        const auto& notification = *result;
        isRecording = !notification.empty();
        m_device.updateRecordings(notification);
      } else {
        // Timeout - no transmission detected in this interval
        m_device.updateRecordings({});
      }
    }
    
    if (!m_isRunning) {
      break;
    }
  }
}

} Logger::info(LABEL, "thread stopped"); }

could you please describe in which files the changes are made? all in notification.h? Thank you very much!

Klammraute avatar May 02 '25 14:05 Klammraute

I have no cpp knownĺedge - just quessing that AI proposed solution was related to notification class (notification.h) and scanner worker implementation (scanner.cpp).

Problem with no recordings with single wide freq range could be related to frequency range splitting - ie when range is splitted, recording problem cause is similar to multiple ranges problem.

mainframe avatar May 02 '25 17:05 mainframe

Check out the new release https://github.com/shajen/sdr-hub it's much simpler!

shajen avatar Oct 29 '25 19:10 shajen