Thank you for your interest in contributing to RTL-SDR Manager! This document provides guidelines and instructions for contributing to the project.
- Code of Conduct
- Getting Started
- Development Setup
- How to Contribute
- Coding Standards
- Pull Request Process
- Reporting Bugs
- Suggesting Features
This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to the project maintainers.
Before you begin, ensure you have the following installed:
- .NET 10.0 SDK or later — Download here
- Git — Version control system
- librtlsdr — Native RTL-SDR library for your platform
- Windows:
choco install rtl-sdror download from releases - Linux:
sudo apt-get install librtlsdr-dev - macOS:
brew install librtlsdr
- Windows:
- IDE (recommended):
- JetBrains Rider
- Visual Studio 2022
- Visual Studio Code with the C# extension
- Fork the repository on GitHub.
- Clone your fork locally:
git clone https://github.com/YOUR-USERNAME/rtlsdr-manager.git cd rtlsdr-manager - Add the upstream repository:
git remote add upstream https://github.com/nandortoth/rtlsdr-manager.git
- Keep your fork up to date:
git fetch upstream git checkout master git merge upstream/master
# Restore dependencies
dotnet restore
# Build the solution
dotnet build
# Build in Release mode
dotnet build --configuration Release
# Or use the convenience script
./build.sh# Run all tests (when available)
dotnet test
# Run tests with detailed output
dotnet test --verbosity detailed
# Run tests with coverage (if configured)
dotnet test --collect:"XPlat Code Coverage"# Using the convenience script
./runsample.sh
# Or manually
dotnet run --project samples/RtlSdrManager.Samples
# Build and run in Release mode
dotnet run --project samples/RtlSdrManager.Samples --configuration ReleaseThe project uses .editorconfig for code style enforcement. Most IDEs apply these rules automatically.
# Format code according to .editorconfig
dotnet format
# Check formatting without making changes
dotnet format --verify-no-changesWe welcome various types of contributions:
- Bug fixes — Fix issues and improve stability
- New features — Add new functionality
- Documentation — Improve or add documentation
- Tests — Add or improve test coverage
- Code quality — Refactoring and improvements
- Examples — Add sample applications
- Tooling — Improve build scripts and tools
- Check existing issues — Look for existing issues or create a new one.
- Discuss major changes — For significant changes, open an issue first to discuss the approach.
- Create a branch — Use a descriptive branch name (see below).
- Make your changes — Follow the coding standards.
- Write tests — Add tests for new functionality.
- Update documentation — Update relevant docs and XML comments.
- Commit your changes — Use clear commit messages.
- Push to your fork — Push your branch to GitHub.
- Open a Pull Request — Submit your PR with a clear description.
Use descriptive branch names following this pattern:
feature/description # New features
bugfix/description # Bug fixes
docs/description # Documentation updates
refactor/description # Code refactoring
test/description # Test additions/improvements
Examples:
git checkout -b feature/add-async-cancellation
git checkout -b bugfix/fix-frequency-overflow
git checkout -b docs/improve-readme-examplesThis project enforces code style through .editorconfig. Key rules:
- Indentation: 4 spaces (no tabs)
- Line endings: LF (Unix-style)
- Braces: Allman style (opening brace on new line)
- File-scoped namespaces: Required for new code
// Good — file-scoped namespace
namespace RtlSdrManager;
public class MyClass
{
public void MyMethod()
{
// Method body
}
}
// Bad — block-scoped namespace (legacy only)
namespace RtlSdrManager
{
public class MyClass { }
}| Element | Convention | Example |
|---|---|---|
| Classes, Methods, Properties | PascalCase |
DeviceManager, OpenDevice |
| Private fields | _camelCase |
_deviceName, _deviceCount |
| Parameters, Local variables | camelCase |
friendlyName, deviceIndex |
| Constants | PascalCase |
MaxDevices |
| Interfaces | IPascalCase |
IDisposable |
- Do not use for built-in types:
int,string,bool, etc. - Use when the type is obvious from the right-hand side:
new ClassName() - Do not use when the type is unclear: method return values
// Good
int count = 5;
string name = "test";
var manager = new RtlSdrDeviceManager();
var frequency = new Frequency(1000);
// Bad
var count = 5; // Use explicit type for primitives
var result = GetSomething(); // Type not obviousAll public APIs must have XML documentation:
/// <summary>
/// Opens an RTL-SDR device for management.
/// </summary>
/// <param name="index">The device index (0-based).</param>
/// <param name="friendlyName">A friendly name to reference the device.</param>
/// <exception cref="ArgumentNullException">Thrown when friendlyName is null.</exception>
/// <exception cref="ArgumentException">Thrown when friendlyName is empty or a device with that name already exists.</exception>
/// <exception cref="RtlSdrDeviceException">Thrown when the device cannot be opened.</exception>
public void OpenManagedDevice(uint index, string friendlyName)
{
// Implementation
}Use appropriate exception types:
// Good — proper exception types
if (friendlyName == null)
throw new ArgumentNullException(nameof(friendlyName));
if (string.IsNullOrWhiteSpace(friendlyName))
throw new ArgumentException("Cannot be empty", nameof(friendlyName));
if (!deviceExists)
throw new RtlSdrDeviceException($"Device {index} not found");
// Bad — wrong exception types
if (friendlyName == null)
throw new Exception("Name is null"); // Too generic
if (!deviceExists)
throw new IndexOutOfRangeException(); // Wrong typeFor classes managing unmanaged resources:
public class MyResource : IDisposable
{
private bool _disposed;
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
// Dispose managed resources
}
// Release unmanaged resources
_disposed = true;
}
~MyResource()
{
Dispose(disposing: false);
}
}// Good — proper async/await with cancellation
public async Task<IQData> ReadDataAsync(CancellationToken cancellationToken = default)
{
await Task.Delay(100, cancellationToken);
return new IQData();
}
// Good — dispose IDisposable in async methods
public async Task ProcessDataAsync()
{
using var cts = new CancellationTokenSource();
await ReadDataAsync(cts.Token);
}
// Bad — async void (only for event handlers)
public async void ProcessData()
{
await Task.Delay(100);
}Ensure your PR meets these requirements:
- Code follows the project's style guidelines (
.editorconfig) - Code builds without warnings:
dotnet build - All tests pass (when tests exist)
- New code has XML documentation comments
- README.md is updated (if needed)
- CHANGELOG.md is updated with your changes
- Commit messages are clear and descriptive
Use a clear, descriptive title following conventional commits:
feat: Add support for async cancellation tokens
fix: Correct frequency overflow in calculations
docs: Improve README installation instructions
refactor: Simplify device manager initialization
test: Add unit tests for Frequency type
Include in your PR description:
- What the PR does and why.
- How you tested the changes.
- Any breaking changes or migration steps required.
- A maintainer will review your PR.
- Feedback may be provided — please address review comments.
- Once approved, a maintainer will merge your PR.
- Your contribution will be included in the next release.
- Check if the bug has already been reported in Issues.
- Ensure you are using the latest version.
- Verify the issue is reproducible.
When reporting bugs, include:
- Description — Clear description of the bug.
- Steps to reproduce — Minimal steps to trigger the issue.
- Expected vs. actual behavior — What you expected and what happened.
- Environment — OS, .NET version, RtlSdrManager version, RTL-SDR device model, librtlsdr version.
- Logs — Relevant log output or exception stack traces.
When suggesting features:
- Check existing issues — See if it has already been suggested.
- Describe the use case — Why is this feature needed? What problem does it solve?
- Provide examples — How would the API look?
- Consider alternatives — Are there other approaches?
By contributing to RTL-SDR Manager, you agree that your contributions will be licensed under the GNU General Public License v3.0 or later.
Thank you for contributing to RTL-SDR Manager! Your efforts help make this project better for the SDR community.